-
Notifications
You must be signed in to change notification settings - Fork 0
136 lines (125 loc) · 6.39 KB
/
Copy pathworkflows-lint.yml
File metadata and controls
136 lines (125 loc) · 6.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
name: Release tooling
# Catches workflow YAML / shell-in-`run:` regressions at PR time so a
# typo can't reach a release tag and surface only when a publish run
# fails. The shell scripts under scripts/ are in the same category — a
# break in them surfaces only when someone reaches for them after a
# release, which is the worst moment to discover it — so they are linted
# and tested here too. Scoped to a few paths to keep CI overhead off
# unrelated PRs.
#
# `.github/scripts/**` is in scope on the same argument. Those scripts stopped
# being thin fetch wrappers once the conformance case-body drift check landed
# there, and they run only on a weekly schedule, so a break in them surfaces
# late and quietly. The trigger stays narrow: it matches PRs touching those
# scripts, not every PR touching `.github/**`.
#
# Linting alone would not have been enough for them, so they carry their own
# tests here as well, next to backport-fixes.test.sh.
#
# Every scripts trigger is `<dir>/**`, not `<dir>/*.sh`: a single-level
# glob would leave a future scripts/lib/*.sh both untriggered here and
# unlinted below, in each case silently.
on:
pull_request:
paths:
- ".github/workflows/**"
- ".github/scripts/**"
- "scripts/**"
push:
branches:
- main
paths:
- ".github/workflows/**"
- ".github/scripts/**"
- "scripts/**"
permissions:
contents: read
jobs:
actionlint:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# Pulls the matching actionlint binary release from GitHub Releases
# via the upstream download script. The script is fetched by commit
# SHA (not a mutable tag) and sha256-verified before it runs — this
# closes Scorecard's "downloadThenRun not pinned by hash" gap. The
# script then checksum-verifies the actionlint binary it pulls from
# the matching release.
#
# To bump: change ACTIONLINT_VERSION, set ACTIONLINT_SCRIPT_SHA to the
# commit the new tag points at (`gh api repos/rhysd/actionlint/commits/vX.Y.Z -q .sha`),
# and update ACTIONLINT_SCRIPT_SHA256 to that file's sha256.
#
# Install dir is passed explicitly as the script's second positional
# arg so the workflow doesn't couple to the script's internal default
# of $PWD (which happens to be $GITHUB_WORKSPACE after checkout —
# a coincidence, not a contract).
- name: Install actionlint
env:
ACTIONLINT_VERSION: "1.7.7"
ACTIONLINT_SCRIPT_SHA: "03d0035246f3e81f36aed592ffb4bebf33a03106"
ACTIONLINT_SCRIPT_SHA256: "221d1d16c03e4e4fcd867de34104e8d479bdce20ccdfa553b9a5c0dc29bf6af2"
ACTIONLINT_INSTALL_DIR: ${{ runner.temp }}/actionlint
run: |
mkdir -p "${ACTIONLINT_INSTALL_DIR}"
script="${ACTIONLINT_INSTALL_DIR}/download-actionlint.bash"
curl -fsSL -o "${script}" \
"https://raw.githubusercontent.com/rhysd/actionlint/${ACTIONLINT_SCRIPT_SHA}/scripts/download-actionlint.bash"
echo "${ACTIONLINT_SCRIPT_SHA256} ${script}" | sha256sum -c -
bash "${script}" "${ACTIONLINT_VERSION}" "${ACTIONLINT_INSTALL_DIR}"
echo "${ACTIONLINT_INSTALL_DIR}" >> "${GITHUB_PATH}"
"${ACTIONLINT_INSTALL_DIR}/actionlint" -version
# Both steps below resolve `shellcheck` off the runner image's $PATH —
# actionlint via `-shellcheck=shellcheck`, the script lint directly.
# Asserting it once, up front, is what makes that dependency explicit:
# naming the binary in actionlint's flag only changes which lookup
# fails, and neither step announces the version it linted with. If the
# Ubuntu image ever drops shellcheck, this fails first and says so,
# rather than actionlint quietly degrading to no shell analysis.
- name: Check shellcheck is available
run: shellcheck --version
- name: Run actionlint
run: actionlint -color -shellcheck=shellcheck
- name: Shellcheck the release scripts
# find, not `scripts/*.sh`: the single-level glob would silently skip
# a future scripts/lib/*.sh, the same blind spot the path trigger had.
# An empty result is an error rather than a green no-op, so a moved or
# renamed directory cannot pass as a clean lint.
run: |
mapfile -d '' -t sh_files < <(find scripts -type f -name '*.sh' -print0)
if [[ ${#sh_files[@]} -eq 0 ]]; then
echo "error: no shell scripts found under scripts/" >&2
exit 1
fi
printf 'shellcheck: %s\n' "${sh_files[@]}"
shellcheck "${sh_files[@]}"
- name: Shellcheck the workflow support scripts
# A second step rather than a second root on the find above, so an
# empty result names the directory that went missing. Merged, a renamed
# .github/scripts/ would still be covered by whatever scripts/ returned.
run: |
mapfile -d '' -t sh_files < <(find .github/scripts -type f -name '*.sh' -print0)
if [[ ${#sh_files[@]} -eq 0 ]]; then
echo "error: no shell scripts found under .github/scripts/" >&2
exit 1
fi
printf 'shellcheck: %s\n' "${sh_files[@]}"
shellcheck "${sh_files[@]}"
# backport-fixes.sh accepts a branch or a tag as --from, and only the
# branch form has a remote-tracking ref. The tag form is what the release
# flow tells you to use once release.yml has deleted the branch, so it is
# the form least likely to be exercised before it is needed.
- name: Test backport-fixes.sh
run: scripts/backport-fixes.test.sh
# Shellcheck above is the only other gate on the conformance drift
# scripts, and it cannot see the way they break: a loosened id regex that
# drops cases, or a `diff` whose exit code stops being read, is valid
# shell. The result is a check that reports green while guarding nothing,
# on a weekly schedule where nobody is watching — and it would stay
# unnoticed until a real re-tightening slipped through, which is the
# failure that check exists to prevent. These controls pin the detection
# itself. They need neither the catalog clone nor the SDK's dependencies,
# so they run here.
- name: Test conformance-case-body-drift.sh
run: .github/scripts/conformance-case-body-drift.test.sh