refactor: share sender-scoped group policy derivation

This commit is contained in:
Peter Steinberger
2026-03-07 22:49:30 +00:00
parent 621063a956
commit 5bbca5be91
9 changed files with 63 additions and 20 deletions

View File

@@ -7,6 +7,7 @@ import {
resolveDefaultGroupPolicy,
resolveDmGroupAccessWithLists,
resolveMentionGatingWithBypass,
resolveSenderScopedGroupPolicy,
warnMissingProviderGroupPolicyFallbackOnce,
} from "openclaw/plugin-sdk/googlechat";
import type { OpenClawConfig } from "openclaw/plugin-sdk/googlechat";
@@ -229,12 +230,10 @@ 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 =
groupPolicy === "disabled"
? "disabled"
: normalizedGroupUsers.length > 0
? "allowlist"
: "open";
const senderGroupPolicy = resolveSenderScopedGroupPolicy({
groupPolicy,
groupAllowFrom: normalizedGroupUsers,
});
const shouldComputeAuth = core.channel.commands.shouldComputeCommandAuthorized(rawBody, config);
const storeAllowFrom =
!isGroup && dmPolicy !== "allowlist" && (dmPolicy !== "open" || shouldComputeAuth)

View File

@@ -3,6 +3,7 @@ import {
issuePairingChallenge,
readStoreAllowFromForDmPolicy,
resolveDmGroupAccessWithLists,
resolveSenderScopedGroupPolicy,
} from "openclaw/plugin-sdk/matrix";
import {
normalizeMatrixAllowList,
@@ -32,12 +33,10 @@ export async function resolveMatrixAccessState(params: {
})
: [];
const normalizedGroupAllowFrom = normalizeMatrixAllowList(params.groupAllowFrom);
const senderGroupPolicy =
params.groupPolicy === "disabled"
? "disabled"
: normalizedGroupAllowFrom.length > 0
? "allowlist"
: "open";
const senderGroupPolicy = resolveSenderScopedGroupPolicy({
groupPolicy: params.groupPolicy,
groupAllowFrom: normalizedGroupAllowFrom,
});
const access = resolveDmGroupAccessWithLists({
isGroup: !params.isDirectMessage,
dmPolicy: params.dmPolicy,

View File

@@ -7,6 +7,7 @@ import {
createScopedPairingAccess,
logInboundDrop,
evaluateSenderGroupAccessForPolicy,
resolveSenderScopedGroupPolicy,
recordPendingHistoryEntryIfEnabled,
resolveControlCommandGate,
resolveDefaultGroupPolicy,
@@ -175,12 +176,10 @@ export function createMSTeamsMessageHandler(deps: MSTeamsMessageHandlerDeps) {
conversationId,
channelName,
});
const senderGroupPolicy =
groupPolicy === "disabled"
? "disabled"
: effectiveGroupAllowFrom.length > 0
? "allowlist"
: "open";
const senderGroupPolicy = resolveSenderScopedGroupPolicy({
groupPolicy,
groupAllowFrom: effectiveGroupAllowFrom,
});
const access = resolveDmGroupAccessWithLists({
isGroup: !isDirectMessage,
dmPolicy,

View File

@@ -73,6 +73,7 @@ export type { WizardPrompter } from "../wizard/prompts.js";
export { resolveInboundRouteEnvelopeBuilderWithRuntime } from "./inbound-envelope.js";
export { createScopedPairingAccess } from "./pairing-access.js";
export { issuePairingChallenge } from "../pairing/pairing-challenge.js";
export { resolveSenderScopedGroupPolicy } from "./group-access.js";
export { extractToolSend } from "./tool-send.js";
export { resolveWebhookPath } from "./webhook-path.js";
export type { WebhookInFlightLimiter } from "./webhook-request-guards.js";

View File

@@ -1,5 +1,35 @@
import { describe, expect, it } from "vitest";
import { evaluateSenderGroupAccess, evaluateSenderGroupAccessForPolicy } from "./group-access.js";
import {
evaluateSenderGroupAccess,
evaluateSenderGroupAccessForPolicy,
resolveSenderScopedGroupPolicy,
} from "./group-access.js";
describe("resolveSenderScopedGroupPolicy", () => {
it("preserves disabled policy", () => {
expect(
resolveSenderScopedGroupPolicy({
groupPolicy: "disabled",
groupAllowFrom: ["a"],
}),
).toBe("disabled");
});
it("maps open/allowlist based on effective sender allowlist", () => {
expect(
resolveSenderScopedGroupPolicy({
groupPolicy: "allowlist",
groupAllowFrom: ["a"],
}),
).toBe("allowlist");
expect(
resolveSenderScopedGroupPolicy({
groupPolicy: "allowlist",
groupAllowFrom: [],
}),
).toBe("open");
});
});
describe("evaluateSenderGroupAccessForPolicy", () => {
it("blocks disabled policy", () => {

View File

@@ -14,6 +14,16 @@ export type SenderGroupAccessDecision = {
reason: SenderGroupAccessReason;
};
export function resolveSenderScopedGroupPolicy(params: {
groupPolicy: GroupPolicy;
groupAllowFrom: string[];
}): GroupPolicy {
if (params.groupPolicy === "disabled") {
return "disabled";
}
return params.groupAllowFrom.length > 0 ? "allowlist" : "open";
}
export function evaluateSenderGroupAccessForPolicy(params: {
groupPolicy: GroupPolicy;
providerMissingFallbackApplied?: boolean;

View File

@@ -280,6 +280,7 @@ export {
export {
evaluateSenderGroupAccess,
evaluateSenderGroupAccessForPolicy,
resolveSenderScopedGroupPolicy,
type SenderGroupAccessDecision,
type SenderGroupAccessReason,
} from "./group-access.js";

View File

@@ -93,6 +93,7 @@ export {
} from "../security/dm-policy-shared.js";
export { formatDocsLink } from "../terminal/links.js";
export type { WizardPrompter } from "../wizard/prompts.js";
export { resolveSenderScopedGroupPolicy } from "./group-access.js";
export { createScopedPairingAccess } from "./pairing-access.js";
export { formatResolvedUnresolvedNote } from "./resolution-notes.js";
export { runPluginCommandWithTimeout } from "./run-command.js";

View File

@@ -91,7 +91,10 @@ export {
resolveDmGroupAccessWithLists,
resolveEffectiveAllowFromLists,
} from "../security/dm-policy-shared.js";
export { evaluateSenderGroupAccessForPolicy } from "./group-access.js";
export {
evaluateSenderGroupAccessForPolicy,
resolveSenderScopedGroupPolicy,
} from "./group-access.js";
export { formatDocsLink } from "../terminal/links.js";
export { sleep } from "../utils.js";
export { loadWebMedia } from "../web/media.js";