fix: revert requireExplicitTarget default to false for backwards compatibility
Keep the security feature available but opt-in rather than opt-out. Maintainers can decide to change the default in a follow-up PR.
This commit is contained in:
parent
e712faadb9
commit
e260f38a69
@ -196,7 +196,7 @@ export type AgentDefaultsConfig = {
|
|||||||
/**
|
/**
|
||||||
* When true, require an explicit target for heartbeat delivery (no implicit routing).
|
* When true, require an explicit target for heartbeat delivery (no implicit routing).
|
||||||
* If no explicit target is provided, heartbeat delivery fails with an error.
|
* If no explicit target is provided, heartbeat delivery fails with an error.
|
||||||
* Default: true (strict mode; prevents accidental sends to stale/implicit targets).
|
* Default: false (backwards compatible; falls back to session-derived or "last" routing).
|
||||||
*/
|
*/
|
||||||
requireExplicitTarget?: boolean;
|
requireExplicitTarget?: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -145,14 +145,8 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses last route when requireExplicitTarget is false", () => {
|
it("uses last route by default", () => {
|
||||||
const cfg: ClawdbotConfig = {
|
const cfg: ClawdbotConfig = {};
|
||||||
agents: {
|
|
||||||
defaults: {
|
|
||||||
heartbeat: { requireExplicitTarget: false },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const entry = {
|
const entry = {
|
||||||
...baseEntry,
|
...baseEntry,
|
||||||
lastChannel: "whatsapp" as const,
|
lastChannel: "whatsapp" as const,
|
||||||
@ -186,13 +180,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("skips when last route is webchat", () => {
|
it("skips when last route is webchat", () => {
|
||||||
const cfg: ClawdbotConfig = {
|
const cfg: ClawdbotConfig = {};
|
||||||
agents: {
|
|
||||||
defaults: {
|
|
||||||
heartbeat: { requireExplicitTarget: false },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const entry = {
|
const entry = {
|
||||||
...baseEntry,
|
...baseEntry,
|
||||||
lastChannel: "webchat" as const,
|
lastChannel: "webchat" as const,
|
||||||
@ -209,9 +197,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
|||||||
|
|
||||||
it("applies allowFrom fallback for WhatsApp targets", () => {
|
it("applies allowFrom fallback for WhatsApp targets", () => {
|
||||||
const cfg: ClawdbotConfig = {
|
const cfg: ClawdbotConfig = {
|
||||||
agents: {
|
agents: { defaults: { heartbeat: { target: "whatsapp", to: "+1999" } } },
|
||||||
defaults: { heartbeat: { target: "whatsapp", to: "+1999", requireExplicitTarget: false } },
|
|
||||||
},
|
|
||||||
channels: { whatsapp: { allowFrom: ["+1555", "+1666"] } },
|
channels: { whatsapp: { allowFrom: ["+1555", "+1666"] } },
|
||||||
};
|
};
|
||||||
const entry = {
|
const entry = {
|
||||||
@ -219,20 +205,18 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
|||||||
lastChannel: "whatsapp" as const,
|
lastChannel: "whatsapp" as const,
|
||||||
lastTo: "+1222",
|
lastTo: "+1222",
|
||||||
};
|
};
|
||||||
// Note: The reason field is set based on whether the final resolved target
|
expect(resolveHeartbeatDeliveryTarget({ cfg, entry })).toEqual({
|
||||||
// differs from what explicit mode would have returned. With heartbeat mode,
|
channel: "whatsapp",
|
||||||
// the fallback behavior is expected.
|
to: "+1555",
|
||||||
const result = resolveHeartbeatDeliveryTarget({ cfg, entry });
|
reason: "allowFrom-fallback",
|
||||||
expect(result.channel).toBe("whatsapp");
|
accountId: undefined,
|
||||||
expect(result.to).toBe("+1555");
|
lastChannel: "whatsapp",
|
||||||
expect(result.lastChannel).toBe("whatsapp");
|
lastAccountId: undefined,
|
||||||
expect(result.accountId).toBeUndefined();
|
});
|
||||||
expect(result.lastAccountId).toBeUndefined();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps WhatsApp group targets even with allowFrom set", () => {
|
it("keeps WhatsApp group targets even with allowFrom set", () => {
|
||||||
const cfg: ClawdbotConfig = {
|
const cfg: ClawdbotConfig = {
|
||||||
agents: { defaults: { heartbeat: { requireExplicitTarget: false } } },
|
|
||||||
channels: { whatsapp: { allowFrom: ["+1555"] } },
|
channels: { whatsapp: { allowFrom: ["+1555"] } },
|
||||||
};
|
};
|
||||||
const entry = {
|
const entry = {
|
||||||
@ -251,7 +235,6 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
|||||||
|
|
||||||
it("normalizes prefixed WhatsApp group targets for heartbeat delivery", () => {
|
it("normalizes prefixed WhatsApp group targets for heartbeat delivery", () => {
|
||||||
const cfg: ClawdbotConfig = {
|
const cfg: ClawdbotConfig = {
|
||||||
agents: { defaults: { heartbeat: { requireExplicitTarget: false } } },
|
|
||||||
channels: { whatsapp: { allowFrom: ["+1555"] } },
|
channels: { whatsapp: { allowFrom: ["+1555"] } },
|
||||||
};
|
};
|
||||||
const entry = {
|
const entry = {
|
||||||
@ -350,7 +333,7 @@ describe("runHeartbeatOnce", () => {
|
|||||||
const cfg: ClawdbotConfig = {
|
const cfg: ClawdbotConfig = {
|
||||||
agents: {
|
agents: {
|
||||||
defaults: {
|
defaults: {
|
||||||
heartbeat: { every: "5m", target: "whatsapp", requireExplicitTarget: false },
|
heartbeat: { every: "5m", target: "whatsapp" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
channels: { whatsapp: { allowFrom: ["*"] } },
|
channels: { whatsapp: { allowFrom: ["*"] } },
|
||||||
@ -407,18 +390,13 @@ describe("runHeartbeatOnce", () => {
|
|||||||
const cfg: ClawdbotConfig = {
|
const cfg: ClawdbotConfig = {
|
||||||
agents: {
|
agents: {
|
||||||
defaults: {
|
defaults: {
|
||||||
heartbeat: { every: "30m", prompt: "Default prompt", requireExplicitTarget: false },
|
heartbeat: { every: "30m", prompt: "Default prompt" },
|
||||||
},
|
},
|
||||||
list: [
|
list: [
|
||||||
{ id: "main", default: true },
|
{ id: "main", default: true },
|
||||||
{
|
{
|
||||||
id: "ops",
|
id: "ops",
|
||||||
heartbeat: {
|
heartbeat: { every: "5m", target: "whatsapp", prompt: "Ops check" },
|
||||||
every: "5m",
|
|
||||||
target: "whatsapp",
|
|
||||||
prompt: "Ops check",
|
|
||||||
requireExplicitTarget: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -486,7 +464,6 @@ describe("runHeartbeatOnce", () => {
|
|||||||
heartbeat: {
|
heartbeat: {
|
||||||
every: "5m",
|
every: "5m",
|
||||||
target: "last",
|
target: "last",
|
||||||
requireExplicitTarget: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -565,7 +542,7 @@ describe("runHeartbeatOnce", () => {
|
|||||||
const cfg: ClawdbotConfig = {
|
const cfg: ClawdbotConfig = {
|
||||||
agents: {
|
agents: {
|
||||||
defaults: {
|
defaults: {
|
||||||
heartbeat: { every: "5m", target: "whatsapp", requireExplicitTarget: false },
|
heartbeat: { every: "5m", target: "whatsapp" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
channels: { whatsapp: { allowFrom: ["*"] } },
|
channels: { whatsapp: { allowFrom: ["*"] } },
|
||||||
@ -624,7 +601,6 @@ describe("runHeartbeatOnce", () => {
|
|||||||
every: "5m",
|
every: "5m",
|
||||||
target: "whatsapp",
|
target: "whatsapp",
|
||||||
includeReasoning: true,
|
includeReasoning: true,
|
||||||
requireExplicitTarget: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -696,7 +672,6 @@ describe("runHeartbeatOnce", () => {
|
|||||||
every: "5m",
|
every: "5m",
|
||||||
target: "whatsapp",
|
target: "whatsapp",
|
||||||
includeReasoning: true,
|
includeReasoning: true,
|
||||||
requireExplicitTarget: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -762,7 +737,7 @@ describe("runHeartbeatOnce", () => {
|
|||||||
try {
|
try {
|
||||||
const cfg: ClawdbotConfig = {
|
const cfg: ClawdbotConfig = {
|
||||||
agents: {
|
agents: {
|
||||||
defaults: { heartbeat: { every: "5m", requireExplicitTarget: false } },
|
defaults: { heartbeat: { every: "5m" } },
|
||||||
list: [{ id: "work", default: true }],
|
list: [{ id: "work", default: true }],
|
||||||
},
|
},
|
||||||
channels: { whatsapp: { allowFrom: ["*"] } },
|
channels: { whatsapp: { allowFrom: ["*"] } },
|
||||||
@ -838,7 +813,7 @@ describe("runHeartbeatOnce", () => {
|
|||||||
agents: {
|
agents: {
|
||||||
defaults: {
|
defaults: {
|
||||||
workspace: workspaceDir,
|
workspace: workspaceDir,
|
||||||
heartbeat: { every: "5m", target: "whatsapp", requireExplicitTarget: false },
|
heartbeat: { every: "5m", target: "whatsapp" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
channels: { whatsapp: { allowFrom: ["*"] } },
|
channels: { whatsapp: { allowFrom: ["*"] } },
|
||||||
@ -910,7 +885,7 @@ describe("runHeartbeatOnce", () => {
|
|||||||
agents: {
|
agents: {
|
||||||
defaults: {
|
defaults: {
|
||||||
workspace: workspaceDir,
|
workspace: workspaceDir,
|
||||||
heartbeat: { every: "5m", target: "whatsapp", requireExplicitTarget: false },
|
heartbeat: { every: "5m", target: "whatsapp" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
channels: { whatsapp: { allowFrom: ["*"] } },
|
channels: { whatsapp: { allowFrom: ["*"] } },
|
||||||
@ -974,7 +949,7 @@ describe("runHeartbeatOnce", () => {
|
|||||||
agents: {
|
agents: {
|
||||||
defaults: {
|
defaults: {
|
||||||
workspace: workspaceDir,
|
workspace: workspaceDir,
|
||||||
heartbeat: { every: "5m", target: "whatsapp", requireExplicitTarget: false },
|
heartbeat: { every: "5m", target: "whatsapp" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
channels: { whatsapp: { allowFrom: ["*"] } },
|
channels: { whatsapp: { allowFrom: ["*"] } },
|
||||||
|
|||||||
@ -183,7 +183,7 @@ export function resolveHeartbeatDeliveryTarget(params: {
|
|||||||
const heartbeat = params.heartbeat ?? cfg.agents?.defaults?.heartbeat;
|
const heartbeat = params.heartbeat ?? cfg.agents?.defaults?.heartbeat;
|
||||||
const rawTarget = heartbeat?.target;
|
const rawTarget = heartbeat?.target;
|
||||||
// FIX-1.4: Default to strict mode - require explicit target for heartbeat delivery
|
// FIX-1.4: Default to strict mode - require explicit target for heartbeat delivery
|
||||||
const requireExplicitTarget = heartbeat?.requireExplicitTarget ?? true;
|
const requireExplicitTarget = heartbeat?.requireExplicitTarget ?? false;
|
||||||
const explicitTo = heartbeat?.to?.trim();
|
const explicitTo = heartbeat?.to?.trim();
|
||||||
let target: HeartbeatTarget = "last";
|
let target: HeartbeatTarget = "last";
|
||||||
if (rawTarget === "none" || rawTarget === "last") {
|
if (rawTarget === "none" || rawTarget === "last") {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user