fix: harden workspace schema contracts
This commit is contained in:
@@ -19,6 +19,8 @@ export interface CanonicalWorkspace {
|
||||
engine: "postgres";
|
||||
database: string;
|
||||
schema: string;
|
||||
port?: number;
|
||||
timeout_ms?: number;
|
||||
supported_transports: DwhTransport[];
|
||||
};
|
||||
semantic_index: {
|
||||
@@ -27,12 +29,15 @@ export interface CanonicalWorkspace {
|
||||
collection: string;
|
||||
dimensions: number;
|
||||
distance: "cosine" | "l2" | "inner_product";
|
||||
port?: number;
|
||||
timeout_ms?: number;
|
||||
supported_transports: VectorTransport[];
|
||||
};
|
||||
embedding: {
|
||||
provider: "ollama_compatible" | "openai_compatible";
|
||||
model: string;
|
||||
dimensions: number;
|
||||
timeout_ms?: number;
|
||||
};
|
||||
};
|
||||
llm_policy: {
|
||||
@@ -48,6 +53,8 @@ const identifier = z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/, {
|
||||
message: "database identifiers must start with a letter or underscore",
|
||||
});
|
||||
const dimensions = z.number().int().positive().max(32_768);
|
||||
const port = z.number().int().min(1).max(65_535);
|
||||
const timeoutMs = z.number().int().positive();
|
||||
const modelReference = z.string().regex(/^[^/\s]+\/[^/\s]+$/, {
|
||||
message: "model must use provider/model syntax",
|
||||
});
|
||||
@@ -70,6 +77,8 @@ const WorkspaceSchema = z.object({
|
||||
engine: z.literal("postgres"),
|
||||
database: identifier,
|
||||
schema: identifier,
|
||||
port: port.optional(),
|
||||
timeout_ms: timeoutMs.optional(),
|
||||
supported_transports: z.array(z.enum(DWH_TRANSPORTS)).min(1),
|
||||
}).strict(),
|
||||
semantic_index: z.object({
|
||||
@@ -78,12 +87,15 @@ const WorkspaceSchema = z.object({
|
||||
collection: identifier,
|
||||
dimensions,
|
||||
distance: z.enum(["cosine", "l2", "inner_product"]),
|
||||
port: port.optional(),
|
||||
timeout_ms: timeoutMs.optional(),
|
||||
supported_transports: z.array(z.enum(VECTOR_TRANSPORTS)).min(1),
|
||||
}).strict(),
|
||||
embedding: z.object({
|
||||
provider: z.enum(["ollama_compatible", "openai_compatible"]),
|
||||
model: z.string().trim().min(1),
|
||||
dimensions,
|
||||
timeout_ms: timeoutMs.optional(),
|
||||
}).strict(),
|
||||
}).strict(),
|
||||
llm_policy: z.object({
|
||||
@@ -127,11 +139,15 @@ export function parseWorkspaceYaml(source: string): CanonicalWorkspace {
|
||||
throw new Error(`Invalid workspace YAML: ${document.errors.map((error) => error.message).join("; ")}`);
|
||||
}
|
||||
|
||||
return WorkspaceSchema.parse(document.toJSON()) as CanonicalWorkspace;
|
||||
return validateCanonicalWorkspace(document.toJSON());
|
||||
}
|
||||
|
||||
export function validateCanonicalWorkspace(workspace: unknown): CanonicalWorkspace {
|
||||
return WorkspaceSchema.parse(workspace) as CanonicalWorkspace;
|
||||
}
|
||||
|
||||
export function serializeWorkspaceYaml(workspace: CanonicalWorkspace): string {
|
||||
const canonical = WorkspaceSchema.parse(workspace) as CanonicalWorkspace;
|
||||
const canonical = validateCanonicalWorkspace(workspace);
|
||||
return stringify(canonical, { lineWidth: 0, sortMapEntries: true });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user