Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .github/packaging/Dockerfile.deb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Build container for DEB packaging of avalanchego and subnet-evm.
#
# Based on Ubuntu 22.04 (jammy, glibc 2.35) to match the DEB target distros.
# Source tree is bind-mounted at runtime, not COPY'd.
#
# Usage (via build-builder-image.sh with DOCKERFILE=Dockerfile.deb):
# DOCKERFILE=Dockerfile.deb .github/packaging/scripts/build-builder-image.sh
# docker run --rm -v .:/build -v ./build/deb:/output avalanchego-deb-builder ...

FROM ubuntu:22.04

ARG GO_VERSION=INVALID
ARG GO_CHECKSUM=INVALID
ARG TARGETARCH

ENV DEBIAN_FRONTEND=noninteractive

# Install build dependencies
# - build-essential: gcc and friends for cgo (CGO_ENABLED=1 in scripts/constants.sh)
# - gettext-base: envsubst for nfpm config template expansion
# - gnupg: GPG key handling (nfpm signs DEBs natively; no dpkg-sig or gpg-agent dance)
# - git: version detection in build scripts
# - ca-certificates: HTTPS for Go and nfpm downloads
# - curl, jq: tarball download and (potentially) metadata lookup
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
gettext-base \
gnupg \
git \
ca-certificates \
curl \
jq \
&& rm -rf /var/lib/apt/lists/*

# Install Go (with SHA256 verification)
RUN curl -fsSL -o /tmp/go.tar.gz \
"https://go.dev/dl/go${GO_VERSION}.linux-${TARGETARCH}.tar.gz" \
&& echo "${GO_CHECKSUM} /tmp/go.tar.gz" | sha256sum -c - \
&& tar -C /usr/local -xzf /tmp/go.tar.gz \
&& rm /tmp/go.tar.gz
ENV PATH="/usr/local/go/bin:${PATH}"

# Install nfpm (with SHA256 verification via checksums.txt)
ARG NFPM_VERSION=2.41.1
# nfpm releases use x86_64 and arm64 (not aarch64)
RUN case "${TARGETARCH}" in \
amd64) NFPM_ARCH="x86_64" ;; \
arm64) NFPM_ARCH="arm64" ;; \
*) echo "Unsupported arch: ${TARGETARCH}" && exit 1 ;; \
esac && \
NFPM_TARBALL="nfpm_${NFPM_VERSION}_Linux_${NFPM_ARCH}.tar.gz" && \
curl -fsSL -o /tmp/nfpm.tar.gz \
"https://github.com/goreleaser/nfpm/releases/download/v${NFPM_VERSION}/${NFPM_TARBALL}" && \
curl -fsSL -o /tmp/checksums.txt \
"https://github.com/goreleaser/nfpm/releases/download/v${NFPM_VERSION}/checksums.txt" && \
EXPECTED=$(grep " ${NFPM_TARBALL}$" /tmp/checksums.txt | awk '{print $1}') && \
echo "${EXPECTED} /tmp/nfpm.tar.gz" | sha256sum -c - && \
tar -C /usr/local/bin -xzf /tmp/nfpm.tar.gz nfpm && \
rm /tmp/nfpm.tar.gz /tmp/checksums.txt

WORKDIR /build
128 changes: 120 additions & 8 deletions .github/packaging/Taskfile.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# RPM packaging tasks for avalanchego and subnet-evm.
# Packaging tasks for avalanchego and subnet-evm (RPM and DEB).
#
# Builds RPMs inside a Rocky Linux 9 container (glibc 2.34) with GPG signing.
# RPMs build inside a Rocky Linux 9 container (glibc 2.34).
# DEBs build inside an Ubuntu 22.04 container (glibc 2.35).
# Both use nfpm for native signing — DEB has no post-build signing step.
# PACKAGING_TAG defaults to v0.0.0 for local testing; set for release builds.

version: '3'
Expand Down Expand Up @@ -28,8 +30,19 @@ vars:
# Default tag for local testing; overridden by CI for release builds.
PACKAGING_TAG:
sh: echo "${PACKAGING_TAG:-v0.0.0}"
# Map uname -m to DEB arch names (x86_64 -> amd64, arm64 stays arm64).
PACKAGING_HOST_DEB_ARCH:
sh: |
arch=$(uname -m)
case "${arch}" in
x86_64) echo "amd64" ;;
arm64|aarch64) echo "arm64" ;;
*) echo "${arch}" ;;
esac
PACKAGING_DOCKER_IMAGE: avalanchego-rpm-builder
PACKAGING_DEB_DOCKER_IMAGE: avalanchego-deb-builder
PACKAGING_OUTPUT_DIR: '{{.REPO_ROOT}}/build/rpm'
PACKAGING_DEB_OUTPUT_DIR: '{{.REPO_ROOT}}/build/deb'

tasks:
default:
Expand Down Expand Up @@ -60,22 +73,29 @@ tasks:
PACKAGE_ARCH: '{{.PACKAGE_ARCH | default .PACKAGING_HOST_ARCH}}'
RPM_TAG: '{{.PACKAGING_TAG}}'
deps: [build-builder-docker-image]
# Secrets are promoted to the task process env via YAML literals, then
# passed to docker via `-e VAR` (pass-through). Never interpolate them
# into the docker run command — values with whitespace or shell
# metacharacters would be split/expanded before docker sees them.
env:
PKG_GPG_KEY_FILE: '{{.PKG_GPG_KEY_FILE | default ""}}'
NFPM_RPM_PASSPHRASE: '{{.NFPM_RPM_PASSPHRASE | default ""}}'
cmds:
- cmd: mkdir -p {{.PACKAGING_OUTPUT_DIR}}
- cmd: >-
docker run --rm
-v {{.REPO_ROOT}}:/build
-v {{.PACKAGING_OUTPUT_DIR}}:/output
{{if .RPM_GPG_KEY_FILE}}-v {{.RPM_GPG_KEY_FILE}}:{{.RPM_GPG_KEY_FILE}}:ro{{end}}
${PKG_GPG_KEY_FILE:+-v "${PKG_GPG_KEY_FILE}:${PKG_GPG_KEY_FILE}:ro"}
-e PKG_FORMAT=RPM
-e PACKAGE=avalanchego
-e VERSION={{trimPrefix "v" .RPM_TAG}}
-e TAG={{.RPM_TAG}}
-e PACKAGE_ARCH={{.PACKAGE_ARCH}}
-e OUTPUT_DIR=/output
-e AVALANCHEGO_COMMIT={{.PACKAGING_GIT_COMMIT}}
{{if .RPM_GPG_KEY_FILE}}-e RPM_GPG_KEY_FILE={{.RPM_GPG_KEY_FILE}}{{end}}
{{if .NFPM_RPM_PASSPHRASE}}-e NFPM_RPM_PASSPHRASE={{.NFPM_RPM_PASSPHRASE}}{{end}}
-e PKG_GPG_KEY_FILE
-e NFPM_RPM_PASSPHRASE
{{.PACKAGING_DOCKER_IMAGE}}
.github/packaging/scripts/build-package.sh

Expand All @@ -85,22 +105,25 @@ tasks:
PACKAGE_ARCH: '{{.PACKAGE_ARCH | default .PACKAGING_HOST_ARCH}}'
RPM_TAG: '{{.PACKAGING_TAG}}'
deps: [build-builder-docker-image]
env:
PKG_GPG_KEY_FILE: '{{.PKG_GPG_KEY_FILE | default ""}}'
NFPM_RPM_PASSPHRASE: '{{.NFPM_RPM_PASSPHRASE | default ""}}'
cmds:
- cmd: mkdir -p {{.PACKAGING_OUTPUT_DIR}}
- cmd: >-
docker run --rm
-v {{.REPO_ROOT}}:/build
-v {{.PACKAGING_OUTPUT_DIR}}:/output
{{if .RPM_GPG_KEY_FILE}}-v {{.RPM_GPG_KEY_FILE}}:{{.RPM_GPG_KEY_FILE}}:ro{{end}}
${PKG_GPG_KEY_FILE:+-v "${PKG_GPG_KEY_FILE}:${PKG_GPG_KEY_FILE}:ro"}
-e PKG_FORMAT=RPM
-e PACKAGE=subnet-evm
-e VERSION={{trimPrefix "v" .RPM_TAG}}
-e TAG={{.RPM_TAG}}
-e PACKAGE_ARCH={{.PACKAGE_ARCH}}
-e OUTPUT_DIR=/output
-e AVALANCHEGO_COMMIT={{.PACKAGING_GIT_COMMIT}}
{{if .RPM_GPG_KEY_FILE}}-e RPM_GPG_KEY_FILE={{.RPM_GPG_KEY_FILE}}{{end}}
{{if .NFPM_RPM_PASSPHRASE}}-e NFPM_RPM_PASSPHRASE={{.NFPM_RPM_PASSPHRASE}}{{end}}
-e PKG_GPG_KEY_FILE
-e NFPM_RPM_PASSPHRASE
{{.PACKAGING_DOCKER_IMAGE}}
.github/packaging/scripts/build-package.sh

Expand All @@ -117,3 +140,92 @@ tasks:
GIT_COMMIT: '{{.PACKAGING_GIT_COMMIT}}'
cmds:
- cmd: '{{.REPO_ROOT}}/.github/packaging/scripts/validate-rpm.sh'

# ── DEB packaging tasks ──────────────────────────────────────────

build-debs:
desc: Builds DEBs for both avalanchego and subnet-evm
cmds:
- task: build-avalanchego-deb
- task: build-subnet-evm-deb

build-deb-builder-docker-image:
desc: Builds the DEB builder Docker image
internal: true
env:
GO_VERSION: '{{.PACKAGING_GO_VERSION}}'
DOCKER_IMAGE: '{{.PACKAGING_DEB_DOCKER_IMAGE}}'
CONTEXT_DIR: '{{.REPO_ROOT}}/.github/packaging'
DOCKERFILE: Dockerfile.deb
cmds:
- cmd: '{{.REPO_ROOT}}/.github/packaging/scripts/build-builder-image.sh'

build-avalanchego-deb:
desc: Builds DEB for avalanchego
vars:
PACKAGE_ARCH: '{{.PACKAGE_ARCH | default .PACKAGING_HOST_DEB_ARCH}}'
DEB_TAG: '{{.PACKAGING_TAG}}'
deps: [build-deb-builder-docker-image]
env:
PKG_GPG_KEY_FILE: '{{.PKG_GPG_KEY_FILE | default ""}}'
NFPM_DEB_PASSPHRASE: '{{.NFPM_DEB_PASSPHRASE | default ""}}'
cmds:
- cmd: mkdir -p {{.PACKAGING_DEB_OUTPUT_DIR}}
- cmd: >-
docker run --rm
-v {{.REPO_ROOT}}:/build
-v {{.PACKAGING_DEB_OUTPUT_DIR}}:/output
${PKG_GPG_KEY_FILE:+-v "${PKG_GPG_KEY_FILE}:${PKG_GPG_KEY_FILE}:ro"}
-e PKG_FORMAT=DEB
-e PACKAGE=avalanchego
-e VERSION={{trimPrefix "v" .DEB_TAG}}
-e TAG={{.DEB_TAG}}
-e PACKAGE_ARCH={{.PACKAGE_ARCH}}
-e OUTPUT_DIR=/output
-e AVALANCHEGO_COMMIT={{.PACKAGING_GIT_COMMIT}}
-e PKG_GPG_KEY_FILE
-e NFPM_DEB_PASSPHRASE
{{.PACKAGING_DEB_DOCKER_IMAGE}}
.github/packaging/scripts/build-package.sh

build-subnet-evm-deb:
desc: Builds DEB for subnet-evm
vars:
PACKAGE_ARCH: '{{.PACKAGE_ARCH | default .PACKAGING_HOST_DEB_ARCH}}'
DEB_TAG: '{{.PACKAGING_TAG}}'
deps: [build-deb-builder-docker-image]
env:
PKG_GPG_KEY_FILE: '{{.PKG_GPG_KEY_FILE | default ""}}'
NFPM_DEB_PASSPHRASE: '{{.NFPM_DEB_PASSPHRASE | default ""}}'
cmds:
- cmd: mkdir -p {{.PACKAGING_DEB_OUTPUT_DIR}}
- cmd: >-
docker run --rm
-v {{.REPO_ROOT}}:/build
-v {{.PACKAGING_DEB_OUTPUT_DIR}}:/output
${PKG_GPG_KEY_FILE:+-v "${PKG_GPG_KEY_FILE}:${PKG_GPG_KEY_FILE}:ro"}
-e PKG_FORMAT=DEB
-e PACKAGE=subnet-evm
-e VERSION={{trimPrefix "v" .DEB_TAG}}
-e TAG={{.DEB_TAG}}
-e PACKAGE_ARCH={{.PACKAGE_ARCH}}
-e OUTPUT_DIR=/output
-e AVALANCHEGO_COMMIT={{.PACKAGING_GIT_COMMIT}}
-e PKG_GPG_KEY_FILE
-e NFPM_DEB_PASSPHRASE
{{.PACKAGING_DEB_DOCKER_IMAGE}}
.github/packaging/scripts/build-package.sh

test-build-debs:
desc: Builds and validates DEBs end-to-end
cmds:
- task: build-debs
- task: validate-debs

validate-debs:
desc: Validates built DEBs by installing and smoke testing in fresh containers
env:
TAG: '{{.PACKAGING_TAG}}'
GIT_COMMIT: '{{.PACKAGING_GIT_COMMIT}}'
cmds:
- cmd: '{{.REPO_ROOT}}/.github/packaging/scripts/validate-deb.sh'
24 changes: 24 additions & 0 deletions .github/packaging/nfpm/avalanchego-deb.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: avalanchego
arch: "${PACKAGE_ARCH}"
version: "${VERSION}"
maintainer: "Ava Labs <[email protected]>"
description: "AvalancheGo node — the official Avalanche protocol implementation"
homepage: "https://github.com/ava-labs/avalanchego"
license: "BSD-3-Clause"
depends:
- "libc6 (>= 2.35)"
contents:
- src: "${BINARY_PATH}"
# DEB install path stays /usr/local/bin for backward compatibility with
# existing DEB consumers; the RPM path is /var/opt/avalanchego/bin.
dst: /usr/local/bin/avalanchego
expand: true
file_info:
mode: 0755
changelog: "${NFPM_CHANGELOG}"
deb:
compression: gzip
signature:
key_file: "${NFPM_SIGNING_KEY}"
method: debsign
type: origin
24 changes: 24 additions & 0 deletions .github/packaging/nfpm/subnet-evm-deb.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: subnet-evm
arch: "${PACKAGE_ARCH}"
version: "${VERSION}"
maintainer: "Ava Labs <[email protected]>"
description: "Subnet-EVM plugin for AvalancheGo"
homepage: "https://github.com/ava-labs/avalanchego"
license: "BSD-3-Clause"
depends:
- "libc6 (>= 2.35)"
contents:
- src: "${BINARY_PATH}"
# SUBNET_EVM_VM_ID is sourced from graft/subnet-evm/scripts/constants.sh
# DEB plugin path differs from RPM (/var/opt/...) to match /usr/local/bin/avalanchego
dst: /usr/local/lib/avalanchego/plugins/${SUBNET_EVM_VM_ID}
expand: true
file_info:
mode: 0755
changelog: "${NFPM_CHANGELOG}"
deb:
compression: gzip
signature:
key_file: "${NFPM_SIGNING_KEY}"
method: debsign
type: origin
17 changes: 9 additions & 8 deletions .github/packaging/scripts/build-package.sh
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
#!/usr/bin/env bash

# Build and sign an RPM package inside the container.
# Build and sign a package (RPM or DEB) inside the container.
#
# Required env vars:
# PACKAGE - "avalanchego" or "subnet-evm"
# VERSION - Semantic version without "v" prefix (e.g., "1.14.1")
# TAG - Git tag (e.g., "v1.14.1")
# PACKAGE_ARCH - Architecture (x86_64 or aarch64)
# PACKAGE_ARCH - Architecture (x86_64/aarch64 for RPM, amd64/arm64 for DEB)
# OUTPUT_DIR - Directory for the output package (bind-mounted from host)
#
# Optional env vars:
# PKG_FORMAT - Package format identifier (default: RPM)
# RPM_GPG_KEY_FILE - Path to GPG private key
# NFPM_RPM_PASSPHRASE - GPG passphrase
# PKG_FORMAT - Package format identifier ("RPM" or "DEB"; default: RPM)
# PKG_GPG_KEY_FILE - Path to GPG private key
# NFPM_RPM_PASSPHRASE - GPG passphrase for RPM signing (read by nfpm)
# NFPM_DEB_PASSPHRASE - GPG passphrase for DEB signing (read by nfpm)
# AVALANCHEGO_COMMIT - Git commit hash (auto-detected if not set)

set -euo pipefail
Expand Down Expand Up @@ -44,14 +45,14 @@ generate_changelog "${VERSION}"

# ── GPG signing ───────────────────────────────────────────────────

GPG_KEY_FILE="${RPM_GPG_KEY_FILE:-}"
GPG_KEY_FILE="${PKG_GPG_KEY_FILE:-}"
GPG_PUBLIC_KEY="${OUTPUT_DIR}/${PKG_FORMAT}-GPG-KEY-avalanchego"

setup_gpg "${GPG_KEY_FILE}" "${GPG_PUBLIC_KEY}" "${PKG_FORMAT}"

# Ephemeral keys have no passphrase; nfpm needs the variable set empty
# Ephemeral keys have no passphrase; nfpm reads NFPM_<FORMAT>_PASSPHRASE
if [[ -z "${GPG_KEY_FILE}" ]]; then
export NFPM_RPM_PASSPHRASE=""
export "NFPM_${PKG_FORMAT}_PASSPHRASE="
fi

# ── Package with nfpm ─────────────────────────────────────────────
Expand Down
24 changes: 19 additions & 5 deletions .github/packaging/scripts/lib-build-common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,27 @@ build_binary() {
echo "Binary built at: ${BINARY_PATH}"
}

# Resolve the subnet-evm VM ID from the canonical constants file.
# Resolve the subnet-evm VM ID.
#
# Prefers the pure-data file (default-vm-data.sh). Falls back to grepping
# DEFAULT_VM_ID from constants.sh for older tags pre-dating the data-file
# split — workflow_dispatch on those tags only overlays .github/packaging,
# so the data file is not present in the checkout.
#
# Sets SUBNET_EVM_VM_ID (global) as a side effect.
resolve_subnet_evm_vm_id() {
# shellcheck disable=SC1091
source "${REPO_ROOT}/graft/subnet-evm/scripts/default-vm-data.sh"
# shellcheck disable=SC2154
: "${DEFAULT_VM_ID:?DEFAULT_VM_ID must be set by default-vm-data.sh}"
local data_file="${REPO_ROOT}/graft/subnet-evm/scripts/default-vm-data.sh"
local constants_file="${REPO_ROOT}/graft/subnet-evm/scripts/constants.sh"
if [[ -f "${data_file}" ]]; then
# shellcheck disable=SC1091
source "${data_file}"
# shellcheck disable=SC2154
: "${DEFAULT_VM_ID:?DEFAULT_VM_ID must be set by default-vm-data.sh}"
else
# Older tags: DEFAULT_VM_ID is a literal assignment in constants.sh.
DEFAULT_VM_ID=$(grep '^DEFAULT_VM_ID=' "${constants_file}" | cut -d'"' -f2)
: "${DEFAULT_VM_ID:?DEFAULT_VM_ID not found in default-vm-data.sh or constants.sh}"
fi
export SUBNET_EVM_VM_ID="${DEFAULT_VM_ID}"
}

Expand Down
Loading
Loading