Skip to content

installer-tests: the prereqs install step is unbounded, so a mirror stall reads as a 20-minute cancel #986

Description

@LukasWodka

Summary

A distro-mirror stall in the Prereqs — <distro> matrix job of .github/workflows/installer-tests.yaml runs until the job's timeout-minutes: 20 fires and then reads as cancelled, with no log line saying why. It happened twice on 2026-09-04 on two package managers. The step that runs the prereqs is:

- name: Install prerequisites in ${{ matrix.distro }}
  run: |
    docker run --rm -v "$PWD:/src:ro" -w /src "$DISTRO" \
      bash scripts/tests/distro-prereqs.sh

What IS already bounded, so this is not "add a timeout" as first written. scripts/tests/distro-prereqs.sh bounds its own bootstrap through _pm_run (three attempts of timeout ${TB_PM_TIMEOUT:-60} <pm> …, then a ::error:: naming mirror connectivity — added for exactly this class after backend#2859), and its header says the real installer functions it then invokes use common.sh's bounded probes. The sibling Pull <distro> (bounded, retried) step and Install bats (bounded, retried) bound their commands the same way. So somewhere in this leg a command reached the 20-minute cap past those bounds, and the ticket's job is to find which. Two candidates, neither verified yet because the cancelled job's step log is not retrievable after the cap fires:

  1. _pm_run falls through to an unbounded call when the container has no timeout binarymeasured false (see comment below): rockylinux:9 ships /usr/bin/timeout via coreutils-single, so the bounded helpers did bound what they wrapped. The fall-through itself remains a fail-open worth closing, but it is not this leg's mechanism.
  2. A later installer function runs a package-manager or network command that is not routed through a bounded probe (docker-ce repo setup, conntrack, helm download). If so, the fix is at that call site, not in the workflow.

Measured

leg evidence
Prereqs — rockylinux:9 (run 33889848786, attempt 1, PR #983) step "Install prerequisites in rockylinux:9" ran 15:40:32 → 16:00:41, the 20-minute cap to the second; the other 24 legs of the run were green. Conclusion cancelled. Nothing in the PR's diff reaches the prereqs path.
Installer tests / PATH persist (the leg behind #980) apt-get update could not reach the Ubuntu mirror; gh run rerun --failed passed with no code change. #980 blamed a merge for it and had to be corrected.

Both cost 20 minutes of wall clock and a reviewer holding an approval on a red check that was never about the diff.

Proposed fix

  1. First, make the cap legible: a timeout on the docker run itself, sized just under timeout-minutes (say 18 min), so the step FAILS with the script's own last stdout/stderr in the log instead of being cancelled by the job cap with nothing to read. That alone turns the next occurrence into evidence about which command stalled.
  2. Close the fail-open regardless of which candidate measures true: _pm_run (distro-prereqs.sh) and _bounded (common.sh) both fall through to a bare "$@" when neither timeout nor gtimeout exists, so an absent guard reads as a satisfied one — a distro without coreutils timeout passes the "bounded call" check by never being bounded. The probe should refuse (or install coreutils first) when command -v timeout is empty, the same way the repo's other guards fail closed.
  3. Then, if the evidence names it, route the unbounded installer call site through the bounded probe.

A mirror stall should end as a failed step with a reason in its log, never a cancelled job whose only evidence is that its start and end timestamps match timeout-minutes.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    work-type:tech-debtRefactor / cleanup, no behavior change

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions