Skip to content
Merged
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
58 changes: 47 additions & 11 deletions .github/workflows/release-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,52 @@ on:
jobs:
releases:
name: Releases
runs-on: ubuntu-24.04
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
target:
- 'bin-Fedora'
- 'bin-Ubuntu-jammy'
- 'bin-Ubuntu-noble'
- 'bin-Ubuntu-resolute'
# dir is where build-release.sh puts the target's output; arch picks
# the merged artifact, since each architecture is checksummed and
# signed separately.
include:
- { target: 'bin-Fedora', runner: 'ubuntu-24.04', arch: 'amd64', dir: 'release' }
- { target: 'bin-Ubuntu-jammy', runner: 'ubuntu-24.04', arch: 'amd64', dir: 'release' }
- { target: 'bin-Ubuntu-noble', runner: 'ubuntu-24.04', arch: 'amd64', dir: 'release' }
- { target: 'bin-Ubuntu-resolute', runner: 'ubuntu-24.04', arch: 'amd64', dir: 'release' }
# arm64 builds natively on an arm64 runner.
- { target: 'bin-Ubuntu-jammy-arm64', runner: 'ubuntu-24.04-arm', arch: 'arm64', dir: 'release-arm64' }
- { target: 'bin-Ubuntu-noble-arm64', runner: 'ubuntu-24.04-arm', arch: 'arm64', dir: 'release-arm64' }
- { target: 'bin-Ubuntu-resolute-arm64', runner: 'ubuntu-24.04-arm', arch: 'arm64', dir: 'release-arm64' }
# armv7 cross-compiles in the amd64 builder image (see
# tools/repro-build.armv7.sh), with qemu for the few armv7 programs
# the build runs.
- { target: 'bin-Ubuntu-jammy-armv7', runner: 'ubuntu-24.04', arch: 'armv7', dir: 'release-armv7' }
- { target: 'bin-Ubuntu-noble-armv7', runner: 'ubuntu-24.04', arch: 'armv7', dir: 'release-armv7' }
- { target: 'bin-Ubuntu-resolute-armv7', runner: 'ubuntu-24.04', arch: 'armv7', dir: 'release-armv7' }
steps:
- name: Git checkout
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Set up QEMU
uses: docker/setup-qemu-action@v4
with:
platforms: arm
if: endsWith(matrix.target, '-armv7')

- name: Build environment setup
run: |
distribution=$(echo ${{ matrix.target }} | cut -d'-' -f3)
# Same naming as contrib/cl-repro.sh: arm64 images are suffixed.
suffix=""
[ "$(dpkg --print-architecture)" = arm64 ] && suffix="-arm64"
sudo docker run --rm -v $(pwd):/build ubuntu:${distribution} bash -c "\
apt-get update && \
apt-get install -y debootstrap && \
debootstrap ${distribution} /build/${distribution}"
sudo tar -C ${distribution} -c . | docker import - ${distribution}
docker build -t cl-repro-${distribution} - < contrib/reprobuild/Dockerfile.${distribution}
docker build -t cl-repro-${distribution}${suffix} - < contrib/reprobuild/Dockerfile.${distribution}
if: contains(matrix.target, 'Ubuntu')

- name: Build release
Expand All @@ -53,18 +75,32 @@ jobs:
- name: Upload target artifacts
uses: actions/upload-artifact@v7
with:
path: release/
name: ${{ matrix.target }}
path: ${{ matrix.dir }}/
name: ${{ matrix.arch }}-${{ matrix.target }}
if-no-files-found: error

artifact:
name: Construct release artifact
needs: releases
runs-on: ubuntu-24.04
steps:
- name: Merge artifacts
- name: Merge amd64 artifacts
uses: actions/upload-artifact/merge@v7
with:
name: c-lightning-${{ inputs.version }}
pattern: bin-*
pattern: amd64-bin-*
delete-merged: true

- name: Merge arm64 artifacts
uses: actions/upload-artifact/merge@v7
with:
name: c-lightning-${{ inputs.version }}-arm64
pattern: arm64-bin-*
delete-merged: true

