Skip to content

Commit 37c8311

Browse files
authored
Merge the "release/v2.2.0+node25.9.0" branch into the "maintenance/v2+node25" branch
This merge promotes `release/v2.2.0+node25.9.0` into `maintenance/v2+node25`, marking the next minor release on the Node.js 25 maintenance line. It consolidates five development cycles: the Node.js base image bump from `25.8.2` to `25.9.0`, the PR test workflow move from Docker Hub-pushed images to OCI artifact handoff, the `docker/build-push-action` upgrade to `v7` in both workflows, the release workflow attestation update to signed `mode=max` provenance and SBOM output, and documentation updates aligning examples and CI/CD tooling references with the current release state. In `Dockerfile`, the builder stage base image is updated from `node:25.8.2-alpine3.23` to `node:25.9.0-alpine3.23`, bumping the bundled Node.js runtime from `25.8.2` to `25.9.0`. In `.github/workflows/pr-tests.yml`, the PR image flow no longer pushes test images to Docker Hub; `Build Image` changes from `push: true` to `push: false` with `outputs: type=oci,dest=image.tar`, a new `Upload Docker Image Artifact` step persists the OCI archive, `Download Docker Image Artifact` and `Extract single-arch image with Skopeo` load per-architecture images for the test matrix, all smoke and integrity checks now target the locally extracted per-architecture image tags, and a new `artifact-clean-up` job removes the uploaded artifact after testing completes. The same workflow also updates `uses: docker/build-push-action@v6` to `uses: docker/build-push-action@v7` in `Build Image`, while `.github/workflows/deployment.yml` updates `uses: docker/build-push-action@v5` to `uses: docker/build-push-action@v7` in `Build and push (multi-registry, multi-platform)`. In `.github/workflows/deployment.yml`, the top-level `permissions:` block now adds `id-token: write` so the release job can mint the OIDC token required for attestation signing, and the multi-platform build step replaces `provenance: true` and `sbom: true` with `attests:` entries `type=provenance,mode=max` and `type=sbom,mode=max`. In `CONTRIBUTING.md`, the Node.js Version Bumps example is updated from `node:25.8.2-alpine3.23` to `node:25.9.0-alpine3.23`. In `README.md`, the Versioning and Tags example is updated from `v2.1.3+node25.8.2` to `v2.2.0+node25.9.0`, and the `CI/CD & Build Tooling` section adds `actions/upload-artifact`, `actions/download-artifact`, `geekyeggo/delete-artifact`, `chrnorm/deployment-action`, and `chrnorm/deployment-status`. No migration steps are required beyond updating to `v2.2.0+node25.9.0` on the `maintenance/v2+node25` line.
2 parents 1f30b82 + c8b1349 commit 37c8311

5 files changed

Lines changed: 80 additions & 30 deletions

File tree

.github/workflows/deployment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ jobs:
115115
# Build the multi-platform container image and push it to both registries.
116116
# BuildKit is used to generate SBOM and provenance metadata.
117117
- name: Build and push (multi-registry, multi-platform)
118-
uses: docker/build-push-action@v5
118+
uses: docker/build-push-action@v7
119119
with:
120120
context: .
121121
push: true

.github/workflows/pr-tests.yml

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -57,30 +57,31 @@ jobs:
5757
- name: Set up Docker Buildx
5858
uses: docker/setup-buildx-action@v3
5959

60-
# Authenticate to Docker Hub so the workflow can push images to test.
61-
- name: Login to Docker Hub
62-
uses: docker/login-action@v3
63-
with:
64-
username: ${{ secrets.DOCKERHUB_USERNAME }}
65-
password: ${{ secrets.DOCKERHUB_TOKEN }}
66-
6760
# Build the Docker image and load it locally
6861
- name: Build Image
69-
uses: docker/build-push-action@v6
62+
uses: docker/build-push-action@v7
7063
with:
7164
context: .
7265
platforms: linux/amd64,linux/arm64
73-
push: true
66+
push: false
67+
outputs: type=oci,dest=image.tar
7468
tags: runtimenode/test:pr-${{ github.event.pull_request.number }}
7569
cache-to: type=gha,mode=max
7670

