Where a hung package mirror spends your CI budget

On fork PR #3555, three jobs died inside Setup environment without running a single test. Drag the controls to see why the failure time tracked the job's own cap instead of the hang.

install path

What actually happened, 2026-08-19

jobcapdied afterstep
Security Tests15 min15m 16sSetup environment
Compliance Tests15 min15m 16sSetup environment
Unit Tests (node 20)30 min30m 15sSetup environment

Each job died at its own cap, to the second. That is timeout-minutes firing, not a test failing and not concurrency cancelling. GitHub reports a cap-killed job as cancelled, which is what made it read like an infra flake.

Why the existing guard could not help

The call site carried what looks like a safety net:

if ! sudo apt-get update -qq; then
    log_warn "apt-get update had issues, continuing anyway..."
fi

That catches a non-zero exit. A hang never exits, so the guard never runs. Only an external watchdog (timeout) converts a hang into an exit the guard can see.

Fix: every package install routes through .github/scripts/ensure-system-deps.sh, which skips the package manager when the tools are already present and bounds the call at SYSTEM_DEPS_TIMEOUT (90s default) otherwise. tests/ci/test-no-unbounded-package-manager.sh greps the whole CI-executed surface so the next call site cannot reintroduce this. Issue #3557.