feat: ship hadolint natively so docker repos stop curling it every CI run #2

Closed
opened 2026-07-29 19:19:36 +00:00 by gravityfargo · 0 comments
Owner

Context

The docker type baseline in gravityfargo/templates lints the Dockerfile in .forgejo/workflows/checks.yml. The image has no hadolint, so every pull-request run installs one first:

env:
    HADOLINT_VERSION: v2.14.0

# ...

- name: Install hadolint
  run: |
      curl -fsSL -o /tmp/hadolint "https://github.com/hadolint/hadolint/releases/download/${HADOLINT_VERSION}/hadolint-Linux-x86_64"
      chmod +x /tmp/hadolint

- name: Lint Dockerfile
  run: |
      /tmp/hadolint --version
      /tmp/hadolint Dockerfile

Repos carrying that step today: bluesky-pds-docker, bluesky-post-action, athena-archive-ci-image, commitizen-ci, and this repo itself.

Three problems with it:

  1. Every lint run reaches out to github.com. An outage or a rate limit there fails a check that otherwise has nothing to do with GitHub.
  2. The version pin lives in a workflow env block in each repo. The shared Renovate preset has no custom manager for it, so moving hadolint forward is a fleet-wide workflow edit instead of an image tag bump the existing wiring already handles.
  3. The download URL hardcodes Linux-x86_64.

Locally the story is already fine — docker/Makefile runs hadolint/hadolint:v2.14.0-alpine as its own container, so docker is the only requirement. CI is the only place the curl exists.

Ask

Install hadolint into the image, pinned in the Dockerfile the same way prettier is (npm install --global prettier@3.8.1). It is a single static binary with no runtime dependencies.

Once it ships, the checks workflow collapses to:

- name: Lint Dockerfile
  run: hadolint Dockerfile

and the version comes under the same Renovate coverage as everything else in the Dockerfile.

Alternatives considered

  • Keep curling it. Works today, but pays a network round trip on every run and keeps the pin scattered across five repos.
  • A separate hadolint-only job container. The same job also runs prettier --check ., so this splits one job across two containers to avoid one download.
  • Cache the binary via actions/cache. More YAML in every repo than the curl step it would replace.

Downstream

Landing this means the docker baseline drops the install step and the HADOLINT_VERSION env, then gets propagated to the repos listed above. Tracked in gravityfargo/templates#10 — nothing to do here beyond shipping the binary.

## Context The docker type baseline in gravityfargo/templates lints the Dockerfile in `.forgejo/workflows/checks.yml`. The image has no hadolint, so every pull-request run installs one first: ```yaml env: HADOLINT_VERSION: v2.14.0 # ... - name: Install hadolint run: | curl -fsSL -o /tmp/hadolint "https://github.com/hadolint/hadolint/releases/download/${HADOLINT_VERSION}/hadolint-Linux-x86_64" chmod +x /tmp/hadolint - name: Lint Dockerfile run: | /tmp/hadolint --version /tmp/hadolint Dockerfile ``` Repos carrying that step today: bluesky-pds-docker, bluesky-post-action, athena-archive-ci-image, commitizen-ci, and this repo itself. Three problems with it: 1. Every lint run reaches out to github.com. An outage or a rate limit there fails a check that otherwise has nothing to do with GitHub. 2. The version pin lives in a workflow `env` block in each repo. The shared Renovate preset has no custom manager for it, so moving hadolint forward is a fleet-wide workflow edit instead of an image tag bump the existing wiring already handles. 3. The download URL hardcodes `Linux-x86_64`. Locally the story is already fine — `docker/Makefile` runs `hadolint/hadolint:v2.14.0-alpine` as its own container, so docker is the only requirement. CI is the only place the curl exists. ## Ask Install hadolint into the image, pinned in the Dockerfile the same way prettier is (`npm install --global prettier@3.8.1`). It is a single static binary with no runtime dependencies. Once it ships, the checks workflow collapses to: ```yaml - name: Lint Dockerfile run: hadolint Dockerfile ``` and the version comes under the same Renovate coverage as everything else in the Dockerfile. ## Alternatives considered - **Keep curling it.** Works today, but pays a network round trip on every run and keeps the pin scattered across five repos. - **A separate hadolint-only job container.** The same job also runs `prettier --check .`, so this splits one job across two containers to avoid one download. - **Cache the binary via `actions/cache`.** More YAML in every repo than the curl step it would replace. ## Downstream Landing this means the docker baseline drops the install step and the `HADOLINT_VERSION` env, then gets propagated to the repos listed above. Tracked in gravityfargo/templates#10 — nothing to do here beyond shipping the binary.
Sign in to join this conversation.
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
ModernLeft/general-ci-image#2
No description provided.