mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix: restore Telegram release isolation checks (#122843)
* fix(release): repair isolated Telegram QA runtime sticky runner/SUT suite root permits config locks without config replacement; add PS1 after attested env verification for nested login shells. * test(node-host): own desktop teardown resets
This commit is contained in:
committed by
GitHub
parent
bb5ef9872a
commit
be600d0a24
@@ -1520,10 +1520,14 @@ jobs:
|
||||
export XDG_CONFIG_HOME="${temp_root}/xdg-config"
|
||||
export XDG_DATA_HOME="${temp_root}/xdg-data"
|
||||
|
||||
chown "$RUNNER_UID:$RUNNER_GID" "$temp_root"
|
||||
chmod 0711 "$temp_root"
|
||||
# The SUT must create config lock/temp entries beside the runner-owned
|
||||
# config. Sticky group-write prevents it from replacing that config.
|
||||
chown "$RUNNER_UID:$SUT_GID" "$temp_root"
|
||||
chmod 1770 "$temp_root"
|
||||
chown "$RUNNER_UID:$SUT_GID" "$config_path"
|
||||
chmod 0640 "$config_path"
|
||||
[[ "$(stat -c '%F:%a:%u:%g' "$temp_root")" == "directory:1770:${RUNNER_UID}:${SUT_GID}" ]]
|
||||
[[ "$(stat -c '%F:%a:%u:%g' "$config_path")" == "regular file:640:${RUNNER_UID}:${SUT_GID}" ]]
|
||||
sut_tmp="${temp_root}/sut-tmp"
|
||||
install -d -o "$SUT_UID" -g "$SUT_GID" -m 0700 "$sut_tmp"
|
||||
export TMPDIR="$sut_tmp"
|
||||
@@ -1834,14 +1838,18 @@ jobs:
|
||||
runtime_stage=write-sandbox-proof
|
||||
printf "%s" "$runtime_sandbox_payload_b64" | base64 -d >&3
|
||||
exec 3>&-
|
||||
runtime_stage=exec-runtime
|
||||
exec "$runtime_node_bin" \
|
||||
--import "$runtime_preload_path" \
|
||||
"$runtime_candidate_root/dist/index.js" \
|
||||
"$@"
|
||||
runtime_node_args=(
|
||||
--import "$runtime_preload_path"
|
||||
"$runtime_candidate_root/dist/index.js" "$@"
|
||||
)
|
||||
else
|
||||
runtime_node_args=("$runtime_candidate_root/dist/index.js" "$@")
|
||||
fi
|
||||
# Login Bash reads /etc/bash.bashrc with inherited nounset.
|
||||
# Add PS1 only after the attested inbound env-key comparison.
|
||||
export PS1=
|
||||
runtime_stage=exec-runtime
|
||||
exec "$runtime_node_bin" "$runtime_candidate_root/dist/index.js" "$@"
|
||||
exec "$runtime_node_bin" "${runtime_node_args[@]}"
|
||||
'\'' openclaw-sut "$@"
|
||||
' openclaw-sut "$@"
|
||||
LAUNCHER
|
||||
|
||||
@@ -13,6 +13,12 @@ import { createDesktopSessionRegistry } from "./session-registry.js";
|
||||
const VERSION = Buffer.from("RFB 003.008\n", "ascii");
|
||||
const cleanups: Array<() => Promise<void>> = [];
|
||||
|
||||
function handleExpectedPeerTeardownError(error: NodeJS.ErrnoException): void {
|
||||
if (error.code !== "ECONNRESET" && error.code !== "EPIPE") {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(cleanups.splice(0).map((cleanup) => cleanup()));
|
||||
});
|
||||
@@ -86,6 +92,8 @@ describe("paired node desktop observe integration", () => {
|
||||
const rfbServer = net.createServer((socket) => {
|
||||
rfbPeers.add(socket);
|
||||
socket.once("close", () => rfbPeers.delete(socket));
|
||||
// Session teardown destroys client sockets; the synthetic server owns the matching resets.
|
||||
socket.on("error", handleExpectedPeerTeardownError);
|
||||
connectionCount += 1;
|
||||
const connectionIndex = connectionCount;
|
||||
const reader = new SocketReader(socket);
|
||||
|
||||
@@ -7,6 +7,12 @@ import { invokeNodeDesktopStream } from "./desktop-stream-command.js";
|
||||
const TICKET = "a".repeat(48);
|
||||
const cleanups: Array<() => Promise<void>> = [];
|
||||
|
||||
function handleExpectedPeerTeardownError(error: NodeJS.ErrnoException): void {
|
||||
if (error.code !== "ECONNRESET" && error.code !== "EPIPE") {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(cleanups.splice(0).map((cleanup) => cleanup()));
|
||||
});
|
||||
@@ -46,6 +52,8 @@ describe("node desktop stream command", () => {
|
||||
const rfbServer = net.createServer((socket) => {
|
||||
rfbPeers.add(socket);
|
||||
socket.once("close", () => rfbPeers.delete(socket));
|
||||
// Cancellation destroys the client socket; the synthetic server owns the matching reset.
|
||||
socket.on("error", handleExpectedPeerTeardownError);
|
||||
socket.write(Buffer.from("RFB 003.008\n", "ascii"));
|
||||
socket.once("data", () => socket.write(Buffer.from([1, 2])));
|
||||
});
|
||||
|
||||
@@ -853,4 +853,42 @@ describe("release Telegram QA workflow", () => {
|
||||
'for path in \\\n "$temp_root/workspace" \\\n "${OPENCLAW_HOME:?}"',
|
||||
);
|
||||
});
|
||||
|
||||
it("lets the SUT create suite locks without exposing the runner-owned config", () => {
|
||||
const createSut = requireRun(
|
||||
"run_telegram",
|
||||
"Create isolated Telegram SUT identity and launcher",
|
||||
);
|
||||
|
||||
expect(createSut).toContain('chown "$RUNNER_UID:$SUT_GID" "$temp_root"');
|
||||
expect(createSut).toContain('chmod 1770 "$temp_root"');
|
||||
expect(createSut).toContain(
|
||||
'"$(stat -c \'%F:%a:%u:%g\' "$temp_root")" == "directory:1770:${RUNNER_UID}:${SUT_GID}"',
|
||||
);
|
||||
expect(createSut).toContain('chown "$RUNNER_UID:$SUT_GID" "$config_path"');
|
||||
expect(createSut).toContain('chmod 0640 "$config_path"');
|
||||
expect(createSut).toContain(
|
||||
'"$(stat -c \'%F:%a:%u:%g\' "$config_path")" == "regular file:640:${RUNNER_UID}:${SUT_GID}"',
|
||||
);
|
||||
expect(createSut).not.toContain('chmod 0711 "$temp_root"');
|
||||
expect(createSut).not.toContain('chmod 1777 "$temp_root"');
|
||||
});
|
||||
|
||||
it("adds an empty PS1 only after attested runtime environment verification", () => {
|
||||
const createSut = requireRun(
|
||||
"run_telegram",
|
||||
"Create isolated Telegram SUT identity and launcher",
|
||||
);
|
||||
const launcher = extractHereDocument(createSut, "LAUNCHER");
|
||||
const verification = '[[ "$actual_env_keys_b64" == "$runtime_expected_env_keys_b64" ]]';
|
||||
const ps1Export = "export PS1=";
|
||||
const candidateExec = 'exec "$runtime_node_bin" "${runtime_node_args[@]}"';
|
||||
|
||||
expect(launcher.match(/export PS1=/gu)).toHaveLength(1);
|
||||
expect(launcher.indexOf(verification)).toBeGreaterThan(-1);
|
||||
expect(launcher.indexOf(ps1Export)).toBeGreaterThan(launcher.indexOf(verification));
|
||||
expect(launcher.indexOf(candidateExec)).toBeGreaterThan(launcher.indexOf(ps1Export));
|
||||
expect(launcher.match(/exec "\$runtime_node_bin"/gu)).toHaveLength(1);
|
||||
expect(launcher).toContain('grep -Ev "^(PWD|SHLVL|_)$"');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user