Skip to content

Commit 72bc9ae

Browse files
committed
fix: keep cron update delivery validation scoped
1 parent d2f1c0e commit 72bc9ae

2 files changed

Lines changed: 43 additions & 6 deletions

File tree

src/gateway/server-methods/cron.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -166,16 +166,19 @@ function assertValidCronUpdatePatch(params: {
166166
currentJob: CronJob;
167167
patch: CronJobPatch;
168168
}) {
169-
// Validate the post-patch job, not just the sparse patch, because delivery
170-
// and payload/session fields can be split across existing state and patch.
169+
// Apply the full patch so service-owned payload/session constraints are
170+
// checked before mutation; configured-channel checks stay delivery-scoped so
171+
// stale existing delivery does not block unrelated updates like disabling.
171172
const nextJob = structuredClone(params.currentJob);
172173
applyJobPatch(nextJob, params.patch, {
173174
defaultAgentId: params.defaultAgentId,
174175
});
175-
assertValidCronAnnounceDelivery({
176-
cfg: params.cfg,
177-
delivery: nextJob.delivery,
178-
});
176+
if ("delivery" in params.patch) {
177+
assertValidCronAnnounceDelivery({
178+
cfg: params.cfg,
179+
delivery: nextJob.delivery,
180+
});
181+
}
179182
}
180183

181184
function resolveCronJobId(params: CronJobIdParams): string | undefined {

src/gateway/server-methods/cron.validation.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,40 @@ describe("cron method validation", () => {
608608
expectResponseError(respond, { messageIncludes: "delivery.channel is required" });
609609
});
610610

611+
it("does not revalidate stale delivery config for unrelated updates", async () => {
612+
setRuntimeConfig({
613+
session: {
614+
mainKey: "main",
615+
},
616+
channels: {
617+
slack: {
618+
botToken: "xoxb-slack-token",
619+
appToken: "xapp-slack-token",
620+
},
621+
},
622+
plugins: {
623+
entries: {
624+
slack: { enabled: true },
625+
},
626+
},
627+
});
628+
629+
const { context, respond } = await invokeCronUpdate(
630+
{
631+
id: "cron-1",
632+
patch: {
633+
enabled: false,
634+
},
635+
},
636+
createCronJob({
637+
delivery: { mode: "announce", channel: "telegram", to: "telegram:123" },
638+
}),
639+
);
640+
641+
expect(context.cron.update).toHaveBeenCalledWith("cron-1", { enabled: false });
642+
expect(respond).toHaveBeenCalledWith(true, { id: "cron-1" }, undefined);
643+
});
644+
611645
it("rejects target ids mistakenly supplied as delivery.channel providers", async () => {
612646
setRuntimeConfig({
613647
session: {

0 commit comments

Comments
 (0)