mirror of
https://github.com/kvcache-ai/AgentENV.git
synced 2026-11-05 01:17:36 +00:00
[PR #355] [MERGED] fix: stabilize recurring CI flakes #374
Labels
No labels
bug
documentation
enhancement
enhancement
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/AgentENV#374
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/kvcache-ai/AgentENV/pull/355
Author: @yingdi-shan
Created: 10/10/2026
Status: ✅ Merged
Merged: 10/12/2026
Merged by: @yingdi-shan
Base:
main← Head:fix/ci-flakes📝 Commits (6)
d4432fefix(firecracker): wait for the API socket to accept connections2d22796test(network): retry expected-success connectivity probesefca2b1ci: authenticate BuildKit release lookup3221303test(buildkit): do not require builders on different nodes6c01d56fix(build): treat a reaped BuildKit daemon as stoppedb673585fix(envd): lock /etc/passwd when adding a Dockerfile USER account📊 Changes
8 files changed (+276 additions, -43 deletions)
View changed files
📝
.github/workflows/integration-tests.yml(+5 -3)📝
scripts/buildkit/install-buildctl.sh(+5 -1)📝
scripts/buildkit/test.py(+4 -2)📝
src/api/impls/image_build/worker.rs(+4 -2)➕
src/sandbox/envd/add_passwd_entry.sh(+38 -0)📝
src/sandbox/envd/user.rs(+139 -4)📝
src/sandbox/firecracker/instance.rs(+31 -9)📝
tests/integration/fc.rs(+50 -22)📄 Description
What
Fix six recurring CI flakes found by triaging the failed runs since mid-September. Each fix is a separate commit:
fix(firecracker): wait for the Firecracker API socket to accept connections, not just exist.test(network): retry expected-success connectivity probes in the network integration tests.ci: authenticate the BuildKit release lookup ininstall-buildctl.sh.test(buildkit): stop requiring concurrent builders to land on different nodes.fix(build): treat a reaped BuildKit daemon as stopped, so the shared build cache is published.fix(envd): lock/etc/passwdwhen adding the generated account for a numeric DockerfileUSER.Why
These failures recur across unrelated PRs and on
main:process::numeric_image_users_preserve_identity_after_start_and_resume(invalid default user: 'aenv-12345-23456')init-adduserrunsusermod/groupmodat boot, which rewrite/etc/passwdvia temp file + rename. AgentENV starts envd before exec'ing the image init and appended the generated account with an unlocked>>, so the line was intermittently lost.Failed to set machine configuration/Connection refused (os error 111)(e.g.fc::oci_tools_share_a_readonly_device_across_concurrent_launches,snapshot_attached_drive::frozen_volumes_survive_deletion_without_vm_snapshot)wait_for_readypolledsocket_path.exists(). The path appears atbind(), before Firecracker callslisten(), so the first API request could getECONNREFUSED.fc::microvm_can_access_internet,fc::microvm_network_policy_controls_egress(Could not resolve host: www.baidu.com,SSL connection timeoutforwww.qq.com, exit 124)Prepare BuildKit test clientexits 22 (curl: (22) ... 403)api.github.comcalls share the per-IP rate limit on hosted runners, andcurl --retrydoes not retry 403.test_concurrent_buildsseed mismatch (AssertionError: '<uuid>' != '<uuid>', single-node and compose)STOP_BUILDKITrankill -0and then grepped/proc/$pid/status. If the buildkitd zombie was reaped in between,grepfailed on the missing file and the script exited 1 (grep: /proc/376/status: No such file or directory). The worker then logged "BuildKit shutdown failed; keeping the previous cache seed", so the next builds started from an empty cache.Timed out waiting for concurrent builders on different nodes(Docker Compose E2E)aenv buildsession creation and status polls that 404 before the builder binds. Two concurrent builders can legitimately share a node.Related issue
N/A: found by triaging recent CI failures.
Scope and non-goals
mainand not touched here: the MinIOquay.iopull failures (nowpgsty/silo) and the clippy 1.99double_must_usefailures.agentenv-tools:0.1.2) were excluded.Design and behavior changes
FirecrackerInstance::wait_for_readynow loops ontokio::net::UnixStream::connectuntil it succeeds, keeping the existing early exit if Firecracker dies and the timeout. Error messages now say "did not accept connections". The pool (pool.rs) and sandbox start paths both use this function.assert_tcp_connect/assert_curlretry up to 3 times, 2 s apart, only when success is expected. Expected-blocked probes still run once, so a retry cannot hide a policy that fails to block.src/sandbox/envd/add_passwd_entry.sh, embedded withinclude_str!and run with the guest's BusyBox. It takes shadow-utils'/etc/passwd.locklink lock (the same protocolusermod/useradduse), reclaims a lock whose owner PID has exited, waits up to 5 s for a live owner, skips the append if the entry is already present, and verifies it afterwards. The script ships with the server rather than the tools drive, so it also covers sandboxes on older, immutable tools releases. Inputs are passed as positional arguments, so there is no Rust-side shell quoting.STOP_BUILDKITdecides liveness from/proc/<pid>/statusalone: the process is running only if the file exists and its state is notZ. A missing file means stopped. A process that ignores SIGTERM still makes the stop fail after the existing 30 s wait.install-buildctl.shsendsAuthorization: Bearer $GITHUB_TOKENwhen the variable is set, and stays unauthenticated otherwise. curl reads the header from stdin (-H @-), so the token never appears in the process list. The integration workflow givesgithub.tokenonly to a separate install step, not tomake build-aenv.test_concurrent_builds(compose mode) now waits for the summed builder increase across nodes to reach 2 instead of requiring 2 distinct nodes. It still asserts that both workers overlap.Compatibility and operations
Install BuildKit test clientstep receives the job's read-onlygithub.token.Validation
make fmtmake clippymake test-unitmake -C services test(required whenservices/changes)maketargetCommands and results:
Skipped checks and reasons:
make test-unit: only the affected unit module was run.scripts/buildkit/test.py) and the Docker Compose E2E suite were not run locally (STOP_BUILDKITwas tested in a container); the CI E2E jobs exercise them.make -C services test:services/is unchanged.Risks and reviewer notes
wait_for_readyopens one throwaway connection to Firecracker's API socket. Firecracker's API server accepts and drops idle connections, and the client already opens a connection per request./etc/passwd.lockfor a few milliseconds means a collidingusermodin the image init fails fast with "cannot lock /etc/passwd; try again later", which is shadow's own contract between account tools, instead of AgentENV's entry being silently lost.Checklist
🤖 Generated with Claude Code
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.