diff --git a/CHANGELOG.md b/CHANGELOG.md index 6500f0f45..2fdaf0db0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ Docs: https://docs.openclaw.ai - Security: keep untrusted channel metadata out of system prompts (Slack/Discord). Thanks @KonstantinMirin. - Security: enforce sandboxed media paths for message tool attachments. (#9182) Thanks @victormier. - Voice call: harden webhook verification with host allowlists/proxy trust and keep ngrok loopback bypass. +- Voice call: add regression coverage for anonymous inbound caller IDs with allowlist policy. (#8104) Thanks @victormier. - Cron: accept epoch timestamps and 0ms durations in CLI `--at` parsing. - Cron: reload store data when the store file is recreated or mtime changes. - Cron: deliver announce runs directly, honor delivery mode, and respect wakeMode for summaries. (#8540) Thanks @tyler6204. diff --git a/extensions/voice-call/src/manager.test.ts b/extensions/voice-call/src/manager.test.ts index 9e40a6459..e0285a444 100644 --- a/extensions/voice-call/src/manager.test.ts +++ b/extensions/voice-call/src/manager.test.ts @@ -135,6 +135,36 @@ describe("CallManager", () => { expect(provider.hangupCalls[0]?.providerCallId).toBe("provider-missing"); }); + it("rejects inbound calls with anonymous caller ID when allowlist enabled", () => { + const config = VoiceCallConfigSchema.parse({ + enabled: true, + provider: "plivo", + fromNumber: "+15550000000", + inboundPolicy: "allowlist", + allowFrom: ["+15550001234"], + }); + + const storePath = path.join(os.tmpdir(), `openclaw-voice-call-test-${Date.now()}`); + const provider = new FakeProvider(); + const manager = new CallManager(config, storePath); + manager.initialize(provider, "https://example.com/voice/webhook"); + + manager.processEvent({ + id: "evt-allowlist-anon", + type: "call.initiated", + callId: "call-anon", + providerCallId: "provider-anon", + timestamp: Date.now(), + direction: "inbound", + from: "anonymous", + to: "+15550000000", + }); + + expect(manager.getCallByProviderCallId("provider-anon")).toBeUndefined(); + expect(provider.hangupCalls).toHaveLength(1); + expect(provider.hangupCalls[0]?.providerCallId).toBe("provider-anon"); + }); + it("rejects inbound calls that only match allowlist suffixes", () => { const config = VoiceCallConfigSchema.parse({ enabled: true,