diff --git a/drb-edge-node/tests/test_host_updater.py b/drb-edge-node/tests/test_host_updater.py index 73b92bc..ddb33f2 100644 --- a/drb-edge-node/tests/test_host_updater.py +++ b/drb-edge-node/tests/test_host_updater.py @@ -151,6 +151,17 @@ def test_mqtt_sentinel_triggers_update_and_is_consumed(env): assert "evil" not in calls and "rm -rf" not in calls +def test_update_prunes_build_cache_and_stale_images_after_up(env): + # node-26#41: the build cache was never pruned and filled node-002's disk. + (env["stub"] / "response").write_text(json.dumps({"update_requested_at": "2026-10-04T12:00:00+00:00"})) + assert _run(env).returncode == 0 + lines = _calls(env).splitlines() + up = next(i for i, ln in enumerate(lines) if ln.startswith("docker compose up -d")) + builder = next(i for i, ln in enumerate(lines) if ln.startswith("docker builder prune -af --filter until=")) + images = next(i for i, ln in enumerate(lines) if ln.startswith("docker image prune -af --filter until=")) + assert up < builder and up < images # only after the new containers are running + + def test_c2_response_is_never_used_as_a_ref_or_command(env): (env["stub"] / "response").write_text(json.dumps({"update_requested_at": "$(touch /tmp/pwned); main"})) r = _run(env) diff --git a/scripts/drb-update.sh b/scripts/drb-update.sh index 0d9219d..6ee7e01 100644 --- a/scripts/drb-update.sh +++ b/scripts/drb-update.sh @@ -225,6 +225,14 @@ do_update() { done || true fi docker image prune -f >/dev/null 2>&1 || true + + # node-26#41: neither of the above ever freed BuildKit cache or untagged- + # but-unused images, so a BUILD=1 node grew ~40 GB of build cache plus + # 16 GB of stale images until the root disk hit 100% and recording silently + # stopped (node-002, 17 days). Both prunes skip anything a container uses; + # the age filters keep the cache warm for the next build. + docker builder prune -af --filter until=72h >/dev/null 2>&1 || true + docker image prune -af --filter until=168h >/dev/null 2>&1 || true } main "$@"