Skip to content

Commit e25841d

Browse files
committed
[ci] Finalize DEB packaging on the unified linux-packages workflow
Collapses the DEB GPG-signing work onto today's master, which already carries the shared packaging infrastructure (nfpm-native signing, lib-build-common.sh, composite build-package action). What remains is the DEB-specific delta: - build-linux-packages.yml: replace the shared upload-pkg-s3 reusable-workflow call with an inline, DEB-only upload-debs-s3 job so `id-token: write` is never granted to a job that checks out a tag tree and runs packaging scripts; RPM S3 publishing can land as a sibling job later - remove upload-pkg-s3.yml, superseded by the inline job - reject a workflow_dispatch input that is not an existing origin tag before the signing key is imported, so the key can never sign arbitrary branch content; a lighter format check is mirrored in workflow-setup-packaging.sh - move DEB install paths off /usr/local to /usr per Debian Policy §9.1.2 (avalanchego-deb.yml, subnet-evm-deb.yml), kept in sync with validate-deb.sh - build-package.sh: inline the package-format uppercasing - build-package action: document that the resolved tag is independent of format and arch - docs: README and RELEASING_README updates for the unified workflow Verified locally: task packaging:test-build-debs builds and signs both DEBs, verifies the signatures, and installs + smoke-tests them in fresh jammy and noble containers.
1 parent fc3bdf3 commit e25841d

10 files changed

Lines changed: 107 additions & 157 deletions

File tree

.github/packaging/README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ The packaging pipeline builds two packages per format and architecture:
2626
| --- | --- | --- | --- |
2727
| RPM | `avalanchego` | `/var/opt/avalanchego/bin/avalanchego` | `glibc >= 2.34` |
2828
| RPM | `subnet-evm` | `/var/opt/avalanchego/plugins/<VM_ID>` | `glibc >= 2.34` |
29-
| DEB | `avalanchego` | `/usr/local/bin/avalanchego` | `libc6 (>= 2.35)` |
30-
| DEB | `subnet-evm` | `/usr/local/lib/avalanchego/plugins/<VM_ID>` | `libc6 (>= 2.35)` |
29+
| DEB | `avalanchego` | `/usr/bin/avalanchego` | `libc6 (>= 2.35)` |
30+
| DEB | `subnet-evm` | `/usr/lib/avalanchego/plugins/<VM_ID>` | `libc6 (>= 2.35)` |
3131

3232
`<VM_ID>` is sourced from `graft/subnet-evm/scripts/constants.sh`.
3333

@@ -176,8 +176,12 @@ Ubuntu glibc, which is typically newer than the intended jammy floor.
176176

177177
### Why workflows overlay `.github/packaging` for manual tag builds
178178

179-
`workflow_dispatch` accepts an arbitrary tag, including tags created before this
180-
packaging implementation existed in the repository.
179+
`workflow_dispatch` accepts any tag whose source tree the current packaging
180+
implementation can still build, including tags created before this packaging
181+
implementation existed in the repository. The practical floor is the commit that
182+
introduced `graft/` populated with both coreth and subnet-evm: `lib-build-common.sh`
183+
sources `graft/subnet-evm/scripts/{build,constants}.sh`, so tags predating `graft`
184+
cannot be rebuilt (see "Implications for maintainers" below).
181185

182186
Those older tags may not contain:
183187

@@ -371,7 +375,8 @@ If you change this area, preserve these unless you are intentionally revisiting
371375
the design:
372376

373377
- RPMs install under `/var/opt/avalanchego/...`
374-
- DEBs install under `/usr/local/...`
378+
- DEBs install under `/usr/bin` and `/usr/lib` (Debian Policy §9.1.2 forbids
379+
`/usr/local` for packaged files)
375380
- Subnet-EVM installs under the VM ID from
376381
`graft/subnet-evm/scripts/constants.sh`
377382
- RPM release builds target glibc 2.34 / Rocky Linux 9 compatibility

.github/packaging/actions/build-package/action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ inputs:
3232
default: 'false'
3333

3434
outputs:
35+
# The tag is derived purely from the dispatch input / git ref (see
36+
# workflow-setup-packaging.sh); it is independent of `format` and
37+
# `package-arch`. Callers that fan this action out across a matrix can
38+
# therefore rely on every leg emitting the same tag value.
3539
tag:
3640
description: 'Resolved package tag (e.g. v1.14.1 or v0.0.0-pr.<sha>)'
3741
value: ${{ steps.setup.outputs.tag }}

