
























@@ -10,6 +10,7 @@ RUN_CHANNEL_SCENARIOS="${OPENCLAW_BUNDLED_CHANNEL_SCENARIOS:-1}"
1010RUN_UPDATE_SCENARIO="${OPENCLAW_BUNDLED_CHANNEL_UPDATE_SCENARIO:-1}"
1111RUN_ROOT_OWNED_SCENARIO="${OPENCLAW_BUNDLED_CHANNEL_ROOT_OWNED_SCENARIO:-1}"
1212RUN_SETUP_ENTRY_SCENARIO="${OPENCLAW_BUNDLED_CHANNEL_SETUP_ENTRY_SCENARIO:-1}"
13+RUN_LOAD_FAILURE_SCENARIO="${OPENCLAW_BUNDLED_CHANNEL_LOAD_FAILURE_SCENARIO:-1}"
13141415echo "Building Docker image..."
1516run_logged bundled-channel-deps-build docker build -t "$IMAGE_NAME" -f "$ROOT_DIR/scripts/e2e/Dockerfile" "$ROOT_DIR"
@@ -1001,6 +1002,167 @@ EOF
10011002 rm -f "$run_log"
10021003}
100310041005+run_load_failure_scenario() {
1006+local run_log
1007+ run_log="$(mktemp "${TMPDIR:-/tmp}/openclaw-bundled-channel-load-failure.XXXXXX")"
1008+1009+echo "Running bundled channel load-failure isolation Docker E2E..."
1010+if ! docker run --rm \
1011+ -e COREPACK_ENABLE_DOWNLOAD_PROMPT=0 \
1012+ -i "$IMAGE_NAME" bash -s >"$run_log" 2>&1 <<'EOF'
1013+set -euo pipefail
1014+1015+export HOME="$(mktemp -d "/tmp/openclaw-bundled-channel-load-failure.XXXXXX")"
1016+export NPM_CONFIG_PREFIX="$HOME/.npm-global"
1017+export PATH="$NPM_CONFIG_PREFIX/bin:$PATH"
1018+export OPENCLAW_NO_ONBOARD=1
1019+1020+package_root() {
1021+ printf "%s/openclaw" "$(npm root -g)"
1022+}
1023+1024+echo "Packing and installing current OpenClaw build..."
1025+pack_dir="$(mktemp -d "/tmp/openclaw-load-failure-pack.XXXXXX")"
1026+npm pack --ignore-scripts --pack-destination "$pack_dir" >/tmp/openclaw-load-failure-pack.log 2>&1
1027+package_tgz="$(find "$pack_dir" -maxdepth 1 -name 'openclaw-*.tgz' -print -quit)"
1028+if [ -z "$package_tgz" ]; then
1029+ cat /tmp/openclaw-load-failure-pack.log
1030+ echo "missing packed OpenClaw tarball" >&2
1031+ exit 1
1032+fi
1033+npm install -g "$package_tgz" --no-fund --no-audit >/tmp/openclaw-load-failure-install.log 2>&1
1034+1035+root="$(package_root)"
1036+plugin_dir="$root/dist/extensions/load-failure-alpha"
1037+mkdir -p "$plugin_dir"
1038+cat >"$plugin_dir/package.json" <<'JSON'
1039+{
1040+ "name": "@openclaw/load-failure-alpha",
1041+ "version": "2026.4.21",
1042+ "private": true,
1043+ "type": "module",
1044+ "openclaw": {
1045+ "extensions": ["./index.js"],
1046+ "setupEntry": "./setup-entry.js"
1047+ }
1048+}
1049+JSON
1050+cat >"$plugin_dir/openclaw.plugin.json" <<'JSON'
1051+{
1052+ "id": "load-failure-alpha",
1053+ "channels": ["load-failure-alpha"],
1054+ "configSchema": {
1055+ "type": "object",
1056+ "additionalProperties": false,
1057+ "properties": {}
1058+ }
1059+}
1060+JSON
1061+cat >"$plugin_dir/index.js" <<'JS'
1062+export default {
1063+ kind: "bundled-channel-entry",
1064+ id: "load-failure-alpha",
1065+ name: "Load Failure Alpha",
1066+ description: "Load Failure Alpha",
1067+ register() {},
1068+ loadChannelSecrets() {
1069+ globalThis.__loadFailureSecrets = (globalThis.__loadFailureSecrets ?? 0) + 1;
1070+ throw new Error("synthetic channel secrets failure");
1071+ },
1072+ loadChannelPlugin() {
1073+ globalThis.__loadFailurePlugin = (globalThis.__loadFailurePlugin ?? 0) + 1;
1074+ throw new Error("synthetic channel plugin failure");
1075+ }
1076+};
1077+JS
1078+cat >"$plugin_dir/setup-entry.js" <<'JS'
1079+export default {
1080+ kind: "bundled-channel-setup-entry",
1081+ loadSetupSecrets() {
1082+ globalThis.__loadFailureSetupSecrets = (globalThis.__loadFailureSetupSecrets ?? 0) + 1;
1083+ throw new Error("synthetic setup secrets failure");
1084+ },
1085+ loadSetupPlugin() {
1086+ globalThis.__loadFailureSetup = (globalThis.__loadFailureSetup ?? 0) + 1;
1087+ throw new Error("synthetic setup plugin failure");
1088+ }
1089+};
1090+JS
1091+1092+echo "Loading synthetic failing bundled channel through packaged loader..."
1093+(
1094+ cd "$root"
1095+ OPENCLAW_BUNDLED_PLUGINS_DIR="$root/dist/extensions" node --input-type=module - <<'NODE'
1096+import fs from "node:fs";
1097+import path from "node:path";
1098+import { pathToFileURL } from "node:url";
1099+1100+const root = process.cwd();
1101+const distDir = path.join(root, "dist");
1102+const bundledPath = fs
1103+ .readdirSync(distDir)
1104+ .filter((entry) => /^bundled-[A-Za-z0-9_-]+\.js$/.test(entry))
1105+ .map((entry) => path.join(distDir, entry))
1106+ .find((entry) => fs.readFileSync(entry, "utf8").includes("src/channels/plugins/bundled.ts"));
1107+if (!bundledPath) {
1108+ throw new Error("missing packaged bundled channel loader artifact");
1109+}
1110+const bundled = await import(pathToFileURL(bundledPath));
1111+const oneArgExports = Object.entries(bundled).filter(
1112+ ([, value]) => typeof value === "function" && value.length === 1,
1113+);
1114+if (oneArgExports.length === 0) {
1115+ throw new Error(`missing one-argument bundled loader exports; exports=${Object.keys(bundled).join(",")}`);
1116+}
1117+1118+const id = "load-failure-alpha";
1119+for (let i = 0; i < 2; i += 1) {
1120+ for (const [name, fn] of oneArgExports) {
1121+ try {
1122+ fn(id);
1123+ } catch (error) {
1124+ const message = error instanceof Error ? error.message : String(error);
1125+ if (message.includes("synthetic")) {
1126+ throw new Error(`bundled export ${name} leaked synthetic load failure: ${message}`);
1127+ }
1128+ }
1129+ }
1130+}
1131+1132+const counts = {
1133+ plugin: globalThis.__loadFailurePlugin,
1134+ setup: globalThis.__loadFailureSetup,
1135+ secrets: globalThis.__loadFailureSecrets,
1136+ setupSecrets: globalThis.__loadFailureSetupSecrets,
1137+};
1138+for (const [key, value] of Object.entries({
1139+ plugin: counts.plugin,
1140+ setup: counts.setup,
1141+ setupSecrets: counts.setupSecrets,
1142+})) {
1143+ if (value !== 1) {
1144+ throw new Error(`expected ${key} failure to be cached after one load, got ${value}`);
1145+ }
1146+}
1147+if (counts.secrets !== undefined && counts.secrets !== 1) {
1148+ throw new Error(`expected secrets failure to be cached after one load when exercised, got ${counts.secrets}`);
1149+}
1150+console.log("synthetic bundled channel load failures were isolated and cached");
1151+NODE
1152+)
1153+1154+echo "bundled channel load-failure isolation Docker E2E passed"
1155+EOF
1156+then
1157+ cat "$run_log"
1158+ rm -f "$run_log"
1159+exit 1
1160+fi
1161+1162+ cat "$run_log"
1163+ rm -f "$run_log"
1164+}
1165+10041166if [ "$RUN_CHANNEL_SCENARIOS" != "0" ]; then
10051167 run_channel_scenario telegram grammy
10061168 run_channel_scenario discord discord-api-types
@@ -1017,3 +1179,6 @@ fi
10171179if [ "$RUN_SETUP_ENTRY_SCENARIO" != "0" ]; then
10181180 run_setup_entry_scenario
10191181fi
1182+if [ "$RUN_LOAD_FAILURE_SCENARIO" != "0" ]; then
1183+ run_load_failure_scenario
1184+fi
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。