fix(ci): bound Telegram Mantis proof cleanup (#115253)

* test(mantis): bound Telegram proof cleanup

* test(mantis): enforce cleanup deadline in wrapper

* test(mantis): supervise cleanup through bash
This commit is contained in:
Peter Steinberger
2026-07-28 11:44:28 -04:00
committed by GitHub
parent cbe19ed3be
commit 3224005c82
3 changed files with 50 additions and 1 deletions
@@ -556,6 +556,15 @@ jobs:
"$runtime_parent/attestations/$lane.json" >/dev/null
done
- name: Return proof artifacts to the runner
if: ${{ always() }}
shell: bash
run: |
set -euo pipefail
if [[ -d "$MANTIS_OUTPUT_DIR" ]]; then
sudo chown -R "$(id -u):$(id -g)" "$MANTIS_OUTPUT_DIR"
fi
- name: Inspect Mantis evidence manifest
id: inspect
if: ${{ always() }}
+22
View File
@@ -8,6 +8,7 @@ readonly runtime_root_file="/etc/openclaw-mantis-sut-runtime-root"
readonly docker_bin="/usr/bin/docker"
readonly flock_bin="/usr/bin/flock"
readonly iptables_bin="/usr/sbin/iptables"
readonly timeout_bin="/usr/bin/timeout"
readonly network_lock_file="/run/lock/openclaw-mantis-sut-network.lock"
readonly network_state_root="/run/openclaw-mantis-sut-networks"
@@ -16,6 +17,19 @@ die() {
exit 64
}
run_cleanup_with_deadline() {
local action="$1"
shift
# timeout owns a separate process group, so escalation reaches Docker and
# network-cleanup descendants instead of killing only the caller's sudo.
exec "$timeout_bin" --signal=TERM --kill-after=5s 30s /bin/bash "$0" "__${action}" "$@"
}
require_cleanup_timeout_parent() {
[[ "$(readlink -f "/proc/$PPID/exe")" == "$timeout_bin" ]] \
|| die "internal cleanup action requires the timeout supervisor"
}
require_container_name() {
[[ "$1" =~ ^openclaw-telegram-sut-[0-9a-f-]+$ ]] || die "invalid container name"
}
@@ -810,6 +824,10 @@ case "$command" in
exit "$run_result"
;;
stop)
run_cleanup_with_deadline stop "$@"
;;
__stop)
require_cleanup_timeout_parent
[[ $# -eq 2 ]] || die "stop expects a container name and runtime root"
require_container_name "$1"
runtime_source="$2"
@@ -823,6 +841,10 @@ case "$command" in
exit "$stop_result"
;;
destroy)
run_cleanup_with_deadline destroy "$@"
;;
__destroy)
require_cleanup_timeout_parent
[[ $# -eq 2 ]] || die "destroy expects a container name and runtime root"
require_container_name "$1"
runtime_source="$2"
@@ -148,6 +148,9 @@ describe("Mantis Telegram Desktop proof workflow", () => {
const inspectIndex = steps.findIndex(
(step) => step.name === "Inspect Mantis evidence manifest",
);
const returnArtifactsIndex = steps.findIndex(
(step) => step.name === "Return proof artifacts to the runner",
);
expect(codexStep.env?.OPENCLAW_QA_CREDENTIAL_OWNER_ID).toContain(
"mantis-telegram-desktop-${{ github.run_id }}-${{ github.run_attempt }}",
@@ -155,7 +158,8 @@ describe("Mantis Telegram Desktop proof workflow", () => {
expect(workflowStep("Prepare Codex user").run).toContain("OPENCLAW_QA_CREDENTIAL_OWNER_ID");
expect(cleanupIndex).toBeGreaterThan(steps.findIndex((step) => step.name === codexStep.name));
expect(cleanupIndex).toBeGreaterThanOrEqual(0);
expect(inspectIndex).toBeGreaterThan(cleanupIndex);
expect(returnArtifactsIndex).toBeGreaterThan(cleanupIndex);
expect(inspectIndex).toBeGreaterThan(returnArtifactsIndex);
const cleanupStep = workflowStep("Release leaked Telegram proof leases");
expect(cleanupStep.if).toBe("${{ always() }}");
@@ -185,6 +189,20 @@ describe("Mantis Telegram Desktop proof workflow", () => {
expect(cleanupStep.run).not.toContain("*/telegram-user-crabbox/*/.session/lease.json");
expect(cleanupStep.run).toContain('sudo -u codex "$MANTIS_NODE_BIN"');
expect(cleanupStep.run).not.toContain("sudo -u codex node");
const returnArtifactsStep = workflowStep("Return proof artifacts to the runner");
expect(returnArtifactsStep.if).toBe("${{ always() }}");
expect(returnArtifactsStep.run).toContain(
'sudo chown -R "$(id -u):$(id -g)" "$MANTIS_OUTPUT_DIR"',
);
const sutWrapper = readFileSync(SUT_CONTAINER_WRAPPER, "utf8");
expect(sutWrapper).toContain(
'exec "$timeout_bin" --signal=TERM --kill-after=5s 30s /bin/bash "$0" "__${action}" "$@"',
);
expect(sutWrapper).toContain('"$(readlink -f "/proc/$PPID/exe")" == "$timeout_bin"');
expect(sutWrapper).toContain("__stop)");
expect(sutWrapper).toContain("__destroy)");
});
it("cleans partially started proof daemons when local SUT startup fails", () => {