.github/packaging/nfpm/avalanchego-deb.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ depends:
99
- "libc6 (>= 2.35)"
1010
contents:
1111
- src: "${BINARY_PATH}"
12-
dst: /usr/local/bin/avalanchego
12+
# Debian Policy §9.1.2: packaged files must not live under /usr/local.
13+
# Keep this path in sync with .github/packaging/scripts/validate-deb.sh.
14+
dst: /usr/bin/avalanchego
1315
file_info:
1416
mode: 0755
1517
changelog: "${NFPM_CHANGELOG}"

.github/packaging/nfpm/subnet-evm-deb.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ depends:
99
- "libc6 (>= 2.35)"
1010
contents:
1111
- src: "${BINARY_PATH}"
12-
# SUBNET_EVM_VM_ID is sourced from graft/subnet-evm/scripts/constants.sh
13-
dst: /usr/local/lib/avalanchego/plugins/${SUBNET_EVM_VM_ID}
12+
# SUBNET_EVM_VM_ID is sourced from graft/subnet-evm/scripts/constants.sh.
13+
# Debian Policy §9.1.2: packaged files must not live under /usr/local.
14+
# Keep this path in sync with .github/packaging/scripts/validate-deb.sh.
15+
dst: /usr/lib/avalanchego/plugins/${SUBNET_EVM_VM_ID}
1416
file_info:
1517
mode: 0755
1618
changelog: "${NFPM_CHANGELOG}"

.github/packaging/scripts/build-package.sh

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ set -euo pipefail
1212
: "${NFPM_PACKAGER:?NFPM_PACKAGER must be set (rpm or deb)}"
1313

1414
NFPM_PACKAGER="${NFPM_PACKAGER,,}"
15-
pkg_format_upper="${NFPM_PACKAGER^^}"
1615

1716
REPO_ROOT="/build"
1817
PACKAGING_DIR="${REPO_ROOT}/.github/packaging"
@@ -31,7 +30,7 @@ export NFPM_CHANGELOG="${REPO_ROOT}/build/nfpm-changelog.yml"
3130
export NFPM_SIGNING_KEY="${REPO_ROOT}/build/gpg/signing-key.asc"
3231
GPG_KEY_FILE="${GPG_KEY_FILE:-}"
3332

34-
echo "=== Building ${PACKAGE} ${pkg_format_upper} for ${PACKAGE_ARCH} (tag: ${TAG}) ==="
33+
echo "=== Building ${PACKAGE} ${NFPM_PACKAGER^^} for ${PACKAGE_ARCH} (tag: ${TAG}) ==="
3534

3635
init_build_env
3736
build_binary "${PACKAGE}"
@@ -44,7 +43,7 @@ GPG_PUBLIC_KEY="${OUTPUT_DIR}/GPG-KEY-avalanchego"
4443
# nfpm reads the signing passphrase from a packager-specific env var
4544
# (NFPM_RPM_PASSPHRASE, NFPM_DEB_PASSPHRASE, ...); mirror our format-
4645
# agnostic GPG_KEY_PASSPHRASE into the name nfpm expects.
47-
nfpm_passphrase_var="NFPM_${pkg_format_upper}_PASSPHRASE"
46+
nfpm_passphrase_var="NFPM_${NFPM_PACKAGER^^}_PASSPHRASE"
4847
export "${nfpm_passphrase_var}=${GPG_KEY_PASSPHRASE:-}"
4948

5049
# Ephemeral keys use a known throwaway passphrase so local and CI builds
@@ -53,7 +52,7 @@ if [[ -z "${GPG_KEY_FILE}" ]]; then
5352
use_ephemeral_gpg_passphrase "${nfpm_passphrase_var}"
5453
fi
5554

56-
setup_gpg "${GPG_KEY_FILE}" "${GPG_PUBLIC_KEY}" "${pkg_format_upper}"
55+
setup_gpg "${GPG_KEY_FILE}" "${GPG_PUBLIC_KEY}" "${NFPM_PACKAGER^^}"
5756

5857
# ── Package with nfpm ─────────────────────────────────────────────
5958

@@ -68,4 +67,4 @@ run_nfpm_package \
6867
"${NFPM_PACKAGER}" \
6968
"${PKG_PATH}"
7069

71-
echo "${pkg_format_upper} built: ${PKG_PATH}"
70+
echo "${NFPM_PACKAGER^^} built: ${PKG_PATH}"