71+
# Save the built image as an artifact for the Test Image job
72+
- name: Upload Docker Image Artifact
73+
uses: actions/upload-artifact@v4
74+
with:
75+
name: docker-image-pr-${{ github.event.pull_request.number }}
76+
path: image.tar
77+
7778
# Job to test the Docker image across multiple architectures
7879
test-image:
7980
name: Test Image
8081
runs-on: ubuntu-24.04
8182
needs: [lint, build-image]
8283
env:
83-
TEST_IMAGE: runtimenode/test:pr-${{ github.event.pull_request.number }}
84+
TEST_IMAGE: test:pr-${{ github.event.pull_request.number }}
8485
strategy:
8586
fail-fast: true
8687
matrix:
@@ -99,24 +100,37 @@ jobs:
99100
- name: Set up QEMU
100101
if: matrix.platform != 'linux/amd64'
101102
uses: docker/setup-qemu-action@v3
102-
103-
# Authenticate to Docker Hub so the workflow can test the image.
104-
- name: Login to Docker Hub
105-
uses: docker/login-action@v3
106-
with:
107-
username: ${{ secrets.DOCKERHUB_USERNAME }}
108-
password: ${{ secrets.DOCKERHUB_TOKEN }}
109103

110-
# Pull the Docker image artifact built in the previous job
111-
- name: Pull Docker Image Artifact
112-
run: docker pull --platform ${{ matrix.platform }} ${{ env.TEST_IMAGE }}
104+
# Download the built Docker image artifact from the Build Image job
105+
- name: Download Docker Image Artifact
106+
uses: actions/download-artifact@v4
107+
with:
108+
name: docker-image-pr-${{ github.event.pull_request.number }}
109+
path: artifacts
110+
111+
# Load the single-arch image into the local Docker daemon using Skopeo
112+
- name: Extract single-arch image with Skopeo
113+
run: |
114+
PLATFORM="${{ matrix.platform }}"
115+
ARCH="${PLATFORM#linux/}"
116+
docker run --rm \
117+
-v /var/run/docker.sock:/var/run/docker.sock \
118+
-v "${{ github.workspace }}:/workspace" \
119+
quay.io/skopeo/stable:v1.22.0 \
120+
copy \
121+
--override-os linux \
122+
--override-arch "$ARCH" \
123+
oci-archive:/workspace/artifacts/image.tar \
124+
docker-daemon:${{ env.TEST_IMAGE }}-$ARCH
113125
114126
# Smoke Test — verify node binary works
115127
- name: Smoke Test — node --version
116128
run: |
129+
PLATFORM="${{ matrix.platform }}"
130+
ARCH="${PLATFORM#linux/}"
117131
OUTPUT=$(docker run --rm --platform ${{ matrix.platform }} \
118132
--entrypoint /usr/local/bin/node \
119-
${{ env.TEST_IMAGE }} \
133+
${{ env.TEST_IMAGE }}-$ARCH \
120134
--version)
121135
122136
echo "Node.js version reported: $OUTPUT"
@@ -125,9 +139,11 @@ jobs:
125139
# Integrity Test — ensure no shell is present
126140
- name: Integrity Test — no shell present
127141
run: |
142+
PLATFORM="${{ matrix.platform }}"
143+
ARCH="${PLATFORM#linux/}"
128144
if docker run --rm --platform ${{ matrix.platform }} \
129145
--entrypoint /bin/sh \
130-
${{ env.TEST_IMAGE }} \
146+
${{ env.TEST_IMAGE }}-$ARCH \
131147
-c "echo shell_found" 2>/dev/null; then
132148
echo "❌ Shell was found inside the image. The distroless guarantee is broken."
133149
exit 1
@@ -136,10 +152,12 @@ jobs:
136152
# Integrity Test — ensure no package manager is present
137153
- name: Integrity Test — no package manager present
138154
run: |
155+
PLATFORM="${{ matrix.platform }}"
156+
ARCH="${PLATFORM#linux/}"
139157
for bin in /usr/bin/apk /usr/bin/apt /usr/bin/apt-get; do
140158
if docker run --rm --platform ${{ matrix.platform }} \
141159
--entrypoint "$bin" \
142-
${{ env.TEST_IMAGE }} \
160+
${{ env.TEST_IMAGE }}-$ARCH \
143161
--version 2>/dev/null; then
144162
echo "❌ Package manager found at $bin. The distroless guarantee is broken."
145163
exit 1
@@ -149,19 +167,41 @@ jobs:
149167
# Integrity Test — verify NODE_ENV is set to production
150168
- name: Integrity Test — NODE_ENV is production
151169
run: |
170+
PLATFORM="${{ matrix.platform }}"
171+
ARCH="${PLATFORM#linux/}"
152172
OUTPUT=$(docker run --rm --platform ${{ matrix.platform }} \
153173
--entrypoint /usr/local/bin/node \
154-
${{ env.TEST_IMAGE }} \
174+
${{ env.TEST_IMAGE }}-$ARCH \
155175
-e "process.stdout.write(process.env.NODE_ENV || '')")
156176
157177
[[ "$OUTPUT" == "production" ]] || exit 1
158178
159179
# Integrity Test — verify TZ is set to UTC
160180
- name: Integrity Test — TZ is UTC
161181
run: |
182+
PLATFORM="${{ matrix.platform }}"
183+
ARCH="${PLATFORM#linux/}"
162184
OUTPUT=$(docker run --rm --platform ${{ matrix.platform }} \
163185
--entrypoint /usr/local/bin/node \
164-
${{ env.TEST_IMAGE }} \
186+
${{ env.TEST_IMAGE }}-$ARCH \
165187
-e "process.stdout.write(process.env.TZ || '')")
166188
167-
[[ "$OUTPUT" == "UTC" ]] || exit 1
189+
[[ "$OUTPUT" == "UTC" ]] || exit 1
190+
191+
# Job to clean up the Docker image artifact after testing to free up storage space
192+
artifact-clean-up:
193+
name: Clean Up Artifacts
194+
runs-on: ubuntu-24.04
195+
needs: test-image
196+
steps:
197+
# Checkout the repository code for removing Artifact
198+
- name: Checkout
199+
uses: actions/checkout@v4
200+
with:
201+
ref: ${{ github.event.pull_request.head.sha }}
202+
203+
# Remove the Docker image artifact to free up storage space
204+
- name: Remove Docker Image Artifact
205+
uses: geekyeggo/delete-artifact@v4
206+
with:
207+
name: docker-image-pr-${{ github.event.pull_request.number }}

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ All pull requests must:
7878

