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
2 changes: 1 addition & 1 deletion .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ permissions: {}

jobs:
build-push-test:
name: 🛠️ Build → Push → Test (🍨 ${{ matrix.flavor }})
name: Build → Push → Test (🍨 ${{ matrix.flavor }})
strategy:
matrix:
flavor: [cpp, rust]
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/wc-build-push-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ jobs:
image-digest: ${{ needs.build-push.outputs.digest }}
test-file: ${{ inputs.integration-test-file }}
runner-labels: ${{ matrix.runner }}
runner-arch: ${{ needs.build-push.outputs.runner-arch }}

acceptance-test:
name: 🏗️
Expand Down
55 changes: 25 additions & 30 deletions .github/workflows/wc-build-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ on:
type: string
outputs:
fully-qualified-image-name:
value: ${{ jobs.sanitize-image-name.outputs.fully-qualified-image-name }}
value: ${{ jobs.sanitize-inputs.outputs.fully-qualified-image-name }}
image-basename:
value: ${{ jobs.sanitize-image-name.outputs.image-basename }}
value: ${{ jobs.sanitize-inputs.outputs.image-basename }}
digest:
value: ${{ jobs.merge-image.outputs.digest }}
runner-arch:
value: ${{ jobs.sanitize-inputs.outputs.runner-arch }}
secrets:
DOCKER_REGISTRY_USERNAME:
required: true
Expand All @@ -48,21 +50,21 @@ on:
permissions: {}

jobs:
sanitize-image-name:
sanitize-inputs:
name: 🧼
uses: ./.github/workflows/wc-sanitize-image-name.yml
uses: ./.github/workflows/wc-sanitize-inputs.yml
with:
image-name: ${{ inputs.image-name }}
registry: ${{ inputs.registry }}
runner-labels: ${{ inputs.runner-labels }}

build-push:
name: ${{ matrix.runner }}
name: Build (${{ needs.sanitize-inputs.outputs.runner-arch }})
Copy link

Copilot AI Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a single runner-arch value from the sanitize job for every matrix entry can mislabel builds when matrix runners differ (e.g. mixing x64 and arm64), leading to misleading job names. Compute architecture within each matrix job (using RUNNER_ARCH) or incorporate matrix.runner into the name to ensure accuracy.

Suggested change
name: Build (${{ needs.sanitize-inputs.outputs.runner-arch }})
name: Build (${{ env.RUNNER_ARCH }})

Copilot uses AI. Check for mistakes.
strategy:
matrix:
runner: ${{ (startsWith(inputs.build-test-runner-labels, '[') && endsWith(inputs.build-test-runner-labels, ']')) && fromJson(inputs.build-test-runner-labels) || inputs.build-test-runner-labels }}
runs-on: ${{ matrix.runner }}
needs: sanitize-image-name
needs: sanitize-inputs
permissions:
contents: read
packages: write
Expand All @@ -87,7 +89,7 @@ jobs:
DOCKER_METADATA_SET_OUTPUT_ENV: false
id: metadata
with:
images: ${{ needs.sanitize-image-name.outputs.fully-qualified-image-name }}
images: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}
- name: Generate image label for devcontainer.metadata
run: |
set -Eeuo pipefail
Expand All @@ -105,16 +107,14 @@ jobs:
id: devcontainer-metadata
- run: echo "git-commit-epoch=$(git log -1 --pretty=%ct)" >> "$GITHUB_OUTPUT"
id: devcontainer-epoch
- run: echo "arch=$(echo "${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT"
id: devcontainer-arch
- uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
id: build-and-push
env:
SOURCE_DATE_EPOCH: ${{ steps.devcontainer-epoch.outputs.git-commit-epoch }}
with:
file: ${{ inputs.dockerfile }}
push: true
tags: ${{ needs.sanitize-image-name.outputs.fully-qualified-image-name }}
tags: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}
labels: |
${{ steps.metadata.outputs.labels }}
${{ steps.devcontainer-metadata.outputs.label }}
Expand All @@ -130,19 +130,17 @@ jobs:
DIGEST: ${{ steps.build-and-push.outputs.digest }}
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: digests-${{ needs.sanitize-image-name.outputs.image-basename }}-${{ steps.devcontainer-arch.outputs.arch }}
name: digests-${{ needs.sanitize-inputs.outputs.image-basename }}-${{ needs.sanitize-inputs.outputs.runner-arch }}
Copy link

Copilot AI Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Artifact name relies on a single upstream runner-arch; with multi-architecture matrix builds all artifacts may share the same name, reducing clarity and risking confusion when inspecting per-arch digests. Include a per-job architecture (e.g. from RUNNER_ARCH) or matrix.runner fragment to differentiate artifacts.

Suggested change
name: digests-${{ needs.sanitize-inputs.outputs.image-basename }}-${{ needs.sanitize-inputs.outputs.runner-arch }}
name: digests-${{ needs.sanitize-inputs.outputs.image-basename }}-${{ matrix.runner }}

