Skip to content

The lint gate downloads a binary over the network every time the hook cache misses #3427

Description

@adamtheturtle

What happens

build (3.14, ubuntu-latest, pre-commit) in the Lint workflow failed while installing hook environments:

error: Failed to install hook `hadolint`
  caused by: Command `uv pip install --project / --directory /home/runner/.cache/prek/repos/2a6b69af185386d7 .` exited with an error:
  × Failed to build `hadolint-py @ ...`
  ├─▶ The build backend returned an error
  ╰─▶ Call to `setuptools.build_meta:__legacy__.build_wheel` failed
      error: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate (_ssl.c:1000)>

https://github.com/VWS-Python/vws-python-mock/actions/runs/31578765061

hadolint-py ships no binary. Its build backend downloads the hadolint release binary during pip install, so installing the hook environment makes a network request to a host which is neither PyPI nor GitHub's API. When that request fails, prek exits 2, and because strategy.fail-fast is not set in .github/workflows/lint.yml it defaults to true, so the other five matrix jobs are cancelled and completion-lint — a required check — fails.

It passed on a re-run.

Why it matters

completion-lint is one of the five checks the require-builds ruleset requires, so a required merge gate depends on an ad-hoc binary download succeeding.

The hook environment is cached, so this only bites on a cache miss — a .pre-commit-config.yaml change, a new runner platform, an evicted cache — which is also exactly when someone is changing linting and least wants an unrelated failure.

This is the same shape as #3402: a required gate whose behaviour depends on something fetched at run time rather than on anything in the repository. Here the fetch is not even version-resolved by a package manager, so there is no lockfile or hash to check it against.

For context on how often the network is the problem rather than the code: on 2026-08-12 a single pull request saw three unrelated TLS failures across two workflows — this one, and actions/checkout failing with server certificate verification failed twice.

Suggested resolution

Options:

  • Install hadolint as a binary in the workflow, with a pinned version and a checksum, and run the hook with language: system. This keeps the pin in the repository and makes the download verifiable, at the cost of a workflow step and a second place to bump the version.
  • Run hadolint through its official Docker image with a pinned digest, using language: docker_image. prek supports this, and it removes the build-time download, but it adds a Docker pull to a lint job which currently needs no Docker.
  • Leave it and accept the occasional re-run, but set fail-fast: false on the Lint matrix so one job's install failure does not cancel five healthy jobs. This is worth doing regardless of which option is chosen — the cancelled jobs are noise which makes the real failure harder to find.

The fail-fast: false part is small and independently useful. The rest is a judgement call about how much a rare, self-clearing failure is worth removing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions