Channels: preserve routed group policy (#56011)

This commit is contained in:
Jacob Tomlinson
2026-03-27 13:33:47 -07:00
committed by GitHub
parent 77060aa9f9
commit e64a881ae0
4 changed files with 57 additions and 12 deletions

View File

@@ -213,6 +213,45 @@ describe("googlechat inbound access policy", () => {
});
});
it("preserves allowlist group policy when a routed space has no sender allowlist", async () => {
primeCommonDefaults();
allowInboundGroupTraffic({
effectiveGroupAllowFrom: [],
effectiveWasMentioned: false,
});
resolveSenderScopedGroupPolicy.mockReturnValue("open");
resolveSenderScopedGroupPolicy.mockClear();
resolveDmGroupAccessWithLists.mockClear();
await expect(
applyInboundAccessPolicy({
account: {
accountId: "default",
config: {
groups: {
"spaces/AAA": {
allow: true,
},
},
},
} as never,
}),
).resolves.toEqual({
ok: true,
commandAuthorized: undefined,
effectiveWasMentioned: false,
groupSystemPrompt: undefined,
});
expect(resolveSenderScopedGroupPolicy).not.toHaveBeenCalled();
expect(resolveDmGroupAccessWithLists).toHaveBeenCalledWith(
expect.objectContaining({
groupPolicy: "allowlist",
groupAllowFrom: [],
}),
);
});
it("drops unauthorized group control commands", async () => {
primeCommonDefaults();
allowInboundGroupTraffic({

View File

@@ -271,10 +271,13 @@ export async function applyGoogleChatInboundAccessPolicy(params: {
const dmPolicy = account.config.dm?.policy ?? "pairing";
const configAllowFrom = (account.config.dm?.allowFrom ?? []).map((v) => String(v));
const normalizedGroupUsers = groupUsers.map((v) => String(v));
const senderGroupPolicy = resolveSenderScopedGroupPolicy({
groupPolicy,
groupAllowFrom: normalizedGroupUsers,
});
const senderGroupPolicy =
groupConfigResolved.allowlistConfigured && normalizedGroupUsers.length === 0
? groupPolicy
: resolveSenderScopedGroupPolicy({
groupPolicy,
groupAllowFrom: normalizedGroupUsers,
});
const shouldComputeAuth = core.channel.commands.shouldComputeCommandAuthorized(rawBody, config);
const storeAllowFrom =
!isGroup && dmPolicy !== "allowlist" && (dmPolicy !== "open" || shouldComputeAuth)

View File

@@ -507,10 +507,9 @@ describe("zalouser monitor group mention gating", () => {
});
});
it("allows allowlisted group replies without inheriting the DM allowlist", async () => {
it("blocks routed allowlist groups without an explicit group sender allowlist", async () => {
const { dispatchReplyWithBufferedBlockDispatcher } = installRuntime({
commandAuthorized: false,
replyPayload: { text: "ok" },
});
await __testing.processMessage({
message: createGroupMessage({
@@ -534,7 +533,7 @@ describe("zalouser monitor group mention gating", () => {
runtime: createRuntimeEnv(),
});
expect(dispatchReplyWithBufferedBlockDispatcher).toHaveBeenCalledTimes(1);
expect(dispatchReplyWithBufferedBlockDispatcher).not.toHaveBeenCalled();
});
it("blocks group messages when sender is not in groupAllowFrom", async () => {

View File

@@ -311,6 +311,7 @@ async function processMessage(
});
const groups = account.config.groups ?? {};
const routeAllowlistConfigured = Object.keys(groups).length > 0;
const allowNameMatching = isDangerousNameMatchingEnabled(account.config);
if (isGroup) {
const groupEntry = findZalouserGroupEntry(
@@ -325,7 +326,7 @@ async function processMessage(
);
const routeAccess = evaluateGroupRouteAccessForPolicy({
groupPolicy,
routeAllowlistConfigured: Object.keys(groups).length > 0,
routeAllowlistConfigured,
routeMatched: Boolean(groupEntry),
routeEnabled: isZalouserGroupEntryAllowed(groupEntry),
});
@@ -350,10 +351,13 @@ async function processMessage(
const dmPolicy = account.config.dmPolicy ?? "pairing";
const configAllowFrom = (account.config.allowFrom ?? []).map((v) => String(v));
const configGroupAllowFrom = (account.config.groupAllowFrom ?? []).map((v) => String(v));
const senderGroupPolicy = resolveSenderScopedGroupPolicy({
groupPolicy,
groupAllowFrom: configGroupAllowFrom,
});
const senderGroupPolicy =
routeAllowlistConfigured && configGroupAllowFrom.length === 0
? groupPolicy
: resolveSenderScopedGroupPolicy({
groupPolicy,
groupAllowFrom: configGroupAllowFrom,
});
const shouldComputeCommandAuth = core.channel.commands.shouldComputeCommandAuthorized(
commandBody,
config,