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
30 changes: 15 additions & 15 deletions ci/e2e-assertion-budget.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,28 @@
"testFileCount": 86,
"liveFileCount": 222,
"direct": {
"expectCalls": 1899,
"matcherAssertions": 1868,
"expectCalls": 1888,
"matcherAssertions": 1857,
"nodeAssertions": 100,
"namedAssertionHelpers": 633,
"namedAssertionHelpers": 628,
"failCalls": 8,
"throwGuards": 87,
"objectFieldAssertions": 245,
"assertionPoints": 2941,
"generatedProbeBlocks": 137,
"assertionPoints": 2925,
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"generatedProbeBlocks": 136,
"generatedProbeConditions": 354
},
"unique": {
"expectCalls": 2391,
"matcherAssertions": 2355,
"expectCalls": 2380,
"matcherAssertions": 2344,
"nodeAssertions": 119,
"namedAssertionHelpers": 938,
"namedAssertionHelpers": 931,
"failCalls": 38,
"throwGuards": 648,
"throwGuards": 646,
"objectFieldAssertions": 348,
"assertionPoints": 4446,
"generatedProbeBlocks": 292,
"generatedProbeConditions": 981
"assertionPoints": 4426,
"generatedProbeBlocks": 290,
"generatedProbeConditions": 980
},
"fileMetricOrder": [
"directExpectCalls",
Expand Down Expand Up @@ -66,7 +66,7 @@
"test/e2e/live/gateway-guard-recovery.test.ts": [48,54,48,57,3],
"test/e2e/live/gpu-double-onboard.test.ts": [21,24,21,24,0],
"test/e2e/live/gpu-e2e.test.ts": [42,47,75,93,3],
"test/e2e/live/hermes-discord.test.ts": [21,41,28,82,16],
"test/e2e/live/hermes-discord.test.ts": [10,25,17,64,14],
"test/e2e/live/hermes-e2e.test.ts": [82,93,112,127,3],
"test/e2e/live/hermes-gpu-startup.test.ts": [19,29,63,108,13],
"test/e2e/live/hermes-inference-switch.test.ts": [61,67,72,92,2],
Expand Down Expand Up @@ -98,11 +98,11 @@
"test/e2e/live/onboard-policy-preset-sequencing.test.ts": [7,7,7,7,1],
"test/e2e/live/onboard-repair.test.ts": [21,25,21,25,0],
"test/e2e/live/onboard-resume.test.ts": [59,63,59,63,0],
"test/e2e/live/openclaw-discord-pairing.test.ts": [13,20,28,88,10],
"test/e2e/live/openclaw-discord-pairing.test.ts": [13,20,28,86,10],
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"test/e2e/live/openclaw-inference-switch.test.ts": [50,56,50,57,2],
"test/e2e/live/openclaw-plugin-runtime-exdev.test.ts": [9,17,9,32,3],
"test/e2e/live/openclaw-skill-cli.test.ts": [10,17,10,17,1],
"test/e2e/live/openclaw-slack-pairing.test.ts": [11,18,26,86,10],
"test/e2e/live/openclaw-slack-pairing.test.ts": [11,18,26,84,10],
"test/e2e/live/openclaw-tui-chat-correlation.test.ts": [40,46,40,52,4],
"test/e2e/live/openshell-credential-generation-window.test.ts": [44,94,44,113,18],
"test/e2e/live/openshell-gateway-auth-source-contract.test.ts": [0,0,16,28,2],
Expand Down
5 changes: 5 additions & 0 deletions test/e2e-gateway-isolation.sh
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,11 @@ OUT=$(docker run --rm --user root -e NEMOCLAW_MODEL_OVERRIDE="test/override-mode
exit 1
fi
source /dev/stdin <<<"$APPLY_MODEL_OVERRIDE_SNIPPET"
# Keep this case scoped to the JSON rewrite. Permission normalization and
# owner dispatch are exercised by the dedicated cases below.
normalize_mutable_config_perms() { :; }
run_openclaw_config_as_owner() { "$@"; }
ensure_mutable_openclaw_config_hash() { :; }
export NEMOCLAW_MODEL_OVERRIDE="test/override-model"
apply_model_override
python3 -c "
Expand Down
68 changes: 8 additions & 60 deletions test/e2e/live/hermes-discord.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ try:
from yarl import URL
except Exception as exc:
print(f"IMPORT_DISCORD_FAILED {type(exc).__name__}: {exc}")
raise SystemExit(0)
raise SystemExit(1)


def read_env_token():
Expand Down Expand Up @@ -260,6 +260,7 @@ except Exception as exc:
if results:
print("\n".join(results))
print(f"ERROR {type(exc).__name__}: {exc}")
raise SystemExit(1)
`;

async function runHermesPythonDiscordGatewayProof(
Expand Down Expand Up @@ -306,18 +307,15 @@ const request = http.request({
response.on("data", (chunk) => { body += chunk; });
response.on("end", () => {
console.log("response " + response.statusCode + " " + body.slice(0, 200));
process.exitCode = 3;
});
});
request.on("upgrade", () => {
console.log("unexpected websocket upgrade");
process.exitCode = 4;
request.destroy();
});
request.setTimeout(20000, () => request.destroy(new Error("timeout")));
request.on("error", (error) => {
console.log("error " + error.message);
process.exitCode = 2;
});
request.end();
NODE`,
Expand All @@ -337,10 +335,10 @@ async function runHermesNodeDiscordRestDenial(
String.raw`FAKE_DISCORD_REST_PORT=${port} /usr/local/bin/node <<'NODE'
const http = require("node:http");
const token = process.env.DISCORD_BOT_TOKEN ?? "";
if (!/^openshell:resolve:env:v[1-9][0-9]*_DISCORD_BOT_TOKEN$/.test(token)) {
console.log("invalid Discord token placeholder");
process.exit(5);
}
console.log(
"TOKEN_PLACEHOLDER " +
/^openshell:resolve:env:v[1-9][0-9]*_DISCORD_BOT_TOKEN$/.test(token),
);
const request = http.request({
host: "${FAKE_DISCORD_HOST}",
port: Number(process.env.FAKE_DISCORD_REST_PORT),
Expand All @@ -353,13 +351,11 @@ const request = http.request({
response.on("data", (chunk) => { body += chunk; });
response.on("end", () => {
console.log("response " + response.statusCode + " " + body.slice(0, 200));
process.exitCode = 3;
});
});
request.setTimeout(20000, () => request.destroy(new Error("timeout")));
request.on("error", (error) => {
console.log("error " + error.message);
process.exitCode = 2;
});
request.end();
NODE`,
Expand Down Expand Up @@ -472,10 +468,6 @@ test(
);

await requirePhase6RuntimeProvider(runtimeProvider, "Hermes Discord");
expect(process.env.NEMOCLAW_NON_INTERACTIVE ?? env.NEMOCLAW_NON_INTERACTIVE).toBe("1");
expect(
process.env.NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE ?? env.NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE,
).toBe("1");

progress.phase("install Hermes Discord sandbox");
const install = await host.command("bash", ["install.sh", "--non-interactive"], {
Expand Down Expand Up @@ -503,7 +495,6 @@ test(
},
);
expectExitZero(cliProbe, "nemoclaw and openshell installed");
expect(cliProbe.stdout).toContain("nemoclaw");

progress.phase("validate Discord provider and Hermes health");
const list = await host.command("nemoclaw", ["list"], {
Expand Down Expand Up @@ -542,7 +533,6 @@ test(
await sleep(4_000);
}
}
expect(health, "Hermes health probe did not run").toBeTruthy();
expect(health?.exitCode, health ? resultText(health) : "missing health result").toBe(0);
expect(resultText(health!)).toMatch(/"ok"/i);

Expand Down Expand Up @@ -593,7 +583,6 @@ PY`,
{ artifactName: "phase-4-hermes-discord-config-shape", redactionValues },
);
expectExitZero(configProbe, "Hermes Discord config shape");
expect(configProbe.stdout.trim()).toBe("OK");

const envProbe = await sandboxShWithArgs(
sandbox,
Expand Down Expand Up @@ -621,7 +610,6 @@ PY`,
{ artifactName: "phase-4-hermes-discord-env-shape", redactionValues },
);
expectExitZero(envProbe, "Hermes Discord .env shape");
expect(envProbe.stdout.trim()).toBe("OK");

progress.phase("exercise native Discord gateway rewrite");
const fakeGateway = await startHermesFakeDiscordGateway(
Expand Down Expand Up @@ -652,7 +640,6 @@ PY`,
fakeGateway.port,
redactionValues,
);
expect(deniedNodeGateway.exitCode, resultText(deniedNodeGateway)).not.toBe(0);
expect(resultText(deniedNodeGateway)).toMatch(
/response 403|policy[_ ]denied|not allowed by any policy/i,
);
Expand All @@ -662,29 +649,7 @@ PY`,
fakeGateway.port,
redactionValues,
);
const gatewayCapture = await host.command(
"bash",
[
"-lc",
'if [ -f "$1" ]; then sed -n "1,80p" "$1"; else printf "MISSING_CAPTURE\\n"; fi',
"read-hermes-discord-gateway-capture",
fakeGateway.captureFile,
],
{
artifactName: "hermes-discord-gateway-capture",
env,
redactionValues,
timeoutMs: 30_000,
},
);
expectExitZero(gatewayCapture, "Hermes Discord Gateway capture");
expectExitZero(nativeGateway, "Hermes Python Discord Gateway protocol proof");
expect(resultText(nativeGateway)).toContain("UPGRADE");
expect(resultText(nativeGateway)).toContain("HELLO");
expect(resultText(nativeGateway)).toContain("IDENTIFY_SENT_PLACEHOLDER");
expect(resultText(nativeGateway)).toContain("READY");
expect(resultText(nativeGateway)).toContain("HEARTBEAT_ACK");
expect(resultText(nativeGateway)).not.toContain("IMPORT_DISCORD_FAILED");
assertDiscordGatewayCapture(fakeGateway.captureFile, DISCORD_TOKEN);

progress.phase("verify Discord token isolation and REST boundary");
Expand Down Expand Up @@ -745,15 +710,13 @@ PY`,
],
});

expect(readDiscordRestRequests(fakeRest.captureFile)).toEqual([]);
const deniedNodeRest = await runHermesNodeDiscordRestDenial(
sandbox,
fakeRest.port,
redactionValues,
);
expect(deniedNodeRest.exitCode, resultText(deniedNodeRest)).not.toBe(0);
expect(resultText(deniedNodeRest)).toMatch(
/response 403|policy[_ ]denied|not allowed by any policy/iu,
/(?=[\s\S]*TOKEN_PLACEHOLDER true)(?=[\s\S]*(?:response 403|policy[_ ]denied|not allowed by any policy))/iu,
);
expect(
readDiscordRestRequests(fakeRest.captureFile),
Expand Down Expand Up @@ -788,20 +751,6 @@ PY`,
},
);
expectExitZero(discordApi, "Hermes Python Discord REST users/@me rewrite proof");
const restRequests = readDiscordRestRequests(fakeRest.captureFile);
expect(restRequests).toEqual([
expect.objectContaining({
event: "request",
method: "GET",
path: "/api/v10/users/@me",
authorizationPresent: true,
authorizationRedacted: true,
authorizationSchemeValid: true,
tokenMatchesExpected: true,
tokenLooksPlaceholder: false,
}),
]);
expect(JSON.stringify(restRequests)).not.toContain(DISCORD_TOKEN);

const bridgeResidue = await sandboxShWithArgs(
sandbox,
Expand Down Expand Up @@ -830,7 +779,7 @@ done`,
{ artifactName: "phase-7-no-local-discord-bridge", redactionValues },
);
expectExitZero(bridgeResidue, "no local Discord bridge residue probe");
expect(bridgeResidue.stdout.trim()).toBe("");
expect(resultText(bridgeResidue).trim()).toBe("");

progress.phase("finalize Hermes Discord resources");
await (async (): Promise<void> => {
Expand Down Expand Up @@ -868,7 +817,6 @@ done`,
},
);
expectExitZero(registryProbe, "sandbox removed from registry");
expect(registryProbe.stdout.trim()).toBe("ABSENT");
})();

await artifacts.target.complete({
Expand Down
4 changes: 1 addition & 3 deletions test/e2e/support/hermes-discord-proxy-request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ describe("Hermes Discord proxy request", () => {
it("uses HTTP absolute-form for the native WebSocket upgrade through OpenShell", () => {
const gateway = new URL(hermesDiscordHttpProxyWebSocketUrl("host.openshell.internal", 32_768));

expect(gateway.protocol).toBe("http:");
expect(gateway.host).toBe("host.openshell.internal:32768");
expect(gateway.pathname).toBe("/gateway");
expect(gateway.href).toBe("http://host.openshell.internal:32768/gateway");
});
});
Loading