Copilot uses AI. Check for mistakes.
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1

merge-image:
name: 🔗 Merge Image
# Support either a plain single label (e.g. ubuntu-latest) OR a JSON array of labels.
# If the input starts & ends with brackets we attempt JSON parsing; otherwise we pass the raw string.
runs-on: ${{ (startsWith(inputs.runner-labels, '[') && endsWith(inputs.runner-labels, ']')) && fromJson(inputs.runner-labels) || inputs.runner-labels }}
needs:
- build-push
- sanitize-image-name
- sanitize-inputs
permissions:
actions: read
attestations: write
Expand All @@ -159,13 +157,10 @@ jobs:
with:
disable-sudo: true
egress-policy: audit
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
path: ${{ runner.temp }}/digests
pattern: digests-${{ needs.sanitize-image-name.outputs.image-basename }}-*
pattern: digests-${{ needs.sanitize-inputs.outputs.image-basename }}-*
merge-multiple: true
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
with:
Expand All @@ -180,7 +175,7 @@ jobs:
env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: index
with:
images: ${{ needs.sanitize-image-name.outputs.fully-qualified-image-name }}
images: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}
# Generate Docker tags based on the following events/attributes.
# To prevent unnecessary image builds we simulate the `type=edge` tag
# with `type=raw,value=edge,enable=...` which only enables the tag
Expand Down Expand Up @@ -208,7 +203,7 @@ jobs:
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "${METADATA_JSON}") \
$(printf "${CONTAINER}@sha256:%s " *)
env:
CONTAINER: ${{ needs.sanitize-image-name.outputs.fully-qualified-image-name }}
CONTAINER: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}
METADATA_JSON: ${{ steps.metadata.outputs.json }}
shell: bash
working-directory: ${{ runner.temp }}/digests
Expand All @@ -219,44 +214,44 @@ jobs:
output=$(docker buildx imagetools inspect "${CONTAINER}" --format '{{json .}}')
echo "digest=$(echo "$output" | jq -r '.manifest.digest // .manifests[0].digest')" >> "$GITHUB_OUTPUT"
env:
CONTAINER: ${{ needs.sanitize-image-name.outputs.fully-qualified-image-name }}:${{ steps.metadata.outputs.version }}
CONTAINER: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}:${{ steps.metadata.outputs.version }}
- run: |
set -Eeuo pipefail
wget -O diffoci https://github.com/reproducible-containers/diffoci/releases/download/v0.1.7/diffoci-v0.1.7.linux-amd64
chmod +x diffoci
./diffoci diff --semantic --report-file=container-diff.json "${FROM_CONTAINER}" "${TO_CONTAINER}" || true
env:
FROM_CONTAINER: ${{ needs.sanitize-image-name.outputs.fully-qualified-image-name }}:edge
TO_CONTAINER: ${{ needs.sanitize-image-name.outputs.fully-qualified-image-name }}:${{ steps.metadata.outputs.version }}
FROM_CONTAINER: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}:edge
TO_CONTAINER: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}:${{ steps.metadata.outputs.version }}
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: container-diff-${{ needs.sanitize-image-name.outputs.image-basename }}
name: container-diff-${{ needs.sanitize-inputs.outputs.image-basename }}
path: container-diff.json
retention-days: 10
- uses: philips-software/amp-devcontainer/.github/actions/container-size-diff@ab0940b1e92f3ccee257d5984166c63c8cfe6a9d # v6.5.0
id: container-size-diff
with:
from-container: ${{ needs.sanitize-image-name.outputs.fully-qualified-image-name }}:edge
to-container: ${{ needs.sanitize-image-name.outputs.fully-qualified-image-name }}:${{ steps.metadata.outputs.version }}
from-container: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}:edge
to-container: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}:${{ steps.metadata.outputs.version }}
- uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
with:
header: container-size-diff-${{ needs.sanitize-image-name.outputs.image-basename }}
header: container-size-diff-${{ needs.sanitize-inputs.outputs.image-basename }}
message: |
${{ steps.container-size-diff.outputs.size-diff-markdown }}
- uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6
with:
image: ${{ needs.sanitize-image-name.outputs.fully-qualified-image-name }}@${{ steps.inspect-manifest.outputs.digest }}
image: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}@${{ steps.inspect-manifest.outputs.digest }}
dependency-snapshot: true
- uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
with:
subject-name: ${{ needs.sanitize-image-name.outputs.fully-qualified-image-name }}
subject-name: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}
subject-digest: ${{ steps.inspect-manifest.outputs.digest }}
show-summary: false
push-to-registry: true
- name: Verify attestation
run: gh attestation verify --repo "${GH_REPO}" "oci://${FULLY_QUALIFIED_IMAGE_NAME}@${DIGEST}"
env:
DIGEST: ${{ steps.inspect-manifest.outputs.digest }}
FULLY_QUALIFIED_IMAGE_NAME: ${{ needs.sanitize-image-name.outputs.fully-qualified-image-name }}
FULLY_QUALIFIED_IMAGE_NAME: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
14 changes: 8 additions & 6 deletions .github/workflows/wc-integration-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ on:
description: "Runner to use for the job, will be passed to `runs-on`"
required: true
type: string
runner-arch:
description: "Architecture of the runner executing the job, only used for job naming and test report files"
required: true
type: string
registry:
description: "Docker registry to push built containers to, DOCKER_REGISTRY_USERNAME and DOCKER_REGISTRY_PASSWORD secrets must be set if not using GitHub Container Registry"
required: false
Expand All @@ -35,7 +39,7 @@ permissions: {}

