Skip to content

Commit 090dc78

Browse files
committed
chore: fix issues with image name
1 parent 316371d commit 090dc78

File tree

4 files changed

+66
-27
lines changed

4 files changed

+66
-27
lines changed
File renamed without changes.
File renamed without changes.

.github/workflows/wc-build-push-test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ jobs:
3030
packages: write
3131
pull-requests: write
3232
with:
33+
devcontainer-metadata: .devcontainer/${{ matrix.flavor }}/devcontainer-metadata.json
3334
dockerfile: .devcontainer/${{ matrix.flavor }}/Dockerfile
3435
image-name: ${{ github.repository }}-${{ matrix.flavor }}
3536

.github/workflows/wc-build-push.yml

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@ on:
99
required: true
1010
type: string
1111
image-name:
12-
description: "Name of the Docker image to build"
12+
description: "Name of the Docker image to build, without registry or tag. E.g. 'my-image' or 'my-org/my-image'"
1313
required: true
1414
type: string
15+
devcontainer-metadata:
16+
description: "Path to a JSON file containing devcontainer metadata to add as a label to the built image"
17+
required: false
18+
type: string
1519
registry:
16-
description: "Docker registry to push built containers to"
20+
description: "Docker registry to push built containers to, DOCKER_USERNAME and DOCKER_PASSWORD secrets must be set if not using GitHub Container Registry"
1721
required: false
1822
type: string
1923
default: "ghcr.io"
@@ -25,8 +29,8 @@ on:
2529
required: false
2630
type: string
2731
default: '{"runner": ["ubuntu-latest", "ubuntu-24.04-arm"]}'
28-
merge-runner:
29-
description: "Runner label for the merge-image job"
32+
default-runner:
33+
description: "Runner label for the non-build jobs"
3034
required: false
3135
type: string
3236
default: ubuntu-latest
@@ -38,19 +42,49 @@ on:
3842
description: "Password or token for Docker login, if not provided the GITHUB_TOKEN will be used"
3943
required: false
4044

41-
permissions:
42-
contents: read
43-
44-
env:
45-
REGISTRY: ${{ inputs.registry }}
46-
FULLY_QUALIFIED_IMAGE_NAME: ${{ inputs.registry }}/${{ inputs.image-name }}
45+
permissions: {}
4746