- name: Merge armv7 artifacts
uses: actions/upload-artifact/merge@v7
with:
name: c-lightning-${{ inputs.version }}-armv7
pattern: armv7-bin-*
delete-merged: true
63 changes: 54 additions & 9 deletions .github/workflows/release-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ jobs:
name: c-lightning-${{ inputs.version }}
path: release/

- name: Download arm64 artifact
uses: actions/download-artifact@v8
with:
name: c-lightning-${{ inputs.version }}-arm64
path: release-arm64/

- name: Download armv7 artifact
uses: actions/download-artifact@v8
with:
name: c-lightning-${{ inputs.version }}-armv7
path: release-armv7/

- name: Import GPG keys
id: gpg
uses: crazy-max/ghaction-import-gpg@v7
Expand All @@ -40,7 +52,15 @@ jobs:
run: echo "default-key $GPG_KEYID" >> ~/.gnupg/gpg.conf

- name: Sign release
run: tools/build-release.sh --without-zip sign
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
tools/build-release.sh --without-zip sign
for arch in arm64 armv7; do
tools/sign-release-arm.sh "$INPUT_VERSION" "$arch"
# Their manifests and signatures sit next to the amd64 ones.
mv release-"$arch"/SHA256SUMS-* release/
done

- name: Upload signed artifact
uses: actions/upload-artifact@v7
Expand All @@ -49,6 +69,20 @@ jobs:
overwrite: true
path: release/

- name: Upload arm64 artifact
uses: actions/upload-artifact@v7
with:
name: c-lightning-${{ inputs.version }}-arm64
overwrite: true
path: release-arm64/

- name: Upload armv7 artifact
uses: actions/upload-artifact@v7
with:
name: c-lightning-${{ inputs.version }}-armv7
overwrite: true
path: release-armv7/

- name: Determine release data
id: release_data
env:
Expand All @@ -60,13 +94,24 @@ jobs:
RELEASE_TITLE=$(echo $CHANGELOG_TITLE | cut -d'"' -f2)
echo "release_title=$RELEASE_TITLE" >> "$GITHUB_OUTPUT"

