ci/toolchain installs the pinned tools, collections and rsync from cache for both GitHub and Gitea; GitLab caches pip downloads. shellcheck now finds scripts rather than globbing, which broke when a glob matched nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
78 lines
3.0 KiB
YAML
78 lines
3.0 KiB
YAML
---
|
|
# The static gate. Runs on every push and pull request, needs no access to any
|
|
# host, and is the definition of "done" for a change here.
|
|
#
|
|
# Everything below is `scripts/check.sh` plus two scans. Keeping the lint steps
|
|
# in a script rather than inline is deliberate: a contributor can run the exact
|
|
# same gate locally with `make check` before pushing, and the two cannot drift.
|
|
name: lint
|
|
|
|
on:
|
|
push:
|
|
branches: ["**"]
|
|
pull_request:
|
|
|
|
# A second push to the same branch makes the first run pointless.
|
|
concurrency:
|
|
group: lint-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
ansible:
|
|
name: yamllint + ansible-lint + syntax
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
# scripts/check.sh is the single source of the version pins; the action
|
|
# installs exactly what a contributor runs locally, so nothing here can
|
|
# drift from `make check`. The collections are cached with it, which
|
|
# leaves check.sh's own `ansible-galaxy install` nothing to fetch.
|
|
- name: Install the pinned toolchain
|
|
uses: ./ci/toolchain
|
|
with:
|
|
specs: all
|
|
collections: "true"
|
|
|
|
- name: Run the static gate
|
|
run: RUNNER=installed scripts/check.sh
|
|
|
|
shell:
|
|
name: shellcheck
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
# Pre-installed on GitHub-hosted Ubuntu runners; installed explicitly so
|
|
# this job also works on a self-hosted runner with a bare image.
|
|
- name: Install shellcheck
|
|
run: command -v shellcheck || sudo apt-get install -y --no-install-recommends shellcheck
|
|
- name: Check the shell scripts
|
|
# find rather than a glob. Bash leaves an unmatched pattern alone instead
|
|
# of expanding it to nothing, so `server/*/*/app/*.sh` reaches
|
|
# shellcheck as a literal filename the moment the last payload script
|
|
# goes away, and the job fails with `openBinaryFile: does not exist`.
|
|
# `xargs -r` covers the other half: no scripts at all must be a no-op,
|
|
# not a shellcheck invocation with no arguments that sits reading stdin.
|
|
run: find scripts server -name '*.sh' -print0 | xargs -0 -r shellcheck
|
|
|
|
secrets:
|
|
name: secret scan
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
# detect scans history, not just the working tree. A secret that was
|
|
# committed and then removed is still a leaked secret.
|
|
fetch-depth: 0
|
|
# Run the upstream image directly rather than the marketplace action: the
|
|
# action requires a licence key for organisation-owned repositories, and
|
|
# silently no-ops without one. The image has no such condition.
|
|
- name: Scan the working tree and history for committed secrets
|
|
run: |
|
|
docker run --rm -v "$PWD:/repo" zricethezav/gitleaks:latest \
|
|
detect --source=/repo --config=/repo/.gitleaks.toml \
|
|
--redact --verbose --no-banner
|