fix(slack): prevent Zod default groupPolicy from breaking multi-account config#17579
Conversation
Additional Comments (1)
The same pattern also appears in Prompt To Fix With AIThis is a comment left during a code review.
Path: src/config/zod-schema.providers-core.ts
Line: 275:275
Comment:
**Same bug exists in other providers.** `DiscordAccountSchema` still has `groupPolicy: GroupPolicySchema.optional().default("allowlist")` (line 275), and `DiscordConfigSchema` inherits it via `.extend()` without overriding. The merge in `mergeDiscordAccountConfig` (`{ ...base, ...account }`) will exhibit the same phantom-default override behavior described in this PR for Slack.
The same pattern also appears in `TelegramAccountSchemaBase` (line 108), `SignalAccountSchemaBase` (line 657), `IrcAccountSchemaBase` (line 745), `IMessageAccountSchemaBase` (line 805), and `BlueBubblesAccountSchemaBase` (line 897) — all have `.default("allowlist")` on the account schema, and all use the same `{ ...base, ...account }` shallow merge. Consider applying the same fix (move the default to the `*ConfigSchema` only) to these providers as well.
How can I resolve this? If you propose a fix, please make it concise. |
|
This pull request has been automatically marked as stale due to inactivity. |
|
Fixed all the CI issues. |
06d3436 to
f89f6da
Compare
…nt config
When `SlackAccountSchema` has `groupPolicy: GroupPolicySchema.optional().default("allowlist")`,
Zod injects `groupPolicy: "allowlist"` into every parsed account entry — even when the user
never specified it. `mergeSlackAccountConfig` then does `{ ...base, ...account }`, so the
account's phantom "allowlist" silently overrides the user's top-level "open". With
`groupPolicy: "allowlist"` active and no channels explicitly listed, ALL channel messages
are dropped by `isSlackChannelAllowedByPolicy`.
The fix moves `.default("allowlist")` from `SlackAccountSchema` to `SlackConfigSchema`,
so the default only applies to the top-level config — not to individual account entries
that get shallow-merged on top of it.
Fixes openclaw#17507
Related: openclaw#5626, openclaw#16522
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
f89f6da to
7d2da57
Compare
|
Merged via squash. Thanks @ZetiMente! |
…nt config (openclaw#17579) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 7d2da57 Co-authored-by: ZetiMente <76985631+ZetiMente@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
…nt config (openclaw#17579) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 7d2da57 Co-authored-by: ZetiMente <76985631+ZetiMente@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
…nt config (openclaw#17579) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 7d2da57 Co-authored-by: ZetiMente <76985631+ZetiMente@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
…nt config (openclaw#17579) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 7d2da57 Co-authored-by: ZetiMente <76985631+ZetiMente@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
…nt config (openclaw#17579) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 7d2da57 Co-authored-by: ZetiMente <76985631+ZetiMente@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
…nt config (openclaw#17579) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 7d2da57 Co-authored-by: ZetiMente <76985631+ZetiMente@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
…nt config (openclaw#17579) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 7d2da57 Co-authored-by: ZetiMente <76985631+ZetiMente@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
…nt config (openclaw#17579) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 7d2da57 Co-authored-by: ZetiMente <76985631+ZetiMente@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
…nt config (openclaw#17579) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 7d2da57 Co-authored-by: ZetiMente <76985631+ZetiMente@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
Summary
.default("allowlist")fromSlackAccountSchematoSlackConfigSchemaso Zod only injects the default at the top-level config, not into individual account entries.Root Cause
SlackAccountSchemahasgroupPolicy: GroupPolicySchema.optional().default("allowlist"). When Zod parses an account entry like{ botToken: "...", appToken: "..." }, it injectsgroupPolicy: "allowlist"into the output — even though the user never specified it.mergeSlackAccountConfigthen does{ ...base, ...account }, so the account's phantom"allowlist"overrides the user's top-levelgroupPolicy: "open". With"allowlist"active and no channels explicitly listed,isSlackChannelAllowedByPolicyreturnsfalsefor every channel message.This affects any config that uses the
channels.slack.accountsobject, even with a single account.The developer's intent was probably "default to secure" — which is reasonable. The mistake was putting that default on the account schema instead of the top-level schema. The right place for "default to secure if nobody says anything" is SlackConfigSchema, because that's the one that represents the user's actual top-level config. Individual account entries are meant to inherit from that, and Zod defaults break the inheritance by filling in keys that should have stayed undefined.
The Fix
Test Plan
pnpm test -- --grep slack)accountsobject) continues to work as beforeFixes #17507
Related: #5626, #16522
cc @thewilloftheshadow (Slack subsystem) @gumadeiras (multi-agent)
🤖 AI-assisted: This bug was diagnosed and fixed by Claude Opus 4.6 (Anthropic) in a live demo session with @ZetiMente. Fully tested on a live instance.
Greptile Summary
Fixes a bug where Zod's
.default("allowlist")onSlackAccountSchema.groupPolicycaused a phantom default to be injected into every parsed account entry, overriding the user's top-levelgroupPolicyduring the shallow merge ({ ...base, ...account }) inmergeSlackAccountConfig. This silently broke channel message delivery for multi-account Slack configs..default("allowlist")fromSlackAccountSchemaso account entries no longer get a phantomgroupPolicyinjected.default("allowlist")toSlackConfigSchemaviasafeExtendso the secure default still applies at the top-level config.default("allowlist")on their account schemas and use the same shallow merge, but were not addressed in this PRConfidence Score: 4/5
src/config/zod-schema.providers-core.ts(DiscordAccountSchema line 275, TelegramAccountSchemaBase line 108, SignalAccountSchemaBase line 657, IrcAccountSchemaBase line 745, IMessageAccountSchemaBase line 805, BlueBubblesAccountSchemaBase line 897) have the same latent bug.Last reviewed commit: fc243e3
(1/5) You can manually trigger the agent by mentioning @greptileai in a comment!