# Never replace what is already on the release: release captains add
# their signatures to the .asc files by hand, and a re-run must keep
# them. tools/publish-release-assets.sh uploads only missing files,
# refuses any that differ from the published copy, and appends our
# signature to an existing .asc instead of overwriting it.
- name: Prepare release draft
if: ${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.create_release) }}
uses: softprops/action-gh-release@v3
with:
name: "${{ inputs.version }} ${{ steps.release_data.outputs.release_title }}"
tag_name: ${{ inputs.version }}
draft: true
prerelease: contains(inputs.version, "-rc")
files: release/*
fail_on_unmatched_files: true
env:
GH_TOKEN: ${{ github.token }}
INPUT_VERSION: ${{ inputs.version }}
RELEASE_TITLE: ${{ steps.release_data.outputs.release_title }}
run: |
if ! gh release view "$INPUT_VERSION" >/dev/null 2>&1; then
PRERELEASE=""
case "$INPUT_VERSION" in *-rc*) PRERELEASE=--prerelease;; esac
# --target only matters for an untagged test run: gh then
# creates the tag, as the previous upload action did.
gh release create "$INPUT_VERSION" --draft --target "$GITHUB_SHA" $PRERELEASE \
--title "$INPUT_VERSION $RELEASE_TITLE" --notes ""
fi
tools/publish-release-assets.sh "$INPUT_VERSION" release/* release-arm64/* release-armv7/*
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ jammy/
noble/
resolute/
release/
release-arm64/
release-armv7/
.vscode/
.cache/

Expand Down
4 changes: 2 additions & 2 deletions cln-rpc/Makefile
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
cln-rpc-wrongdir:
$(MAKE) -C .. cln-rpc-all

CLN_RPC_EXAMPLES := target/${RUST_PROFILE}/examples/cln-rpc-getinfo
CLN_RPC_EXAMPLES := $(RUST_TARGET_DIR)/examples/cln-rpc-getinfo
CLN_RPC_GENALL = cln-rpc/src/model.rs cln-rpc/src/notifications.rs cln-rpc/src/hooks.rs
CLN_RPC_SOURCES = $(shell find cln-rpc -name *.rs) ${CLN_RPC_GENALL}
DEFAULT_TARGETS += $(CLN_RPC_EXAMPLES) $(CLN_RPC_GENALL)

MSGGEN_GENALL += $(CLN_RPC_GENALL)

target/${RUST_PROFILE}/examples/cln-rpc-getinfo: ${CLN_RPC_SOURCES} cln-rpc/examples/getinfo.rs
$(RUST_TARGET_DIR)/examples/cln-rpc-getinfo: ${CLN_RPC_SOURCES} cln-rpc/examples/getinfo.rs
$(CARGO) build ${CARGO_OPTS} --example cln-rpc-getinfo

cln-rpc-all: ${CLN_RPC_GENALL} ${CLN_RPC_EXAMPLES}
6 changes: 5 additions & 1 deletion contrib/cl-repro.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ for v in jammy noble resolute; do
echo "$v release:"
sudo docker run ubuntu:$v cat /etc/lsb-release
echo "Building CL repro $v:"
# arm64 images are suffixed so both architectures can coexist, and so the
# bin-Ubuntu-<dist>-arm64 targets resolve. amd64 keeps its bare name.
SUFFIX=""
[ "$(dpkg --print-architecture)" = arm64 ] && SUFFIX="-arm64"
# shellcheck disable=SC2024
sudo docker build --no-cache -t cl-repro-$v - < "$LIGHTNING_DIR"/contrib/reprobuild/Dockerfile.$v
sudo docker build --no-cache -t cl-repro-$v$SUFFIX - < "$LIGHTNING_DIR"/contrib/reprobuild/Dockerfile.$v
done
14 changes: 12 additions & 2 deletions contrib/reprobuild/Dockerfile.jammy
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,15 @@ WORKDIR /build
# that we no longer take the zipfile.
CMD git clone /repo . \
&& uv sync --all-extras --all-groups \
&& uv run tools/repro-build.sh \
&& cp *.xz /repo/release/
&& if [ "$REPRO_ARCH" = armv7 ]; then \
uv run tools/repro-build.armv7.sh \
&& mkdir -p /repo/release-armv7 \
&& cp *.xz /repo/release-armv7/; \
elif [ "$(dpkg --print-architecture)" = arm64 ]; then \
uv run tools/repro-build.arm64.sh \
&& mkdir -p /repo/release-arm64 \
&& cp *.xz /repo/release-arm64/; \
else \
uv run tools/repro-build.sh \
&& cp *.xz /repo/release/; \
fi
14 changes: 12 additions & 2 deletions contrib/reprobuild/Dockerfile.noble
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,15 @@ WORKDIR /build
# that we no longer take the zipfile.
CMD git clone /repo . \
&& uv sync --all-extras --all-groups \
&& uv run tools/repro-build.sh \
&& cp *.xz /repo/release/
&& if [ "$REPRO_ARCH" = armv7 ]; then \
uv run tools/repro-build.armv7.sh \
&& mkdir -p /repo/release-armv7 \
&& cp *.xz /repo/release-armv7/; \
elif [ "$(dpkg --print-architecture)" = arm64 ]; then \
uv run tools/repro-build.arm64.sh \
&& mkdir -p /repo/release-arm64 \
&& cp *.xz /repo/release-arm64/; \
else \
uv run tools/repro-build.sh \
&& cp *.xz /repo/release/; \
fi
14 changes: 12 additions & 2 deletions contrib/reprobuild/Dockerfile.resolute
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,15 @@ WORKDIR /build
# that we no longer take the zipfile.
CMD git clone /repo . \
&& uv sync --all-extras --all-groups \
&& uv run tools/repro-build.sh \
&& cp *.xz /repo/release/
&& if [ "$REPRO_ARCH" = armv7 ]; then \
uv run tools/repro-build.armv7.sh \
&& mkdir -p /repo/release-armv7 \
&& cp *.xz /repo/release-armv7/; \
elif [ "$(dpkg --print-architecture)" = arm64 ]; then \
uv run tools/repro-build.arm64.sh \
&& mkdir -p /repo/release-arm64 \
&& cp *.xz /repo/release-arm64/; \
else \
uv run tools/repro-build.sh \
&& cp *.xz /repo/release/; \
fi
4 changes: 2 additions & 2 deletions doc/contribute-to-core-lightning/release-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Here's a checklist for the release process.
3. Confirm that the tag will show up for builds with `git describe`. We don't push it to GitHub yet, just in case the following steps fail, and more fixes are required!
4. Run `contrib/cl-repro.sh` to generate the required `cl-repro-<codename>` builder images for the reproducible build environment.
5. Execute `tools/build-release.sh bin-Fedora bin-Ubuntu sign` to locally reproduce the release, generating a matching `SHA256SUMS-v<VERSION>` file and signing it with your GPG key.
6. Push the tag to trigger the "Release 🚀" CI action, which drafts a new `v<VERSION>rc1` pre-release on GitHub and uploads reproducible builds alongside the `SHA256SUMS-v<VERSION>` file and its signature from the `cln@blockstream.com` key.
6. Push the tag to trigger the "Release 🚀" CI action, which drafts a new `v<VERSION>rc1` pre-release on GitHub and uploads reproducible builds alongside the `SHA256SUMS-v<VERSION>` file and its signature from the `cln@blockstream.com` key. The arm64 and armv7 tarballs each come with their own manifest, `SHA256SUMS-v<VERSION>-arm64` and `SHA256SUMS-v<VERSION>-armv7`, and its `.asc`. The CI never replaces a file already on the release: re-running it only adds missing files, and appends its signature to an `.asc` that already has yours.
7. Verify your local `SHA256SUMS-v<VERSION>` file matches the one in the draft release, then append your local signatures to the release's `SHA256SUMS-v<VERSION>.asc` file to attest to the build's integrity.
8. Announce rc1 release on core-lightning's release-chat channel on Discord & Telegram.
9. Use `devtools/credit --markdown v<PREVIOUS-VERSION>` to generate a single contributor list for the release notes. Use `devtools/credit --verbose v<PREVIOUS-VERSION>` for namer selection and detailed annotations.
Expand Down Expand Up @@ -119,7 +119,7 @@ Here's a checklist for the release process.
5. Create a new commit that includes the updates from `update-versions` and `CHANGELOG.md`.
6. Tag the release with `git pull && git tag -s v<VERSION>.<POINT_VERSION>`. You will be prompted to enter a tag message, ensure this is filled out.
7. Confirm that the tag is properly set up for builds by running `git describe`.
8. Trigger the pre-release by pushing the version tag with `git push origin v<VERSION>.<POINT_VERSION>`; the CI will handle drafting the release and uploading the initial signed checksums.
8. Trigger the pre-release by pushing the version tag with `git push origin v<VERSION>.<POINT_VERSION>`; the CI will handle drafting the release and uploading the initial signed checksums, for amd64 (`SHA256SUMS-v<VERSION>`), arm64 (`SHA256SUMS-v<VERSION>-arm64`) and armv7 (`SHA256SUMS-v<VERSION>-armv7`).
9. Generate the required builder images by running `contrib/cl-repro.sh`.
10. Sign the release locally by running `tools/build-release.sh bin-Fedora bin-Ubuntu sign` which will sign the release contents and create `SHA256SUMS-v<VERSION>` and `SHA256SUMS-v<VERSION>.asc` in the release folder.
11. Validate that your local checksums `SHA256SUMS-v<VERSION>` match the Draft release's, then add your signatures to the draft release's signature `SHA256SUMS-v<VERSION>.asc` file.
Expand Down
16 changes: 16 additions & 0 deletions doc/getting-started/advanced-setup/repro.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,22 @@ ee83cf4948228ab1f644dbd9d28541fd8ef7c453a3fec90462b08371a8686df8 /repo/release/

Repeat this step for each distribution and each architecture you wish to sign. Once all the binaries are in the `release/` subdirectory we can sign the hashes.

## ARM builds (arm64 and armv7)

Each ARM architecture has its own manifest and signatures: `SHA256SUMS-v<VERSION>-arm64` / `.asc` and `SHA256SUMS-v<VERSION>-armv7` / `.asc`. They are separate because they are reproduced differently (arm64 natively, armv7 cross-compiled), so you can verify and co-sign one without the other. Their output goes to `release-arm64/` and `release-armv7/`, not `release/`, so the manifests never mix.

- **arm64** builds natively, on an arm64 machine. Running `contrib/cl-repro.sh` there creates the builder images as `cl-repro-<codename>-arm64`, and `tools/build-release.sh bin-Ubuntu-<codename>-arm64` (or `docker run --rm -v $(pwd):/repo -ti cl-repro-<codename>-arm64`) builds the tarball using the pinned packages in `tools/repro-build.arm64.sh`.
- **armv7** is cross-compiled on an amd64 machine, in the same `cl-repro-<codename>` image as the amd64 build, using the pinned toolchain and armhf libraries in `tools/repro-build.armv7.sh`. The build runs a few armv7 programs, so register qemu with the kernel first (once per boot):

```shell
docker run --privileged --rm tonistiigi/binfmt --install arm
tools/build-release.sh bin-Ubuntu-noble-armv7
# or directly:
docker run --rm -v $(pwd):/repo -e REPRO_ARCH=armv7 -ti cl-repro-noble
```

Once the tarballs are built, `tools/sign-release-arm.sh v<VERSION> arm64` (or `armv7`) creates and signs `SHA256SUMS-v<VERSION>-arm64` (or `-armv7`).

# Signing the release manifest

The release captain is in charge of creating the manifest, whereas contributors and interested bystanders may contribute their signatures to further increase trust in the binaries.
Expand Down
30 changes: 28 additions & 2 deletions tools/build-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,23 @@ fi

TARGETS=${TARGETS:-$ALL_TARGETS}

RELEASEDIR="$(pwd)/release"
# ARM targets get their own release directory per architecture
# (release-arm64/, release-armv7/), and never build the zip: the zip is
# architecture-independent, and its block unconditionally removes release/'s
# copy before rebuilding it from the current HEAD.
case "$TARGETS" in
*-arm64*)
RELEASEDIR="$(pwd)/release-arm64"
WITHOUT_ZIP=true
;;
*-armv7*)
RELEASEDIR="$(pwd)/release-armv7"
WITHOUT_ZIP=true
;;
*)
RELEASEDIR="$(pwd)/release"
;;
esac
BARE_VERSION="$(echo "${VERSION}" | sed 's/^v//g')"
TARBALL="${RELEASEDIR}/lightningd_${BARE_VERSION}.orig.tar.bz2"
DATE=$(date +%Y%m%d%H%M%S)
Expand Down Expand Up @@ -203,7 +219,17 @@ for target in $TARGETS; do
# Capitalize the first letter of distro
D=$(echo "$d" | awk '{print toupper(substr($0,1,1))substr($0,2)}')
echo "Building Ubuntu $D Image"
docker run --rm -v "$(pwd)":/repo -e FORCE_MTIME="$MTIME" -e FORCE_VERSION="$VERSION" -e MAKEPAR="$MAKEPAR" cl-repro-"$d"
# armv7 is cross-compiled in the amd64 builder image; arm64
# builds natively in its own cl-repro-<dist>-arm64 image.
IMAGE=cl-repro-"$d"
REPRO_ARCH=""
case "$d" in
*-armv7)
IMAGE=cl-repro-"${d%-armv7}"
REPRO_ARCH=armv7
;;
esac
docker run --rm -v "$(pwd)":/repo -e FORCE_MTIME="$MTIME" -e FORCE_VERSION="$VERSION" -e MAKEPAR="$MAKEPAR" -e REPRO_ARCH="$REPRO_ARCH" "$IMAGE"
echo "Ubuntu $D Image Built"
done
;;
Expand Down
Loading
Loading