fix: validate canonical Worker launch segments
This commit is contained in:
@@ -135,7 +135,10 @@ Deno.test("Worker create request parser requires the complete shared request", (
|
|||||||
display_name: "Worker A",
|
display_name: "Worker A",
|
||||||
profile: "builtin:coder",
|
profile: "builtin:coder",
|
||||||
ticket_assignment: null,
|
ticket_assignment: null,
|
||||||
initial_submit: [{ kind: "text", content: "Implement T-565." }],
|
initial_submit: [
|
||||||
|
{ kind: "text", content: "Implement T-565." },
|
||||||
|
{ kind: "flow", selector: "builtin:coder-review" },
|
||||||
|
],
|
||||||
working_directory: {
|
working_directory: {
|
||||||
working_directory_id: "workdir-a",
|
working_directory_id: "workdir-a",
|
||||||
relative_cwd: null,
|
relative_cwd: null,
|
||||||
@@ -159,4 +162,22 @@ Deno.test("Worker create request parser requires the complete shared request", (
|
|||||||
Error,
|
Error,
|
||||||
"initial_submit",
|
"initial_submit",
|
||||||
);
|
);
|
||||||
|
assertThrows(
|
||||||
|
() =>
|
||||||
|
parseCreateWorkspaceWorkerRequest({
|
||||||
|
...request,
|
||||||
|
initial_submit: [{ kind: "flow" }],
|
||||||
|
}),
|
||||||
|
Error,
|
||||||
|
"selector",
|
||||||
|
);
|
||||||
|
assertThrows(
|
||||||
|
() =>
|
||||||
|
parseCreateWorkspaceWorkerRequest({
|
||||||
|
...request,
|
||||||
|
initial_submit: [{ kind: "newer_client_segment" }],
|
||||||
|
}),
|
||||||
|
Error,
|
||||||
|
"kind is invalid",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -489,15 +489,145 @@ function ticketAssignment(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function unsignedInteger(value: unknown, label: string): number {
|
||||||
|
const parsed = number(value, label);
|
||||||
|
if (!Number.isSafeInteger(parsed) || parsed < 0) {
|
||||||
|
throw new Error(`${label} must be a non-negative safe integer`);
|
||||||
|
}
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pasteArtifact(
|
||||||
|
value: unknown,
|
||||||
|
label: string,
|
||||||
|
): Extract<Segment, { kind: "paste_artifact" }>["artifact"] {
|
||||||
|
const item = record(value, label);
|
||||||
|
exact(
|
||||||
|
item,
|
||||||
|
[
|
||||||
|
"artifact_id",
|
||||||
|
"created_at_ms",
|
||||||
|
"media_type",
|
||||||
|
"availability",
|
||||||
|
"byte_len",
|
||||||
|
"char_count",
|
||||||
|
"line_count",
|
||||||
|
"sha256",
|
||||||
|
"source_entry_id",
|
||||||
|
],
|
||||||
|
label,
|
||||||
|
);
|
||||||
|
const mediaType = string(item.media_type, `${label}.media_type`);
|
||||||
|
if (mediaType !== "text_plain_utf8") {
|
||||||
|
throw new Error(`${label}.media_type is invalid`);
|
||||||
|
}
|
||||||
|
const availability = string(item.availability, `${label}.availability`);
|
||||||
|
if (
|
||||||
|
!["available", "unavailable", "integrity_failed"].includes(availability)
|
||||||
|
) {
|
||||||
|
throw new Error(`${label}.availability is invalid`);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
artifact_id: string(item.artifact_id, `${label}.artifact_id`),
|
||||||
|
created_at_ms: unsignedInteger(
|
||||||
|
item.created_at_ms,
|
||||||
|
`${label}.created_at_ms`,
|
||||||
|
),
|
||||||
|
media_type: mediaType,
|
||||||
|
availability: availability as Extract<Segment, { kind: "paste_artifact" }>[
|
||||||
|
"artifact"
|
||||||
|
]["availability"],
|
||||||
|
byte_len: unsignedInteger(item.byte_len, `${label}.byte_len`),
|
||||||
|
char_count: unsignedInteger(item.char_count, `${label}.char_count`),
|
||||||
|
line_count: unsignedInteger(item.line_count, `${label}.line_count`),
|
||||||
|
sha256: string(item.sha256, `${label}.sha256`),
|
||||||
|
source_entry_id: string(item.source_entry_id, `${label}.source_entry_id`),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadedFile(
|
||||||
|
value: unknown,
|
||||||
|
label: string,
|
||||||
|
): Extract<Segment, { kind: "uploaded_file" }>["file"] {
|
||||||
|
const item = record(value, label);
|
||||||
|
exact(
|
||||||
|
item,
|
||||||
|
[
|
||||||
|
"artifact_id",
|
||||||
|
"file_name",
|
||||||
|
"media_type",
|
||||||
|
"created_at_ms",
|
||||||
|
"availability",
|
||||||
|
"byte_len",
|
||||||
|
"sha256",
|
||||||
|
"source_entry_id",
|
||||||
|
],
|
||||||
|
label,
|
||||||
|
);
|
||||||
|
const availability = string(item.availability, `${label}.availability`);
|
||||||
|
if (
|
||||||
|
!["available", "unavailable", "integrity_failed"].includes(availability)
|
||||||
|
) {
|
||||||
|
throw new Error(`${label}.availability is invalid`);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
artifact_id: string(item.artifact_id, `${label}.artifact_id`),
|
||||||
|
file_name: string(item.file_name, `${label}.file_name`),
|
||||||
|
media_type: string(item.media_type, `${label}.media_type`),
|
||||||
|
created_at_ms: unsignedInteger(
|
||||||
|
item.created_at_ms,
|
||||||
|
`${label}.created_at_ms`,
|
||||||
|
),
|
||||||
|
availability: availability as Extract<Segment, { kind: "uploaded_file" }>[
|
||||||
|
"file"
|
||||||
|
]["availability"],
|
||||||
|
byte_len: unsignedInteger(item.byte_len, `${label}.byte_len`),
|
||||||
|
sha256: string(item.sha256, `${label}.sha256`),
|
||||||
|
source_entry_id: optional(
|
||||||
|
item.source_entry_id,
|
||||||
|
`${label}.source_entry_id`,
|
||||||
|
string,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function segment(value: unknown, label: string): Segment {
|
function segment(value: unknown, label: string): Segment {
|
||||||
const item = record(value, label);
|
const item = record(value, label);
|
||||||
const kind = string(item.kind, `${label}.kind`);
|
const kind = string(item.kind, `${label}.kind`) as Segment["kind"];
|
||||||
if (kind === "text") {
|
switch (kind) {
|
||||||
|
case "text":
|
||||||
exact(item, ["kind", "content"], label);
|
exact(item, ["kind", "content"], label);
|
||||||
return { kind, content: string(item.content, `${label}.content`) };
|
return { kind, content: string(item.content, `${label}.content`) };
|
||||||
}
|
case "paste":
|
||||||
|
exact(item, ["kind", "id", "chars", "lines", "content"], label);
|
||||||
|
return {
|
||||||
|
kind,
|
||||||
|
id: unsignedInteger(item.id, `${label}.id`),
|
||||||
|
chars: unsignedInteger(item.chars, `${label}.chars`),
|
||||||
|
lines: unsignedInteger(item.lines, `${label}.lines`),
|
||||||
|
content: string(item.content, `${label}.content`),
|
||||||
|
};
|
||||||
|
case "paste_artifact":
|
||||||
|
exact(item, ["kind", "artifact"], label);
|
||||||
|
return {
|
||||||
|
kind,
|
||||||
|
artifact: pasteArtifact(item.artifact, `${label}.artifact`),
|
||||||
|
};
|
||||||
|
case "uploaded_file":
|
||||||
|
exact(item, ["kind", "file"], label);
|
||||||
|
return { kind, file: uploadedFile(item.file, `${label}.file`) };
|
||||||
|
case "file_ref":
|
||||||
|
exact(item, ["kind", "path"], label);
|
||||||
|
return { kind, path: string(item.path, `${label}.path`) };
|
||||||
|
case "flow":
|
||||||
|
exact(item, ["kind", "selector"], label);
|
||||||
|
return { kind, selector: string(item.selector, `${label}.selector`) };
|
||||||
|
case "unknown":
|
||||||
throw new Error(`${label}.kind is not supported by Worker creation`);
|
throw new Error(`${label}.kind is not supported by Worker creation`);
|
||||||
}
|
}
|
||||||
|
const exhaustive: never = kind;
|
||||||
|
throw new Error(`${label}.kind is invalid: ${exhaustive}`);
|
||||||
|
}
|
||||||
|
|
||||||
export function parseCreateWorkspaceWorkerRequest(
|
export function parseCreateWorkspaceWorkerRequest(
|
||||||
value: unknown,
|
value: unknown,
|
||||||
|
|||||||
Reference in New Issue
Block a user