Repository navigation
191 lines (178 loc) · 8.01 KB
/
Copy pathpacman-static.yml
File metadata and controls
191 lines (178 loc) · 8.01 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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
name: Static pacman
# Build a statically linked pacman for every architecture, from source, and
# publish the eight binaries as release assets.
#
# ⛔ Nothing here touches an image build. The Dockerfile does not read the source
# pin and does not fetch these binaries. This produces release assets only, and
# tests/static/85-pacman-static-pin.sh fails if that ever stops being true.
#
# ⭐ A dispatch builds and uploads for inspection and stops. Nothing here creates
# a release: release.yml owns the v* tag and calls this workflow for the eight
# binaries, so a manual run cannot publish one by accident and there is one
# place that publishes rather than two.
on:
workflow_dispatch:
workflow_call:
defaults:
run:
shell: bash
permissions:
contents: read
concurrency:
group: pacman-static-${{ github.ref }}
cancel-in-progress: true
jobs:
#----------------------------------------------------------------------------------#
# One job per architecture. fail-fast is off so one run reports every broken
# target rather than the first, and the release job needs the whole matrix, so
# a run that lost one architecture publishes nothing.
#----------------------------------------------------------------------------------#
build:
name: Build ${{ matrix.docker_arch }}
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
# ⚠ arch-subset: this is the whole architecture set and is kept in step
# with the build matrix by tests/static/85-pacman-static-pin.sh, which
# reads build-deploy.yml and fails when a row here is missing from
# scripts/build-pacman-static.
docker_arch:
- amd64
- arm64
- armv7
- loong64
- riscv64
# - ppc
# - ppc64
# - ppc64le
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# The build runs natively; the emulator is only used to run the finished
# binary and print its version. ⛔ Without one the run column reads
# NOT MEASURED, so the emulator is what turns a link into a proof.
# ⛔ meson comes from pip at a pinned version, not from apt.
#
# meson detects a linker by its banner, and the branch that recognises
# zig's `zig ld` arrived in meson 1.6.0. ubuntu-latest ships 1.3.2 through
# apt, so every architecture built all eleven libraries and then stopped
# at the pacman step with "Unable to detect linker". Measured 2026-08-29
# in run 33208408451.
#
# ⛔ Pinned rather than floated, for the same reason every other input
# here is: the runner image's apt version is upstream's mood, and this
# build's output must not depend on it. scripts/build-pacman-static
# asserts the minimum separately, so a host with an old meson fails with
# the version named rather than with meson's own message.
#
# ⚠ This pin has no freshness job watching it. HISTORY/pacman-static.md.
- name: Install the build tools and the emulators
env:
MESON_VERSION: "1.10.1"
run: |
set -euo pipefail
sudo apt-get update -qq
sudo apt-get install -y -qq --no-install-recommends \
cmake ninja-build gperf diffutils qemu-user-static gnupg
# An explicit branch on a capability, not a suppressed failure: the
# runner image has pipx, and a host without it still gets a pinned
# meson rather than whatever apt holds.
if command -v pipx > /dev/null; then
pipx install "meson==${MESON_VERSION}"
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
export PATH="$HOME/.local/bin:$PATH"
else
python3 -m pip install --break-system-packages --quiet "meson==${MESON_VERSION}"
fi
got="$(meson --version)"
if [ "$got" != "${MESON_VERSION}" ]; then
echo "meson is $got, the pin says ${MESON_VERSION}" >&2
echo "an unpinned meson is the runner image's apt version, which was 1.3.2" >&2
command -v meson
exit 1
fi
echo "meson $got, ninja $(ninja --version)"
# ⛔ Asserted, not assumed. The emulator for this target has to be on PATH
# before the build starts, because the build treats a missing one as
# NOT MEASURED rather than as a failure, and a whole matrix reporting
# NOT MEASURED would read like a pass.
- name: Check the emulator for this target is installed
env:
DOCKER_ARCH: ${{ matrix.docker_arch }}
run: |
set -euo pipefail
case "$DOCKER_ARCH" in
amd64) emu=qemu-x86_64-static ;;
arm64) emu=qemu-aarch64-static ;;
armv7) emu=qemu-arm-static ;;
loong64) emu=qemu-loongarch64-static ;;
riscv64) emu=qemu-riscv64-static ;;
ppc) emu=qemu-ppc-static ;;
ppc64) emu=qemu-ppc64-static ;;
ppc64le) emu=qemu-ppc64le-static ;;
*) echo "no emulator recorded for $DOCKER_ARCH" >&2; exit 1 ;;
esac
if ! command -v "$emu" > /dev/null; then
echo "$emu is not installed, so the binary for $DOCKER_ARCH could be built and never run" >&2
echo "qemu-user-static supplies it. What is present:" >&2
ls /usr/bin/qemu-*-static >&2
exit 1
fi
echo "$emu: $("$emu" --version | awk 'NR == 1')"
- name: Build
env:
DOCKER_ARCH: ${{ matrix.docker_arch }}
run: |
set -euo pipefail
WORK="${RUNNER_TEMP}/pacman-static" OUT="${RUNNER_TEMP}/dist" \
scripts/build-pacman-static "$DOCKER_ARCH"
# ⛔ The pin names two pacman release manager fingerprints and the build
# requires a signature from one of them. NOT VERIFIED is what an evidence
# file carries when that never ran, and SKIPPED is what it carries when
# somebody set PACMAN_TAG_VERIFY=skip. Neither may reach a release asset.
- name: Refuse an asset whose signed tag was not verified
env:
DOCKER_ARCH: ${{ matrix.docker_arch }}
run: |
set -euo pipefail
ev="${RUNNER_TEMP}/dist/pacman-static-${DOCKER_ARCH}.json"
verified="$(jq -r .pacman_tag_verified_by "$ev")"
signer="$(jq -r .pacman_tag_signer "$ev")"
case "$verified" in
"NOT VERIFIED" | SKIPPED | "" | null)
echo "the ${DOCKER_ARCH} asset carries tag verification: $verified" >&2
echo "an asset whose upstream signature was never checked is not evidence" >&2
exit 1
;;
esac
echo "::notice::${DOCKER_ARCH} signed tag verified by ${signer} (${verified})"
# ⛔ The build says NOT MEASURED when it could not run the binary. That is
# the honest value and it must not reach a release, so it is refused here
# rather than shipped with a caveat nobody reads.
- name: Refuse an asset whose binary was never run
env:
DOCKER_ARCH: ${{ matrix.docker_arch }}
run: |
set -euo pipefail
ev="${RUNNER_TEMP}/dist/pacman-static-${DOCKER_ARCH}.json"
reported="$(jq -r .reported_version "$ev")"
if [ "$reported" = "NOT MEASURED" ]; then
echo "the ${DOCKER_ARCH} binary linked and was never executed" >&2
echo "an asset nobody has run is not evidence that it works" >&2
exit 1
fi
echo "::notice::${DOCKER_ARCH} reported ${reported}"
- name: Upload
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: pacman-static-${{ matrix.docker_arch }}
path: |
${{ runner.temp }}/dist/pacman-static-${{ matrix.docker_arch }}
${{ runner.temp }}/dist/pacman-static-${{ matrix.docker_arch }}.json
if-no-files-found: error
retention-days: 7