fix(gateway): trim cron job ids before exact lookup (#110849)

* fix(gateway): trim cron job ids before exact lookup

* test(gateway): cover padded legacy cron update ids

Co-authored-by: NIO <0668000903@xydigit.com>

* fix(gateway): preserve blank cron run selector scope

Co-authored-by: NIO <0668000903@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
nocodet888-arch
2026-07-28 00:38:57 +08:00
committed by GitHub
parent 445e262d26
commit 4c126fd844
2 changed files with 57 additions and 3 deletions
@@ -575,6 +575,31 @@ describe("cron method validation", () => {
});
});
it("trims whitespace around cron.get job ids before lookup", async () => {
const job = createCronJob({ id: "cron-42" });
const { context, respond } = await invokeCronGet({ jobId: " cron-42 " }, job);
expect(context.cron.readJob).toHaveBeenCalledWith("cron-42");
expectCronReadSuccess(respond, job);
});
it("trims whitespace around cron.run job ids before lookup", async () => {
const job = createCronJob({ id: "cron-42" });
const { context, respond } = await invokeCron(
"cron.run",
{ id: " cron-42 " },
{ currentJob: job },
);
expect(context.cron.readJob).toHaveBeenCalledWith("cron-42");
expect(context.cron.enqueueRun).toHaveBeenCalledWith("cron-42", "force");
expect(respond).toHaveBeenCalledWith(
true,
expect.objectContaining({ ok: true, enqueued: true, runId: "run-1" }),
undefined,
);
});
it("returns a single cron job for cron.get", async () => {
const job = createCronJob({ id: "cron-42", name: "single job" });
@@ -1837,6 +1862,20 @@ describe("cron method validation", () => {
expectCronSuccess(respond);
});
it("trims whitespace around legacy cron.update job ids before lookup", async () => {
const { context, respond } = await invokeCronUpdate(
{
jobId: " cron-1 ",
patch: { enabled: false },
},
createCronJob(),
);
expect(context.cron.readJob).toHaveBeenCalledWith("cron-1");
expect(context.cron.update).toHaveBeenCalledWith("cron-1", { enabled: false });
expectCronSuccess(respond);
});
it("allows cron.update to clear a display name", async () => {
const { context, respond } = await invokeCronUpdate(
{ id: "cron-1", patch: { displayName: null } },
@@ -3254,6 +3293,18 @@ describe("cron method validation", () => {
});
});
it("does not widen a whitespace-only cron.runs selector to all history", async () => {
const context = createCronContext();
const { respond } = await invokeCron("cron.runs", { id: " " }, { context });
expect(context.cron.list).not.toHaveBeenCalled();
expectResponseError(respond, {
code: "INVALID_REQUEST",
messageIncludes: "invalid cron.runs params: missing id",
});
});
it("hides caller-scoped cron.runs for a foreign job", async () => {
const context = createCronContext(createCronJob({ id: "cron-1", agentId: "worker" }));