jobs:
run-test:
name: 🧪 Integration Test
name: 🧪 Integration Test (${{ inputs.runner-arch }})
runs-on: ${{ (startsWith(inputs.runner-labels, '[') && endsWith(inputs.runner-labels, ']')) && fromJson(inputs.runner-labels) || inputs.runner-labels }}
container:
image: ${{ inputs.fully-qualified-image-name }}@${{ inputs.image-digest }}
Expand All @@ -52,15 +56,13 @@ jobs:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- run: echo "arch=$(echo "${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT"
id: runner-arch
- run: bats --formatter junit "${TEST_FILE}" | tee "test-report-${IMAGE_BASENAME}-${RUNNER_ARCH}.xml"
- run: bats --formatter junit "${TEST_FILE}" | tee "test-report-${IMAGE_BASENAME}-${RUNNER_ARCHITECTURE}.xml"
env:
IMAGE_BASENAME: ${{ inputs.image-basename }}
TEST_FILE: ${{ inputs.test-file }}
RUNNER_ARCH: ${{ steps.runner-arch.outputs.arch }}
RUNNER_ARCHITECTURE: ${{ inputs.runner-arch }}
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: ${{ !cancelled() }}
with:
name: test-results-integration-${{ inputs.image-basename }}-${{ steps.runner-arch.outputs.arch }}
name: test-results-integration-${{ inputs.image-basename }}-${{ inputs.runner-arch }}
path: test-report-*.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
name: Sanitize Image Name
name: Sanitize Inputs

on:
workflow_call:
Expand All @@ -15,31 +15,38 @@ on:
type: string
outputs:
image-basename:
description: "The sanitized base name of the image (without registry or tag)"
description: "The sanitized base name of the image"
Copy link

Copilot AI Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original description clarified exclusion of registry and tag; removing that reduces precision. Recommend restoring explicit scope: The sanitized base name of the image (excluding registry and tag).

Suggested change
description: "The sanitized base name of the image"
description: "The sanitized base name of the image (excluding registry and tag)"

Copilot uses AI. Check for mistakes.
value: ${{ jobs.sanitize.outputs.image-basename }}
image-name:
description: "The sanitized name of the image (without registry or tag)"
description: "The sanitized name of the image"
Copy link

Copilot AI Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This description no longer states that the tag and registry are excluded, which can lead to misuse when composing full image references. Suggest: The sanitized image name (repository path without registry or tag).

Suggested change
description: "The sanitized name of the image"
description: "The sanitized image name (repository path without registry or tag)"

Copilot uses AI. Check for mistakes.
value: ${{ jobs.sanitize.outputs.image-name }}
fully-qualified-image-name:
description: "The fully qualified name of the image including registry (but without tag)"
description: "The fully qualified name of the image including registry"
Copy link

Copilot AI Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous wording clarified that the tag was not included; current phrasing could imply tags are present. Suggest: The fully qualified image name including registry (no tag).

Suggested change
description: "The fully qualified name of the image including registry"
description: "The fully qualified image name including registry (no tag)"

Copilot uses AI. Check for mistakes.
value: ${{ jobs.sanitize.outputs.fully-qualified-image-name }}
runner-arch:
description: "The architecture of the runner executing the job"
value: ${{ jobs.sanitize.outputs.runner-arch }}

permissions: {}

jobs:
sanitize:
name: Sanitize Image Name
name: Sanitize Inputs
runs-on: ${{ (startsWith(inputs.runner-labels, '[') && endsWith(inputs.runner-labels, ']')) && fromJson(inputs.runner-labels) || inputs.runner-labels }}
outputs:
image-basename: ${{ steps.sanitize-image-name.outputs.sanitized-basename }}
image-name: ${{ steps.sanitize-image-name.outputs.sanitized-image-name }}
fully-qualified-image-name: ${{ inputs.registry }}/${{ steps.sanitize-image-name.outputs.sanitized-image-name }}
runner-arch: ${{ steps.runner-arch.outputs.arch }}
steps:
- uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
disable-sudo-and-containers: true
allowed-endpoints: >
api.github.com:443
- name: Sanitize runner architecture
id: runner-arch
run: echo "arch=$(echo "${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT"
- name: Sanitize image name
id: sanitize-image-name
env:
Expand Down
Loading