diff --git a/.github/actions/repo-gate/repo_gate.py b/.github/actions/repo-gate/repo_gate.py index 7ef62177..1bc0cd9e 100755 --- a/.github/actions/repo-gate/repo_gate.py +++ b/.github/actions/repo-gate/repo_gate.py @@ -412,7 +412,7 @@ def check_eol_coverage(root: Path, files: list[str]) -> list[str]: ACTION_FILE = re.compile(r"^\.github/actions/(?:.+/)?action\.ya?ml$") # A GitHub expression is not shell, so shellcheck would read its braces as syntax. EXPRESSION_START = "${{" -SHELLCHECK_IMAGE = "koalaman/shellcheck:stable" +SHELLCHECK_IMAGE = "mirror.gcr.io/koalaman/shellcheck:stable" SHELLCHECK_TIMEOUT = 300 SCHEMA_TIMEOUT = 300 YAML_TIMEOUT = 60 diff --git a/.github/workflows/validate-task.yml b/.github/workflows/validate-task.yml index 899e551a..ed11f42f 100644 --- a/.github/workflows/validate-task.yml +++ b/.github/workflows/validate-task.yml @@ -158,7 +158,7 @@ jobs: uses: raven-actions/actionlint@3d39aea434753780c3b3d4a1a31c854b4dbf49d7 # v2.2.0 - name: Check EditorConfig step - run: docker run --rm --pull=always -v "$PWD":/check --workdir /check mstruebing/editorconfig-checker:latest + run: docker run --rm --pull=always -v "$PWD":/check --workdir /check ghcr.io/editorconfig-checker/editorconfig-checker:latest # The file list comes from git rather than a glob, and the docker run is skipped rather than invoked on an empty argument list. # That is how a repo with no shell scripts stays clean instead of failing on a linter's own no-file usage error. @@ -226,8 +226,8 @@ jobs: fi done if [ "${#scripts[@]}" -gt 0 ]; then - docker run --rm --pull=always -v "$PWD":/mnt --workdir /mnt koalaman/shellcheck:stable -- "${scripts[@]}" - docker run --rm --pull=always -v "$PWD":/mnt --workdir /mnt mvdan/shfmt:latest -d -- "${scripts[@]}" + docker run --rm --pull=always -v "$PWD":/mnt --workdir /mnt mirror.gcr.io/koalaman/shellcheck:stable -- "${scripts[@]}" + docker run --rm --pull=always -v "$PWD":/mnt --workdir /mnt mirror.gcr.io/mvdan/shfmt:latest -d -- "${scripts[@]}" else echo "no shell scripts are tracked" fi diff --git a/host-setup/linux/README.md b/host-setup/linux/README.md index 3e69c984..cc5d0f41 100644 --- a/host-setup/linux/README.md +++ b/host-setup/linux/README.md @@ -166,7 +166,7 @@ Two of those are guards rather than previews. `--release --dry-run` on a Proxmox `--repo` adds the repository's `install.linux` entries to the report or action. Only `apt` package names are accepted. The script does not execute the declaration's `remedy` text. Reading the JSON needs `jq`, which the ordinary fleet install provides. -The scripts are checked by `shellcheck` and `shfmt`, which run in CI over every `.sh` file `git ls-files` returns, plus a tracked, extension-less file whose shebang names bash or sh. A local run uses the same `koalaman/shellcheck:stable` and `mvdan/shfmt:latest` containers. [`tests/test_bootstrap.py`][test-bootstrap] asserts that every tool the spec requires on Linux is one `install-tools.sh` can provide, or a recorded exception. It also asserts each script here is tracked executable, so a fresh checkout can run it. +CI checks the scripts with `shellcheck` and `shfmt`. It runs both over every `.sh` file `git ls-files` returns, plus a tracked, extension-less file whose shebang names bash or sh. A local run uses the same `mirror.gcr.io/koalaman/shellcheck:stable` and `mirror.gcr.io/mvdan/shfmt:latest` containers. [`tests/test_bootstrap.py`][test-bootstrap] asserts that every tool the spec requires on Linux is one `install-tools.sh` can provide, or a recorded exception. It also asserts each script here is tracked executable, so a fresh checkout can run it. diff --git a/scripts/README.md b/scripts/README.md index 22140fcc..83175614 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -114,7 +114,7 @@ Deterministic checks: - `sha-pin`: every external action or reusable-workflow `uses:` reference is a 40-hex commit SHA, with the documented `dotnet/nbgv@master` exception. References under the scanned repository's owner are also resolved through GitHub. References under another owner are shape-checked only. Local (`./`) and self-repository (`$/`) references name no ref, so they take no pin, and a quoted one is recognized once its quotes are stripped. They resolve differently, though. A `$/` reference and a job-level `./` reusable-workflow call resolve at the calling workflow file's commit, while a `./` action reference resolves against whatever the job checked out, which is the caller's tree where a reusable workflow called from another repository checks out its caller. A reference starting with a bare `.github/` is reported, since GitHub reads it as `owner/repo` rather than as a path. - `eol`: every path pinned LF in [`.gitattributes`][gitattributes] has the matching [`.editorconfig`][editorconfig] override the line-ending rule requires, with EditorConfig brace syntax expanded. One direction only: an `.editorconfig` LF glob with no git pin is legitimate, since `.editorconfig` governs what the editor writes where git enforces a class it must not guess at. - `eol-coverage`: the same pins read against the tree instead. A tracked file opening `#!` that git does not resolve to `eol=lf` is an interpreter line a CRLF checkout breaks, and a pin matching no tracked file is dead unless its block is marked `forward-declared`. -- `composite-actions`: every tracked `action.yml` or `action.yaml` under `.github/actions/`, at any depth, is shellchecked and schema-checked, because actionlint reads workflows only. Each non-empty `run:` body of a bash, sh, or unset-shell step goes to shellcheck. Every `${{ }}` expression is replaced by a placeholder first. A finding names the action file and the step. A pwsh or python step is skipped. The file set goes to `check-jsonschema`'s `vendor.github-actions` builtin through `uvx check-jsonschema@latest`, or `pipx run` where `uvx` is absent. Shellcheck runs from the `koalaman/shellcheck:stable` image, so the check needs Docker. It reads the action through PyYAML, in process where it is importable and through `uvx --with pyyaml` otherwise. Each half reports its own missing tool. Bodies run at warning severity without SC2154, so this is weaker than shellcheck over a `.sh` file. A tree with no action file is skipped with a note. +- `composite-actions`: every tracked `action.yml` or `action.yaml` under `.github/actions/`, at any depth, is shellchecked and schema-checked, because actionlint reads workflows only. Each non-empty `run:` body of a bash, sh, or unset-shell step goes to shellcheck. Every `${{ }}` expression is replaced by a placeholder first. A finding names the action file and the step. A pwsh or python step is skipped. The file set goes to `check-jsonschema`'s `vendor.github-actions` builtin through `uvx check-jsonschema@latest`, or `pipx run` where `uvx` is absent. Shellcheck runs from the `mirror.gcr.io/koalaman/shellcheck:stable` image, so the check needs Docker. It reads the action through PyYAML, in process where it is importable and through `uvx --with pyyaml` otherwise. Each half reports its own missing tool. Bodies run at warning severity without SC2154, so this is weaker than shellcheck over a `.sh` file. A tree with no action file is skipped with a note. ```sh python3 scripts/repo_gate.py diff --git a/scripts/docker_lint.py b/scripts/docker_lint.py index d6391b6a..8e8faf39 100755 --- a/scripts/docker_lint.py +++ b/scripts/docker_lint.py @@ -41,7 +41,12 @@ class Linter: NODE_MODULES_EXCLUDE = ":(glob,exclude)**/node_modules/**" LINTERS = ( - Linter("editorconfig-checker", "mstruebing/editorconfig-checker:latest", (), "/check"), + Linter( + "editorconfig-checker", + "ghcr.io/editorconfig-checker/editorconfig-checker:latest", + (), + "/check", + ), Linter( "actionlint", "rhysd/actionlint:latest", @@ -62,10 +67,16 @@ class Linter: "/workdir", arguments=("--no-progress",), ), - Linter("shellcheck", "koalaman/shellcheck:stable", ("*.sh",), "/mnt", discover_shebang=True), + Linter( + "shellcheck", + "mirror.gcr.io/koalaman/shellcheck:stable", + ("*.sh",), + "/mnt", + discover_shebang=True, + ), Linter( "shfmt", - "mvdan/shfmt:latest", + "mirror.gcr.io/mvdan/shfmt:latest", ("*.sh",), "/mnt", arguments=("-d",),