7979
## Node.js Version Bumps
8080

81-
Node.js version upgrades are tracked as versioned releases. Requests must include the official Alpine Node image tag (for example, `node:25.8.2-alpine3.23`) and are expected to trigger a semver release bump for the image.
81+
Node.js version upgrades are tracked as versioned releases. Requests must include the official Alpine Node image tag (for example, `node:25.9.0-alpine3.23`) and are expected to trigger a semver release bump for the image.
8282

8383
## Documentation Standards
8484

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Stage 1: Builder
22
# Extract binaries, libraries, and generate configuration files.
3-
FROM node:25.8.2-alpine3.23 AS builder
3+
FROM node:25.9.0-alpine3.23 AS builder
44

55
COPY --chmod=550 script.sh /
66
COPY --chmod=550 dependencies/requirements.txt /dependencies/

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ Applications that need a different timezone can set `TZ` at runtime (timezone da
175175
## Versioning and Tags
176176

177177
Tags follow the pattern:
178-
- `v<image_semver>+node<node_version>` (example: `v2.1.3+node25.8.2`)
178+
- `v<image_semver>+node<node_version>` (example: `v2.2.0+node25.9.0`)
179179
- `latest` tracks the most recent release.
180180

181181
Check the GitHub Releases page for the current tag and Node.js version.
@@ -243,6 +243,16 @@ Runtime Node exists because of a small set of outstanding open-source projects t
243243

244244
[**actions/checkout**](https://github.com/actions/checkout) — GitHub Action used to check out the repository code in every workflow job.
245245

246+
[**actions/upload-artifact**](https://github.com/actions/upload-artifact) — GitHub Action used to persist build artifacts between workflow jobs during validation.
247+
248+
[**actions/download-artifact**](https://github.com/actions/download-artifact) — GitHub Action used to retrieve previously uploaded build artifacts for later verification steps.
249+
250+
[**geekyeggo/delete-artifact**](https://github.com/geekyeggo/delete-artifact) — GitHub Action used to clean up temporary workflow artifacts after validation completes.
251+
252+
[**chrnorm/deployment-action**](https://github.com/chrnorm/deployment-action) — GitHub Action used to create GitHub Deployment records for release and promotion workflow runs.
253+
254+
[**chrnorm/deployment-status**](https://github.com/chrnorm/deployment-status) — GitHub Action used to publish in-progress, success, and failure states back to the associated GitHub Deployment.
255+
246256
### Contributors
247257

248258
| | Name | GitHub | Role |

0 commit comments

Comments
 (0)