name: Lint # The repo's cheap-checks workflow: everything that can be verified WITHOUT # building an image. Runs on every push and PR, in ~30s, independent of the # build pipeline. Three jobs: workflow lint (actionlint + the Gitea shell # guard), Dockerfile lint (hadolint), and the DOCKER_HUB.md docs-sync check. # # Deliberately the ONLY workflow that runs on a push to main. validate.yml # (amd64 build + smoke) is PR/dispatch-only and docker-publish-split.yml is # tag-only, so pushing work-in-progress to main never starts an image build. # # Its original purpose, still the most important one: the "bash-only syntax # under the default `sh`/dash shell" footgun. Ported from pi-devbox, where this # class broke resolve-versions (ed49b8d) and promote-base-latest (b7197e8 → run # 418). actionlint runs shellcheck against each `run:` step using its # *effective* shell, so `set -o pipefail` under dash is flagged as SC3040 # before any expensive build runs. on: push: pull_request: workflow_dispatch: concurrency: group: lint-${{ github.ref }} cancel-in-progress: true defaults: run: shell: bash jobs: actionlint: runs-on: ubuntu-latest container: image: catthehacker/ubuntu:act-latest steps: - uses: actions/checkout@v4 - name: Install shellcheck run: | apt-get update apt-get install -y --no-install-recommends shellcheck python3-yaml - name: Gitea shell guard (catches the actionlint blind spot) # actionlint models GitHub Actions, where the default run shell is # bash, so it does NOT flag bash syntax in a step that merely OMITS # `shell:` — which is exactly how ed49b8d and b7197e8 manifested on # Gitea (default sh/dash). This guard enforces that every run: step # resolves to bash under Gitea's real defaults. Run it BEFORE # actionlint so the more precise diagnostic surfaces first. run: bash scripts/check-workflow-shell.sh .gitea/workflows - name: Install actionlint (pinned) env: ACTIONLINT_VERSION: 1.7.7 run: | curl -fsSL \ "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" \ | tar -xz -C /usr/local/bin actionlint actionlint --version - name: Run actionlint # SHELLCHECK_OPTS excludes pure-style codes (quoting/style opinions) # so the guard stays focused on correctness bugs — crucially the # SC3xxx "not POSIX / wrong shell" family that catches the pipefail # footgun. Do NOT exclude SC3040 (set -o pipefail under sh) or any # other SC3xxx code. env: SHELLCHECK_OPTS: "-e SC2086 -e SC2016 -e SC2129 -e SC2001 -e SC2312" # Pass explicit paths: actionlint's no-arg mode auto-detects a # project by looking for `.github/workflows`, which doesn't exist in # this `.gitea/workflows` repo and hard-fails with exit 3 # ("no project was found"). Globbing the workflow files is the # supported way to lint a non-GitHub layout. run: actionlint -color .gitea/workflows/*.yml hadolint: # Lint the two Dockerfiles that ARE the project (the shell/actions linting # above never looked at them). Config — ignored rules + failure threshold # — lives in .hadolint.yaml, which hadolint reads automatically, so a local # `hadolint Dockerfile.base` reproduces CI exactly. runs-on: ubuntu-latest container: image: catthehacker/ubuntu:act-latest steps: - uses: actions/checkout@v4 - name: Install hadolint (pinned) env: HADOLINT_VERSION: 2.14.0 run: | curl -fsSL \ "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-Linux-x86_64" \ -o /usr/local/bin/hadolint chmod +x /usr/local/bin/hadolint hadolint --version - name: Run hadolint run: hadolint Dockerfile.base Dockerfile.variant docs-check: # Fails if DOCKER_HUB.md is out of sync with what generate-dockerhub-md.py # would produce from HUB_TEMPLATE. Keeps the two docs from drifting. # # Lives here rather than in validate.yml because it needs no image: keeping # it in the cheap workflow means it still runs on every push to main now # that validate.yml is PR/dispatch-only. Reproduce locally with # `python3 scripts/generate-dockerhub-md.py --check`. runs-on: ubuntu-latest container: image: catthehacker/ubuntu:act-latest steps: - uses: actions/checkout@v4 - name: Check DOCKER_HUB.md is in sync with HUB_TEMPLATE run: python3 scripts/generate-dockerhub-md.py --check