Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions scripts/generate-openclaw-config.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ def _placeholder(channel: str, env_key: str) -> str:
channel_id: dict(slack_channel_config)
for channel_id in _slack_allowed_channels
}
_ch_cfg[ch] = {"accounts": {"default": account}}
_ch_cfg[ch] = {**({"enabled": True} if ch == "slack" else {}), "accounts": {"default": account}}

# WeChat (openclaw-weixin) is NOT added to channels.* here in build
# contexts where the plugin has not been installed yet — writing it upfront
Expand All @@ -630,7 +630,6 @@ def _placeholder(channel: str, env_key: str) -> str:
# framework allowFrom file at credentials/openclaw-weixin-{accountId}-
# allowFrom.json — not the openclaw.json accounts.<id>.allowFrom mechanism
# that telegram/discord/slack use.

if "discord" in _ch_cfg and _discord_guilds:
_ch_cfg["discord"].update(
{"groupPolicy": "allowlist", "guilds": _discord_guilds}
Expand Down Expand Up @@ -717,6 +716,7 @@ def _placeholder(channel: str, env_key: str) -> str:
# registered an accountId under channels.openclaw-weixin.accounts.
"openclaw-weixin": {"enabled": True},
}
plugin_entries.update({"slack": {"enabled": True}} if "slack" in _ch_cfg else {})
_bundled_provider_plugins = {
"amazon-bedrock": {"amazon-bedrock", "bedrock"},
"amazon-bedrock-mantle": {"amazon-bedrock-mantle"},
Expand Down
1 change: 1 addition & 0 deletions test/e2e-scenario/framework-tests/e2e-suite-runner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ describe("Issue #3810 messaging suite wiring", () => {
"telegram-injection-safety",
"discord-gateway-path",
"slack-provider-state",
"slack.runtime-discovery",
]) {
expect(output).toContain(id);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ ONBOARDING_PATH="$(read_plan_value dimensions.onboarding.profile.path)"
AGENT="$(read_plan_value dimensions.onboarding.profile.agent)"
PROVIDER="$(read_plan_value dimensions.onboarding.profile.provider)"
INFERENCE_ROUTE="$(read_plan_value dimensions.onboarding.profile.inference_route)"
MESSAGING_PROVIDER="$(read_plan_value dimensions.onboarding.profile.messaging)"

: "${PLATFORM_OS:=unknown}"
: "${EXECUTION_TARGET:=local}"
Expand All @@ -77,6 +78,9 @@ e2e_context_set E2E_ONBOARDING_PATH "${ONBOARDING_PATH}"
e2e_context_set E2E_AGENT "${AGENT}"
e2e_context_set E2E_PROVIDER "${PROVIDER}"
e2e_context_set E2E_INFERENCE_ROUTE "${INFERENCE_ROUTE}"
if [[ -n "${MESSAGING_PROVIDER}" ]]; then
e2e_context_set E2E_MESSAGING_PROVIDER "${MESSAGING_PROVIDER}"
fi

# Sandbox name and gateway URL are normally discovered/assigned by
# onboarding. Seed them here so dry-run consumers can exercise the suite
Expand Down
10 changes: 10 additions & 0 deletions test/e2e-scenario/validation_suites/lib/messaging_providers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,16 @@ e2e_messaging_read_config_surface() {
cat "${path}"
return 0
fi
local sandbox_name
sandbox_name="$(e2e_context_get E2E_SANDBOX_NAME)"
if [[ -n "${sandbox_name}" && "${path}" == /sandbox/* ]]; then
local remote
remote="$(timeout 30 openshell sandbox exec --name "${sandbox_name}" -- cat "${path}" 2>/dev/null || true)"
if [[ -n "${remote}" ]]; then
printf '%s\n' "${remote}"
return 0
fi
fi
e2e_fail "expected-state.messaging.config-surface missing config content/path for ${path}"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,43 @@ case "${provider}" in
*) e2e_fail "expected-state.messaging.slack.provider-state expected slack provider, got ${provider}" ;;
esac
e2e_messaging_assert_provider_attached
if [[ "$(e2e_context_get E2E_AGENT)" == "openclaw" ]]; then
if [[ -n "${E2E_DRY_RUN:-}" ]]; then
e2e_pass "expected-state.messaging.slack.openclaw-enabled dry-run"
e2e_pass "expected-state.messaging.slack.runtime-discovery dry-run"
else
content="$(e2e_messaging_read_config_surface)"
if ! printf '%s\n' "${content}" | python3 -c '
import json
import sys
cfg = json.load(sys.stdin)
assert cfg["channels"]["slack"]["enabled"] is True
assert cfg["plugins"]["entries"]["slack"]["enabled"] is True
'; then
e2e_fail "expected-state.messaging.slack.openclaw-enabled missing channels.slack.enabled or plugins.entries.slack.enabled"
fi
e2e_pass "expected-state.messaging.slack.openclaw-enabled channel and plugin enabled"

sandbox_name="$(e2e_context_get E2E_SANDBOX_NAME)"
runtime_json="$(openshell sandbox exec --name "${sandbox_name}" -- timeout 45 openclaw channels list --all --json --no-color 2>/dev/null || true)"
runtime_state="$(printf '%s\n' "${runtime_json}" | python3 -c '
import json
import sys
try:
data = json.load(sys.stdin)
slack = data.get("chat", {}).get("slack", {})
accounts = slack.get("accounts", [])
if slack.get("installed") is True and slack.get("origin") == "configured" and "default" in accounts:
print("yes")
else:
print("no installed=%s origin=%s accounts=%s" % (slack.get("installed"), slack.get("origin"), accounts))
except Exception as exc:
print("error %s" % exc)
' 2>/dev/null || true)"
if [[ "${runtime_state}" != "yes" ]]; then
e2e_fail "expected-state.messaging.slack.runtime-discovery OpenClaw did not report Slack installed/configured (${runtime_state}; output=${runtime_json:0:300})"
fi
e2e_pass "expected-state.messaging.slack.runtime-discovery OpenClaw reports Slack installed and configured"
fi
fi
e2e_pass "expected-state.messaging.slack.provider-state ${provider} provider state configured"
4 changes: 4 additions & 0 deletions test/generate-openclaw-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,8 @@ describe("generate-openclaw-config.py: config generation", () => {
it("emits Bolt-shape placeholders for Slack so the SDK's prefix regex passes", () => {
const channels = Buffer.from(JSON.stringify(["slack"])).toString("base64");
const config = runConfigScript({ NEMOCLAW_MESSAGING_CHANNELS_B64: channels });
expect(config.channels.slack.enabled).toBe(true);
expect(config.plugins.entries.slack).toEqual({ enabled: true });
const slack = config.channels.slack.accounts.default;
// Bolt validates ^xoxb-[A-Za-z0-9_-]+$ / ^xapp-…$ at App construction.
// OpenShell resolves these provider-shaped aliases at the egress boundary.
Expand All @@ -560,6 +562,8 @@ describe("generate-openclaw-config.py: config generation", () => {
});
const slack = config.channels.slack.accounts.default;

expect(config.channels.slack.enabled).toBe(true);
expect(config.plugins.entries.slack).toEqual({ enabled: true });
expect(slack.dmPolicy).toBe("allowlist");
expect(slack.allowFrom).toEqual(allowedUsers);
expect(slack.groupPolicy).toBe("allowlist");
Expand Down
Loading