.github/packaging/scripts/validate-deb.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,11 @@ for UBUNTU_IMAGE in ubuntu:22.04 ubuntu:24.04; do
7070
dpkg -i "/debs/avalanchego-${TAG}-${PACKAGE_ARCH}.deb"
7171
dpkg -i "/debs/subnet-evm-${TAG}-${PACKAGE_ARCH}.deb"
7272
73+
# These install paths must match the nfpm `dst` values in
74+
# .github/packaging/nfpm/{avalanchego,subnet-evm}-deb.yml.
7375
bash /smoke-test.sh \
74-
/usr/local/bin/avalanchego \
75-
"/usr/local/lib/avalanchego/plugins/${SUBNET_EVM_VM_ID}" \
76+
/usr/bin/avalanchego \
77+
"/usr/lib/avalanchego/plugins/${SUBNET_EVM_VM_ID}" \
7678
"${GIT_COMMIT}"
7779
'
7880
done

.github/packaging/scripts/workflow-setup-packaging.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ OUTPUT="${GITHUB_OUTPUT:-/dev/stdout}"
2626
TAG_INPUT="${TAG_INPUT:-}"
2727

2828
if [[ -n "${TAG_INPUT}" ]]; then
29+
# Second layer behind the workflow's tag-existence gate: reject a malformed
30+
# dispatch input before it reaches the signing step. The strong "is this an
31+
# actual tag" check lives in build-linux-packages.yml (needs origin/network).
32+
if [[ ! "${TAG_INPUT}" =~ ^v[0-9] ]]; then
33+
echo "ERROR: TAG_INPUT '${TAG_INPUT}' must start with 'v<digit>' (e.g. v1.14.1)" >&2
34+
exit 1
35+
fi
2936
TAG="${TAG_INPUT}"
3037
elif [[ "${GITHUB_REF}" == refs/tags/* ]]; then
3138
TAG="${GITHUB_REF/refs\/tags\//}"

.github/workflows/build-linux-packages.yml

Lines changed: 70 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ on:
1818
paths:
1919
- ".github/packaging/**"
2020
- ".github/workflows/build-linux-packages.yml"
21-
- ".github/workflows/upload-pkg-s3.yml"
2221

2322
env:
2423
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
@@ -47,6 +46,11 @@ jobs:
4746
runs-on: ${{ matrix.runner }}
4847
permissions:
4948
contents: read
49+
# All four matrix legs resolve the same tag: the composite action derives
50+
# it only from the dispatch input / git ref (see workflow-setup-packaging.sh),
51+
# never from format or arch. The job output is therefore a last-writer-wins
52+
# race between legs, but every leg writes the identical value, so downstream
53+
# consumers (upload-debs-s3) read a stable tag regardless of which leg wins.
5054
outputs:
5155
tag: ${{ steps.build.outputs.tag }}
5256

@@ -55,6 +59,28 @@ jobs:
5559
with:
5660
ref: ${{ github.event.inputs.tag || github.ref }}
5761

62+
# Defense in depth: workflow_dispatch accepts an arbitrary ref, and non-PR
63+
# events import the real signing key. The overlay below replaces only
64+
# .github/packaging, so the repo-root build helpers and the graft tree still
65+
# run from the checked-out ref. Refuse to proceed unless the dispatched input
66+
# names an actual tag in origin (not a branch), so the key can never sign
67+
# arbitrary branch content.
68+
# tag-push events are already constrained to refs/tags/v* by the `on:` filter.
69+
- name: Assert dispatch input is a released tag
70+
if: github.event.inputs.tag
71+
env:
72+
TAG_INPUT: ${{ github.event.inputs.tag }}
73+
shell: bash
74+
run: |
75+
if [[ ! "${TAG_INPUT}" =~ ^v[0-9] ]]; then
76+
echo "ERROR: tag input '${TAG_INPUT}' must start with 'v<digit>' (e.g. v1.14.1)" >&2
77+
exit 1
78+
fi
79+
if ! git ls-remote --exit-code --tags origin "refs/tags/${TAG_INPUT}" >/dev/null; then
80+
echo "ERROR: '${TAG_INPUT}' is not a tag in origin; refusing to build/sign a non-tag ref" >&2
81+
exit 1
82+
fi
83+
5884
# When building an older tag via workflow_dispatch, the tag's
5985
# .github/packaging tree may be stale or absent. Replace it
6086
# wholesale with the workflow branch's version so that this build
@@ -88,35 +114,51 @@ jobs:
88114
gpg-passphrase: ${{ github.event_name != 'pull_request' && secrets.RPM_GPG_PASSPHRASE || '' }}
89115
release: ${{ github.event_name != 'pull_request' && 'true' || 'false' }}
90116

91-
# Release-only S3 upload. Delegates to the shared upload-pkg-s3
92-
# workflow so id-token: write stays scoped to that workflow's job —
93-
# never granted to a job that checks out a tag tree and runs
94-
# packaging scripts.
95-
upload-s3:
117+
# Release-only DEB S3 upload. Runs in its own job so id-token: write is
118+
# never granted to a job that checks out and executes PR-controlled
119+
# packaging scripts. RPM S3 publishing can land as a sibling job later.
120+
upload-debs-s3:
96121
needs: build
97122
if: (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) || github.event_name == 'workflow_dispatch'
123+
strategy:
124+
matrix:
125+
deb_arch: [amd64, arm64]
126+
runs-on: ubuntu-22.04
98127
permissions:
99128
id-token: write
100129
contents: read
101-
strategy:
102-
matrix:
103-
include:
104-
- pkg-format: deb
105-
arches: '["amd64","arm64"]'
106-
distros: jammy noble
107-
s3-prefix: linux/debs/ubuntu
108-
- pkg-format: rpm
109-
arches: '["x86_64","aarch64"]'
110-
distros: el9
111-
s3-prefix: linux/rpms/rhel
112-
uses: ./.github/workflows/upload-pkg-s3.yml
113-
with:
114-
pkg-format: ${{ matrix.pkg-format }}
115-
tag: ${{ needs.build.outputs.tag }}
116-
arches: ${{ matrix.arches }}
117-
packages: avalanchego subnet-evm
118-
distros: ${{ matrix.distros }}
119-
s3-prefix: ${{ matrix.s3-prefix }}
120-
secrets:
121-
AWS_ROLE_ARN: ${{ secrets.AWS_DEPLOY_SA_ROLE_ARN }}
122-
BUCKET: ${{ secrets.BUCKET }}
130+
131+
steps:
132+
- name: Download DEB artifacts
133+
uses: actions/download-artifact@v6
134+
with:
135+
name: debs-${{ matrix.deb_arch }}
136+
path: build/deb
137+
138+
- name: Configure AWS credentials
139+
uses: aws-actions/configure-aws-credentials@v6
140+
with:
141+
role-to-assume: ${{ secrets.AWS_DEPLOY_SA_ROLE_ARN }}
142+
role-session-name: githubrolesession
143+
aws-region: us-east-1
144+
145+
- name: Install aws cli
146+
run: |
147+
if ! command -v aws &>/dev/null; then
148+
sudo snap install aws-cli --classic
149+
fi
150+
151+
- name: Upload DEBs to S3
152+
env:
153+
TAG: ${{ needs.build.outputs.tag }}
154+
DEB_ARCH: ${{ matrix.deb_arch }}
155+
BUCKET: ${{ secrets.BUCKET }}
156+
run: |
157+
for release in jammy noble; do
158+
aws s3 cp "build/deb/avalanchego-${TAG}-${DEB_ARCH}.deb" \
159+
"s3://${BUCKET}/linux/debs/ubuntu/${release}/${DEB_ARCH}/"
160+
aws s3 cp "build/deb/subnet-evm-${TAG}-${DEB_ARCH}.deb" \
161+
"s3://${BUCKET}/linux/debs/ubuntu/${release}/${DEB_ARCH}/"
162+
aws s3 cp "build/deb/GPG-KEY-avalanchego" \
163+
"s3://${BUCKET}/linux/debs/ubuntu/${release}/"
164+
done

.github/workflows/upload-pkg-s3.yml

Lines changed: 0 additions & 111 deletions
This file was deleted.

RELEASING_README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,7 @@ The tag push triggers these workflows automatically:
359359
- `build-linux-packages.yml` - Linux RPM/DEB packages (matrix over `{rpm, deb}` and `{amd64, arm64}` via the
360360
`./.github/packaging/actions/build-package` composite action). On tag pushes, the `upload-debs-s3` job additionally
361361
publishes `.deb` packages to `linux/debs/ubuntu/{jammy,noble}/{arch}/` and `GPG-KEY-avalanchego` to
362-
`linux/debs/ubuntu/{jammy,noble}/`. The `upload-rpms-s3` job publishes `.rpm` packages to
363-
`linux/rpms/rhel/el9/{arch}/` and `GPG-KEY-avalanchego` to `linux/rpms/rhel/el9/`.
364-
The same per-arch `.deb` is published under both jammy and noble; it is not rebuilt per Ubuntu release.
362+
`linux/debs/ubuntu/{jammy,noble}/`.
365363
- `publish_docker_image.yml` - Docker images
366364

367365
Artifacts produced:

0 commit comments

Comments
 (0)