Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion actions/setup/js/work_queue_delivery.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ async function verifyBuiltinDeliveryOutput(options) {
if (["create_discussion", "create_pull_request"].includes(message.type)) return require("./work_queue_native_creation_delivery.cjs").verifyNativeCreationDelivery(options);
// Updating branches still requires its own pinned commit/tree verifier.
if (message.type === "update_pull_request") return unverified("delivery.builtin.pinned_verifier_required");
const verifiedFields = new Set(["type", "claim_handle", "claim_id", "work_id", "repo", "item_number", "issue_number", "pull_request_number", "temporary_id", ...(BUILTIN_EFFECT_FIELDS[message.type] || [])]);
const verifiedFields = new Set(["type", "output_id", "depends-on", "claim_handle", "claim_id", "work_id", "repo", "item_number", "issue_number", "pull_request_number", "temporary_id", ...(BUILTIN_EFFECT_FIELDS[message.type] || [])]);
if (Object.keys(message).some(field => !verifiedFields.has(field))) return unverified("delivery.builtin.undeclared_fields");
if (!result || result.staged || !github?.rest || message.data !== undefined || message.duplicate_of !== undefined)
return unverified("delivery.builtin.readback_unavailable", { result_present: !!result, staged: !!result?.staged, client_present: !!github?.rest, data_present: message.data !== undefined, duplicate: message.duplicate_of !== undefined });
Expand Down
55 changes: 29 additions & 26 deletions actions/setup/js/work_queue_delivery.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -41,35 +41,38 @@ describe("historical diagnostic delivery contracts", () => {
for (const legacy of ["missing_tool", "missing_data"]) {
const canonical = `report_${legacy}`;

it(`matches ${legacy} contracts and messages canonically without rewriting immutable Work`, async () => {
for (const contractType of [legacy, canonical]) {
const original = assignment([
{ type: "create_issue", min: 1, max: 1 },
{ type: contractType, min: 1, max: 1 },
]);
const before = JSON.stringify(original);
const beforeDigest = digest(original);
expect(validateDeliveryContract(original.claims[0].work.effect_contract)).toBe(original.claims[0].work.effect_contract);
for (const messageType of [legacy, canonical]) {
const messages = [Object.freeze({ type: "create_issue", repo: "owner/repo" }), Object.freeze({ type: messageType })];
const delivered = await deliver(original, messages, {
verifyOutput: verifyBuiltinDeliveryOutput,
github: {
rest: {
repos: { get: async () => ({ data: { id: 7, full_name: "owner/repo" } }) },
issues: { get: async () => ({ data: { id: 142, number: 42, html_url: "https://github.com/owner/repo/issues/42" } }) },
it.each([{}, { output_id: "so_xbzi2dhGSY-3" }, { "depends-on": "so_priorOutput1" }, { output_id: "so_xbzi2dhGSY-3", "depends-on": "so_priorOutput1" }])(
`matches ${legacy} contracts and messages canonically without rewriting immutable Work with metadata %j`,
async metadata => {
for (const contractType of [legacy, canonical]) {
const original = assignment([
{ type: "create_issue", min: 1, max: 1 },
{ type: contractType, min: 1, max: 1 },
]);
const before = JSON.stringify(original);
const beforeDigest = digest(original);
expect(validateDeliveryContract(original.claims[0].work.effect_contract)).toBe(original.claims[0].work.effect_contract);
for (const messageType of [legacy, canonical]) {
const messages = [Object.freeze({ type: "create_issue", repo: "owner/repo", ...metadata }), Object.freeze({ type: messageType })];
const delivered = await deliver(original, messages, {
verifyOutput: verifyBuiltinDeliveryOutput,
github: {
rest: {
repos: { get: async () => ({ data: { id: 7, full_name: "owner/repo" } }) },
issues: { get: async () => ({ data: { id: 142, number: 42, html_url: "https://github.com/owner/repo/issues/42" } }) },
},
},
},
});
expect(delivered.verification).toBe("verified");
expect(delivered.disposition).toBe("complete");
expect(delivered.descriptor.outputs[1]).toEqual({ type: canonical, effect: "none" });
expect(messages[1].type).toBe(messageType);
expect(JSON.stringify(original)).toBe(before);
expect(digest(original)).toBe(beforeDigest);
});
expect(delivered.verification).toBe("verified");
expect(delivered.disposition).toBe("complete");
expect(delivered.descriptor.outputs[1]).toEqual({ type: canonical, effect: "none" });
expect(messages[1].type).toBe(messageType);
expect(JSON.stringify(original)).toBe(before);
expect(digest(original)).toBe(beforeDigest);
}
}
}
});
);

it(`shares cardinality across ${legacy} and ${canonical} messages`, async () => {
const messages = [{ type: legacy }, { type: canonical }];
Expand Down
2 changes: 2 additions & 0 deletions actions/setup/js/work_queue_native_creation_delivery.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ async function verifyNativeCreationDelivery(options) {
}
const fields = new Set([
"type",
"output_id",
"depends-on",
"claim_handle",
"claim_id",
"work_id",
Expand Down
19 changes: 18 additions & 1 deletion actions/setup/js/work_queue_native_creation_delivery.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -610,8 +610,13 @@ describe("native creation Claim delivery", () => {
}
});

it.each(["create_discussion", "create_pull_request"])("settles %s through the actual manager verifier and publishes a protected Result", async type => {
it.each(
["create_discussion", "create_pull_request"].flatMap(type =>
[{}, { output_id: "so_xbzi2dhGSY-3" }, { "depends-on": "so_priorOutput1" }, { output_id: "so_xbzi2dhGSY-3", "depends-on": "so_priorOutput1" }].map(metadata => ({ type, metadata }))
)
)("settles $type with submission metadata $metadata through the actual manager verifier and publishes a protected Result", async ({ type, metadata }) => {
const f = fixture(type);
Object.assign(f.message, metadata);
await f.execute(async () => {
await f.capture();
expect(closeClaimEffectChannel()).toBeDefined();
Expand All @@ -624,6 +629,18 @@ describe("native creation Claim delivery", () => {
expect(f.queue.state.works.get(f.member.work_id).barrier).toBe("verified");
});

it.each(["create_discussion", "create_pull_request"])("rejects undeclared %s fields even with submission metadata", async type => {
const f = fixture(type);
Object.assign(f.message, { output_id: "so_xbzi2dhGSY-3", "depends-on": "so_priorOutput1", unexpected_transport_field: "untrusted" });
await f.execute(async () => {
await f.capture();
expect((await f.settle()).verification).toBe("unknown");
});
expect(f.client.graphql).not.toHaveBeenCalled();
expect(f.client.rest.pulls.get).not.toHaveBeenCalled();
expect(f.queue.state.works.get(f.member.work_id).barrier).toBe("pending");
});

it("settles the enriched PR message emitted by the safe-output transport", async () => {
const f = fixture("create_pull_request");
Object.assign(f.message, { head_repo: REPOSITORY, base_branch: "main", base_commit: BASE });
Expand Down
Loading