惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

美团技术团队
阮一峰的网络日志
阮一峰的网络日志
T
The Blog of Author Tim Ferriss
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
宝玉的分享
宝玉的分享
L
LangChain Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Last Week in AI
Last Week in AI
博客园 - 司徒正美
M
MIT News - Artificial intelligence
人人都是产品经理
人人都是产品经理
WordPress大学
WordPress大学
B
Blog RSS Feed
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园 - Franky
B
Blog
V
V2EX
J
Java Code Geeks
D
Docker
博客园 - 叶小钗
The Cloudflare Blog
量子位
博客园_首页
MongoDB | Blog
MongoDB | Blog

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
test(whatsapp): cover inbound admission contract · opencl...
mcaxtr · 2026-06-16 · via Recent Commits to openclaw:main
11

// Whatsapp tests cover access control plugin behavior.

22

import { beforeAll, describe, expect, it } from "vitest";

3+

import type {

4+

AcceptedInboundAccessControlResult,

5+

InboundAccessControlResult,

6+

} from "./access-control.js";

37

import {

48

readAllowFromStoreMock,

59

sendMessageMock,

@@ -19,6 +23,15 @@ beforeAll(async () => {

1923

({ resolveWhatsAppCommandAuthorized } = await import("../inbound-policy.js"));

2024

});

212526+

function expectAccepted(

27+

result: InboundAccessControlResult,

28+

): asserts result is AcceptedInboundAccessControlResult {

29+

expect(result.allowed).toBe(true);

30+

if (!result.allowed) {

31+

throw new Error("Expected accepted inbound access result");

32+

}

33+

}

34+2235

async function checkUnauthorizedWorkDmSender() {

2336

return checkInboundAccessControl({

2437

cfg: getAccessControlTestConfig() as never,

@@ -92,6 +105,190 @@ async function checkCommandAuthorizedForGroup(params: {

92105

});

93106

}

94107108+

describe("checkInboundAccessControl admission contract", () => {

109+

it("keeps blocked results on the legacy flat access shape", async () => {

110+

const cfg = {

111+

channels: {

112+

whatsapp: {

113+

dmPolicy: "allowlist",

114+

allowFrom: ["+15559999999"],

115+

},

116+

},

117+

};

118+

setAccessControlTestConfig(cfg);

119+120+

const result = await checkInboundAccessControl({

121+

cfg: getAccessControlTestConfig() as never,

122+

accountId: "default",

123+

from: "+15550001111",

124+

selfE164: "+15550009999",

125+

senderE164: "+15550001111",

126+

group: false,

127+

pushName: "Stranger",

128+

isFromMe: false,

129+

sock: { sendMessage: sendMessageMock },

130+

remoteJid: "15550001111@s.whatsapp.net",

131+

});

132+133+

expect(result).toMatchObject({

134+

allowed: false,

135+

shouldMarkRead: false,

136+

resolvedAccountId: "default",

137+

isSelfChat: false,

138+

});

139+

expect("admission" in result).toBe(false);

140+

});

141+142+

it("returns accepted facts through admission while preserving legacy access fields", async () => {

143+

const cfg = {

144+

channels: {

145+

whatsapp: {

146+

dmPolicy: "allowlist",

147+

contextVisibility: "allowlist_quote",

148+

allowFrom: ["+15550001111"],

149+

direct: {

150+

"+15550001111": {

151+

systemPrompt: "direct prompt",

152+

},

153+

},

154+

},

155+

},

156+

};

157+

setAccessControlTestConfig(cfg);

158+159+

const result = await checkInboundAccessControl({

160+

cfg: getAccessControlTestConfig() as never,

161+

accountId: "default",

162+

from: "+15550001111",

163+

selfE164: "+15550009999",

164+

senderE164: "+15550001111",

165+

group: false,

166+

pushName: "Sam",

167+

isFromMe: false,

168+

sock: { sendMessage: sendMessageMock },

169+

remoteJid: "15550001111@s.whatsapp.net",

170+

});

171+172+

expectAccepted(result);

173+

expect(result.resolvedAccountId).toBe(result.admission.accountId);

174+

expect(result.isSelfChat).toBe(result.admission.isSelfChat);

175+

expect(result.shouldMarkRead).toBe(true);

176+

expect(result.admission).toMatchObject({

177+

accountId: "default",

178+

account: {

179+

accountId: "default",

180+

enabled: true,

181+

sendReadReceipts: true,

182+

},

183+

conversation: {

184+

kind: "direct",

185+

id: "+15550001111",

186+

groupSessionId: "+15550001111",

187+

},

188+

sender: {

189+

id: "+15550001111",

190+

dmSenderId: "+15550001111",

191+

isSamePhone: false,

192+

isDmSenderSamePhone: false,

193+

},

194+

ingress: {

195+

admission: "dispatch",

196+

decision: "allow",

197+

reasonCode: "activation_allowed",

198+

},

199+

senderAccess: {

200+

allowed: true,

201+

decision: "allow",

202+

providerMissingFallbackApplied: false,

203+

reasonCode: "dm_policy_allowlisted",

204+

},

205+

commandAccess: {

206+

requested: false,

207+

authorized: false,

208+

shouldBlockControlCommand: false,

209+

reasonCode: "command_authorized",

210+

},

211+

activationAccess: {

212+

ran: true,

213+

allowed: true,

214+

shouldSkip: false,

215+

reasonCode: "activation_allowed",

216+

},

217+

});

218+

expect(result.admission.account).not.toHaveProperty("authDir");

219+

expect(result.admission.conversation).not.toHaveProperty("requireMention");

220+

expect(result.admission.senderAccess).not.toHaveProperty("effectiveAllowFrom");

221+

expect(result.admission.senderAccess).not.toHaveProperty("effectiveGroupAllowFrom");

222+

expect(result.admission).not.toHaveProperty("resolvedPolicy");

223+

});

224+225+

it("uses group participant JID as the admission sender fallback", async () => {

226+

const groupJid = "120363401234567890@g.us";

227+

const participantJid = "15550001111@s.whatsapp.net";

228+

const cfg = {

229+

channels: {

230+

whatsapp: {

231+

groupPolicy: "open",

232+

},

233+

},

234+

};

235+

setAccessControlTestConfig(cfg);

236+237+

const result = await checkInboundAccessControl({

238+

cfg: getAccessControlTestConfig() as never,

239+

accountId: "default",

240+

from: groupJid,

241+

selfE164: "+15550009999",

242+

senderE164: null,

243+

senderJid: participantJid,

244+

group: true,

245+

pushName: "Sam",

246+

isFromMe: false,

247+

sock: { sendMessage: sendMessageMock },

248+

remoteJid: groupJid,

249+

});

250+251+

expectAccepted(result);

252+

expect(result.admission.conversation).toMatchObject({

253+

kind: "group",

254+

id: groupJid,

255+

groupSessionId: groupJid,

256+

});

257+

expect(result.admission.sender.id).toBe(participantJid);

258+

expect(result.admission.sender.dmSenderId).toBe(groupJid);

259+

});

260+261+

it("does not authorize unresolved group participant JIDs as phone allowlist entries", async () => {

262+

const groupJid = "120363401234567890@g.us";

263+

const cfg = {

264+

channels: {

265+

whatsapp: {

266+

groupPolicy: "allowlist",

267+

groupAllowFrom: ["+15550001111"],

268+

},

269+

},

270+

};

271+

setAccessControlTestConfig(cfg);

272+273+

const result = await checkInboundAccessControl({

274+

cfg: getAccessControlTestConfig() as never,

275+

accountId: "default",

276+

from: groupJid,

277+

selfE164: "+15550009999",

278+

senderE164: null,

279+

senderJid: "15550001111@lid",

280+

group: true,

281+

pushName: "Sam",

282+

isFromMe: false,

283+

sock: { sendMessage: sendMessageMock },

284+

remoteJid: groupJid,

285+

});

286+287+

expect(result.allowed).toBe(false);

288+

expect("admission" in result).toBe(false);

289+

});

290+

});

291+95292

describe("checkInboundAccessControl pairing grace", () => {

96293

async function runPairingGraceCase(messageTimestampMs: number) {

97294

const connectedAtMs = 1_000_000;