4847
jobs:
48+
sanitize-inputs:
49+
runs-on: ${{ inputs.default-runner }}
50+
outputs:
51+
image-name: ${{ steps.sanitize-image-name.outputs.sanitized-image-name }}
52+
fully-qualified-image-name: ${{ inputs.registry }}/${{ steps.sanitize-image-name.outputs.sanitized-image-name }}
53+
image-basename: ${{ steps.sanitize-image-name.outputs.sanitized-basename }}
54+
steps:
55+
- name: Sanitize image name
56+
id: sanitize-image-name
57+
env:
58+
IMAGE_NAME: ${{ inputs.image-name }}
59+
run: |
60+
set -Eeuo pipefail
61+
62+
# Split all image name components (on '/') and sanitize each component independently.
63+
# Rules: lowercase; allowed chars a-z0-9._- ; collapse invalid sequences to single '-'; trim leading/trailing '-'.
64+
IFS='/' read -r -a PARTS <<< "$IMAGE_NAME"
65+
SANITIZED_PARTS=()
66+
67+
for PART in "${PARTS[@]}"; do
68+
SANITIZED_PART=$(echo "$PART" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9._-]+/-/g' | sed -E 's/^-+|-+$//g')
69+
if [ -z "$SANITIZED_PART" ]; then
70+
echo "Invalid or empty component after sanitization in image component: '$PART', please correct your image name: '$IMAGE_NAME'" >&2
71+
exit 1
72+
fi
73+
SANITIZED_PARTS+=("$SANITIZED_PART")
74+
done
75+
76+
SANITIZED_IMAGE_NAME=$(IFS='/'; echo "${SANITIZED_PARTS[*]}")
77+
SANITIZED_BASENAME=${SANITIZED_PARTS[-1]}
78+
echo "sanitized-image-name=$SANITIZED_IMAGE_NAME" >> "$GITHUB_OUTPUT"
79+
echo "sanitized-basename=$SANITIZED_BASENAME" >> "$GITHUB_OUTPUT"
80+
4981
build-push:
5082
strategy:
5183
matrix: ${{ fromJson(inputs.build-matrix) }}
5284
runs-on: ${{ matrix.runner }}
85+
needs: sanitize-inputs
5386
permissions:
87+
contents: read
5488
packages: write
5589
steps:
5690
- uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
@@ -66,15 +100,15 @@ jobs:
66100
USERNAME: ${{ secrets.DOCKER_USERNAME || github.actor }}
67101
PASSWORD: ${{ secrets.DOCKER_PASSWORD || secrets.GITHUB_TOKEN }}
68102
with:
69-
registry: ${{ env.REGISTRY }}
103+
registry: ${{ inputs.registry }}
70104
username: ${{ env.USERNAME }}
71105
password: ${{ env.PASSWORD }}
72106
- uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
73107
env:
74108
DOCKER_METADATA_SET_OUTPUT_ENV: false
75109
id: metadata
76110
with:
77-
images: ${{ env.FULLY_QUALIFIED_IMAGE_NAME }}
111+
images: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}
78112
# Generate image LABEL for devcontainer.metadata
79113
# the sed expression is a workaround for quotes being eaten in arrays (e.g. ["x", "y", "z"] -> ["x",y,"z"])
80114
- run: echo "metadata=$(jq -cj '[.]' ".devcontainer/${CONTAINER_FLAVOR}/devcontainer-metadata-vscode.json" | sed 's/,"/, "/g')" >> "$GITHUB_OUTPUT"
@@ -90,7 +124,7 @@ jobs:
90124
with:
91125
file: ${{ inputs.dockerfile }}
92126
push: true
93-
tags: ${{ env.FULLY_QUALIFIED_IMAGE_NAME }}
127+
tags: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}
94128
labels: |
95129
${{ steps.metadata.outputs.labels }}
96130
devcontainer.metadata=${{ steps.devcontainer-metadata.outputs.metadata }}
@@ -107,13 +141,13 @@ jobs:
107141
RUNNER_TEMP: ${{ runner.temp }}
108142
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
109143
with:
110-
name: digests-${{ inputs.image-name }}-${{ steps.devcontainer-arch.outputs.arch }}
144+
name: digests-${{ needs.sanitize-inputs.outputs.image-basename }}-${{ steps.devcontainer-arch.outputs.arch }}
111145
path: ${{ runner.temp }}/digests/*
112146
if-no-files-found: error
113147
retention-days: 1
114148

115149
merge-image:
116-
runs-on: ${{ inputs.merge-runner }}
150+
runs-on: ${{ inputs.default-runner }}
117151
needs: build-push
118152
permissions:
119153
actions: read
@@ -135,15 +169,15 @@ jobs:
135169
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
136170
with:
137171
path: ${{ runner.temp }}/digests
138-
pattern: digests-${{ inputs.image-name }}-*
172+
pattern: digests-${{ needs.sanitize-inputs.outputs.image-basename }}-*
139173
merge-multiple: true
140174
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
141175
- uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
142176
env:
143177
USERNAME: ${{ secrets.DOCKER_USERNAME || github.actor }}
144178
PASSWORD: ${{ secrets.DOCKER_PASSWORD || secrets.GITHUB_TOKEN }}
145179
with:
146-
registry: ${{ env.REGISTRY }}
180+
registry: ${{ inputs.registry }}
147181
username: ${{ env.USERNAME }}
148182
password: ${{ env.PASSWORD }}
149183
- uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
@@ -152,7 +186,7 @@ jobs:
152186
DOCKER_METADATA_ANNOTATIONS_LEVELS: index
153187
DOCKER_METADATA_SET_OUTPUT_ENV: false
154188
with:
155-
images: ${{ env.FULLY_QUALIFIED_IMAGE_NAME }}
189+
images: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}
156190
# Generate Docker tags based on the following events/attributes.
157191
# To prevent unnecessary image builds we simulate the `type=edge` tag
158192
# with `type=raw,value=edge,enable=...` which only enables the tag
@@ -165,6 +199,8 @@ jobs:
165199
type=semver,pattern={{major}}.{{minor}}
166200
type=semver,pattern={{major}}
167201
- name: Create manifest list and push
202+
env:
203+
FULLY_QUALIFIED_IMAGE_NAME: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}
168204
run: |
169205
import os
170206
import json
@@ -189,6 +225,8 @@ jobs:
189225
working-directory: ${{ runner.temp }}/digests
190226
- name: Inspect manifest and extract digest
191227
id: inspect-manifest
228+
env:
229+
FULLY_QUALIFIED_IMAGE_NAME: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}
192230
run: |
193231
set -Eeuo pipefail
194232
output=$(docker buildx imagetools inspect "${FULLY_QUALIFIED_IMAGE_NAME}:${CONTAINER_VERSION}" --format '{{json .}}')
@@ -201,35 +239,35 @@ jobs:
201239
chmod +x diffoci
202240
./diffoci diff --semantic --report-file=container-diff.json "${FROM_CONTAINER}" "${TO_CONTAINER}" || true
203241
env:
204-
FROM_CONTAINER: ${{ env.FULLY_QUALIFIED_IMAGE_NAME }}:edge
205-
TO_CONTAINER: ${{ env.FULLY_QUALIFIED_IMAGE_NAME }}:${{ steps.metadata.outputs.version }}
242+
FROM_CONTAINER: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}:edge
243+
TO_CONTAINER: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}:${{ steps.metadata.outputs.version }}
206244
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
207245
with:
208-
name: container-diff-${{ inputs.image-name }}
246+
name: container-diff-${{ needs.sanitize-inputs.outputs.image-basedname }}
209247
path: container-diff.json
210248
retention-days: 10
211249
- uses: ./.github/actions/container-size-diff
212250
id: container-size-diff
213251
with:
214-
from-container: ${{ env.FULLY_QUALIFIED_IMAGE_NAME }}:edge
215-
to-container: ${{ env.FULLY_QUALIFIED_IMAGE_NAME }}:${{ steps.metadata.outputs.version }}
252+
from-container: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}:edge
253+
to-container: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}:${{ steps.metadata.outputs.version }}
216254
- uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
217255
with:
218-
header: container-size-diff-${{ inputs.flavor }}
256+
header: container-size-diff-${{ needs.sanitize-inputs.outputs.image-basename }}
219257
message: |
220258
${{ steps.container-size-diff.outputs.size-diff-markdown }}
221259
- uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6
222260
with:
223-
image: ${{ env.FULLY_QUALIFIED_IMAGE_NAME }}@${{ steps.inspect-manifest.outputs.digest }}
261+
image: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}@${{ steps.inspect-manifest.outputs.digest }}
224262
dependency-snapshot: true
225263
- uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
226264
with:
227-
subject-name: ${{ env.FULLY_QUALIFIED_IMAGE_NAME }}
265+
subject-name: ${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}
228266
subject-digest: ${{ steps.inspect-manifest.outputs.digest }}
229267
show-summary: false
230268
push-to-registry: true
231269
- name: Verify attestation
232-
run: gh attestation verify --repo "${GH_REPO}" "oci://${FULLY_QUALIFIED_IMAGE_NAME}@${DIGEST}"
270+
run: gh attestation verify --repo "${GH_REPO}" "oci://${{ needs.sanitize-inputs.outputs.fully-qualified-image-name }}@${DIGEST}"
233271
env:
234272
DIGEST: ${{ steps.inspect-manifest.outputs.digest }}
235273
GH_REPO: ${{ github.repository }}

0 commit comments

Comments
 (0)