diff --git a/test/e2e/test-messaging-providers.sh b/test/e2e/test-messaging-providers.sh index b3a22f2354f..9b76aa242b7 100755 --- a/test/e2e/test-messaging-providers.sh +++ b/test/e2e/test-messaging-providers.sh @@ -1733,6 +1733,49 @@ print(','.join(bad)) fail "M-WA9: WhatsApp config contains secret-like fields: ${whatsapp_secret_fields}" fi + # M-W7: WeChat plugin install registry is restored alongside the channel + # block, the plugin entry is enabled, and the install spec is pinned to a + # concrete semver. The upstream plugin loader needs this install metadata + # after OpenClaw config rewrites (plugins.entries alone is not enough), + # and a floating spec (e.g. "@latest") would silently bypass the + # installer-trust pinning enforced in Dockerfile.base and + # scripts/seed-wechat-accounts.py (WECHAT_PLUGIN_SPEC=@2.4.3). + wechat_plugins_json=$(sandbox_exec "python3 -c \" +import json +cfg = json.load(open('/sandbox/.openclaw/openclaw.json')) +plugins = cfg.get('plugins', {}) or {} +print(json.dumps({ + 'install': plugins.get('installs', {}).get('openclaw-weixin', {}), + 'entry': plugins.get('entries', {}).get('openclaw-weixin', {}), +})) +\"" 2>/dev/null || true) + if echo "$wechat_plugins_json" | python3 -c " +import json, re, sys +try: + data = json.load(sys.stdin) +except Exception: + sys.exit(2) +inst = data.get(\"install\") if isinstance(data, dict) else None +entry = data.get(\"entry\") if isinstance(data, dict) else None +spec = inst.get(\"spec\") if isinstance(inst, dict) else None +install_path = inst.get(\"installPath\") if isinstance(inst, dict) else None +ok = ( + isinstance(inst, dict) + and inst.get(\"source\") == \"npm\" + and isinstance(spec, str) + and bool(re.fullmatch(r\"@tencent-weixin/openclaw-weixin@\d+\.\d+\.\d+\", spec)) + and isinstance(install_path, str) + and bool(install_path.strip()) + and isinstance(entry, dict) + and entry.get(\"enabled\") is True +) +sys.exit(0 if ok else 1) +" 2>/dev/null; then + pass "M-W7: WeChat plugin install registry restored, entry enabled, spec pinned in openclaw.json" + else + fail "M-W7: WeChat plugin install registry missing/invalid, entry not enabled, or spec not pinned to a concrete semver" + fi + # M-W8: WeChat channel registered under channels.openclaw-weixin with the # configured accountId enabled. Written by seed-wechat-accounts.py during # image build using NEMOCLAW_WECHAT_CONFIG_B64. Absence here means @@ -1748,7 +1791,7 @@ print(account.get('enabled', False)) if [ "$wechat_enabled" = "True" ]; then pass "M-W8: WeChat account '$WECHAT_ACCOUNT' is enabled in openclaw.json (channels.openclaw-weixin)" else - skip "M-W8: WeChat account not enabled in openclaw.json (expected in non-root sandbox or seed-wechat-accounts.py was skipped)" + fail "M-W8: WeChat account not enabled in openclaw.json (channels.openclaw-weixin missing or disabled)" fi fi @@ -1759,7 +1802,7 @@ fi # would mean someone bypassed the placeholder constant. wechat_account_json=$(sandbox_exec "cat /sandbox/.openclaw/openclaw-weixin/accounts/${WECHAT_ACCOUNT}.json 2>/dev/null || true" 2>/dev/null || true) if [ -z "$wechat_account_json" ] || echo "$wechat_account_json" | grep -qi "no such file"; then - skip "M-W9: WeChat per-account credential file not found (seed-wechat-accounts.py may have been skipped)" + fail "M-W9: WeChat per-account credential file not found (seed-wechat-accounts.py may have been skipped)" else if echo "$wechat_account_json" | grep -qF "$WECHAT_TOKEN"; then fail "M-W9: Real WeChat token spliced into accounts/${WECHAT_ACCOUNT}.json — seed-wechat-accounts.py placeholder regression" @@ -1775,7 +1818,7 @@ fi # auth/accounts.ts boots accounts that appear in this index. wechat_index_json=$(sandbox_exec "cat /sandbox/.openclaw/openclaw-weixin/accounts.json 2>/dev/null || true" 2>/dev/null || true) if [ -z "$wechat_index_json" ] || echo "$wechat_index_json" | grep -qi "no such file"; then - skip "M-W10: WeChat accounts.json index not found" + fail "M-W10: WeChat accounts.json index not found" else if echo "$wechat_index_json" | python3 -c " import json, sys