fix(ci): isolate bounded metadata retries (#108804)

* fix(ci): bound Mantis runner IP retries

* fix(e2e): isolate Windows metadata retries

* fix(ci): validate complete runner IPv4

Co-authored-by: Alix-007 <li.long15@xydigit.com>

---------

Co-authored-by: Alix-007 <li.long15@xydigit.com>
This commit is contained in:
Peter Steinberger
2026-07-16 03:39:31 -07:00
committed by GitHub
co-authored by Alix-007
parent d572c5cb2d
commit e0ffbd90d9
4 changed files with 137 additions and 6 deletions
@@ -266,8 +266,29 @@ jobs:
require_var OPENCLAW_QA_CONVEX_SECRET_CI
require_var CRABBOX_COORDINATOR_TOKEN
if [[ -z "${CRABBOX_LEASE_ID:-}" && "$CRABBOX_PROVIDER" == "aws" ]]; then
runner_ip="$(curl -fsS --connect-timeout 5 --max-time 15 --retry 2 https://checkip.amazonaws.com | tr -d '[:space:]')"
if [[ -z "$runner_ip" ]]; then
runner_ip=""
for attempt in 1 2 3; do
if runner_ip="$(curl -fsS --connect-timeout 5 --max-time 15 https://checkip.amazonaws.com | tr -d '[:space:]')"; then
break
fi
runner_ip=""
if [[ "$attempt" != "3" ]]; then
sleep "$attempt"
fi
done
valid_runner_ip=true
if [[ ! "$runner_ip" =~ ^(0|[1-9][0-9]{0,2})\.(0|[1-9][0-9]{0,2})\.(0|[1-9][0-9]{0,2})\.(0|[1-9][0-9]{0,2})$ ]]; then
valid_runner_ip=false
else
IFS=. read -r -a runner_ip_octets <<<"$runner_ip"
for octet in "${runner_ip_octets[@]}"; do
if ((10#$octet > 255)); then
valid_runner_ip=false
break
fi
done
fi
if [[ "$valid_runner_ip" != "true" ]]; then
echo "Could not resolve GitHub runner public IPv4 for AWS SSH ingress." >&2
exit 1
fi
+12 -1
View File
@@ -95,7 +95,18 @@ require_host_tools() {
fetch_host_metadata() {
# Keep host metadata lookups bounded like the guest download paths below.
curl -fsSL --connect-timeout 10 --max-time 120 --retry 2 "$@"
local attempt output
for attempt in 1 2 3; do
if output="$(curl -fsSL --connect-timeout 10 --max-time 120 "$@")"; then
printf '%s' "$output"
return 0
fi
output=""
if [[ "$attempt" != "3" ]]; then
sleep "$attempt"
fi
done
return 1
}
vm_exists() {
+71 -1
View File
@@ -2161,9 +2161,79 @@ describe("ci workflow guards", () => {
(step) => step.name === "Run Slack desktop scenario",
);
expect(runStep?.run).toContain("for attempt in 1 2 3");
expect(runStep?.run).toContain(
"curl -fsS --connect-timeout 5 --max-time 15 --retry 2 https://checkip.amazonaws.com",
"curl -fsS --connect-timeout 5 --max-time 15 https://checkip.amazonaws.com",
);
expect(runStep?.run).not.toContain("--retry");
expect(runStep?.run).toContain('runner_ip=""');
expect(runStep?.run).toContain('[[ ! "$runner_ip" =~ ^(0|[1-9][0-9]{0,2})\\.');
expect(runStep?.run).toContain("((10#$octet > 255))");
const discoveryBlock = runStep?.run?.match(
/runner_ip=""[\s\S]*?echo "Using AWS SSH CIDR \$\{CRABBOX_AWS_SSH_CIDRS\}"/u,
)?.[0];
expect(discoveryBlock).toBeTruthy();
const root = mkdtempSync(path.join(tmpdir(), "openclaw-mantis-runner-ip-"));
try {
const fakeBin = path.join(root, "bin");
const callCount = path.join(root, "curl-calls");
mkdirSync(fakeBin);
writeFileSync(callCount, "0\n");
writeFileSync(
path.join(fakeBin, "curl"),
`#!/bin/bash
count="$(<"$CURL_CALL_COUNT")"
count=$((count + 1))
printf '%s\n' "$count" >"$CURL_CALL_COUNT"
if [[ "$count" == "1" ]]; then
printf '198.51.'
exit 28
fi
printf '%s\n' "\${CURL_SUCCESS_IP:-203.0.113.7}"
`,
{ mode: 0o755 },
);
writeFileSync(path.join(fakeBin, "sleep"), "#!/bin/sh\nexit 0\n", { mode: 0o755 });
const result = spawnSync(
"bash",
[
"-c",
`set -euo pipefail\n${discoveryBlock}\nprintf 'result=%s\\n' "$CRABBOX_AWS_SSH_CIDRS"`,
],
{
encoding: "utf8",
env: {
CURL_CALL_COUNT: callCount,
PATH: `${fakeBin}:${process.env.PATH}`,
},
},
);
expect(result.status, result.stderr).toBe(0);
expect(result.stdout).toContain("result=203.0.113.7/32");
expect(result.stdout).not.toContain("198.51.");
expect(readFileSync(callCount, "utf8")).toBe("2\n");
for (const invalidIp of ["999.0.0.1", "203.0.113.7."]) {
writeFileSync(callCount, "0\n");
const invalidResult = spawnSync("bash", ["-c", `set -euo pipefail\n${discoveryBlock}`], {
encoding: "utf8",
env: {
CURL_CALL_COUNT: callCount,
CURL_SUCCESS_IP: invalidIp,
PATH: `${fakeBin}:${process.env.PATH}`,
},
});
expect(invalidResult.status).toBe(1);
expect(invalidResult.stderr).toContain(
"Could not resolve GitHub runner public IPv4 for AWS SSH ingress.",
);
}
} finally {
rmSync(root, { recursive: true, force: true });
}
});
it("fails Windows Testbox setup when Blacksmith phone-home is not accepted", () => {
+31 -2
View File
@@ -318,14 +318,43 @@ describe("Parallels smoke model selection", () => {
"10",
"--max-time",
"120",
"--retry",
"2",
"https://example.test/metadata",
]);
const controller = readFileSync(WINDOWS_PREPARE_WRAPPER, "utf8");
expect(controller.match(/\bcurl -fsSL\b/g)).toHaveLength(1);
expect(controller.match(/\bfetch_host_metadata\b/g)).toHaveLength(5);
expect(controller).toContain("for attempt in 1 2 3");
expect(controller).not.toContain("--retry 2");
const tempDir = makeTempDir(tempDirs, "openclaw-windows-metadata-retry-");
const callCount = join(tempDir, "curl-calls");
writeFileSync(callCount, "0\n");
const retryResult = spawnSync(
"bash",
[
"-c",
`OPENCLAW_PARALLELS_WINDOWS_LIBRARY_ONLY=1 source "$1"
curl() {
count="$(<"$CURL_CALL_COUNT")"
count=$((count + 1))
printf '%s\\n' "$count" >"$CURL_CALL_COUNT"
if [[ "$count" == "1" ]]; then
printf 'partial-'
return 28
fi
printf 'complete'
}
sleep() { :; }
fetch_host_metadata "https://example.test/metadata"`,
"bash",
WINDOWS_PREPARE_WRAPPER,
],
{ encoding: "utf8", env: { ...process.env, CURL_CALL_COUNT: callCount } },
);
expect(retryResult.status, retryResult.stderr).toBe(0);
expect(retryResult.stdout).toBe("complete");
expect(readFileSync(callCount, "utf8")).toBe("2\n");
});
it("accepts leading package-manager separators and still honors later terminators", () => {