1111 * matrix value; the `image:` tag (with env vars resolved) is the published tag.
1212 * This script prints a literal preamble (stages, job templates), then loops
1313 * over the parsed compose services to emit, per Linux OS, one build matrix job
14- * over PHP versions (bake builds and pushes the multi-arch image) plus a manual
15- * publish matrix job that mirrors the tags to Docker Hub. Windows is emitted the
16- * same way but single-arch (no manifest) with its own build runner/script.
14+ * over PHP versions (bake builds and pushes the multi-arch image, then ddsign
15+ * signs it) plus a manual publish matrix job that mirrors the tags to Docker
16+ * Hub. Windows is emitted the same way but single-arch (no manifest) with its
17+ * own build runner/script; its images are signed by a separate Linux job
18+ * (ddsign has no Windows binary), see .image_sign.
1719 */
1820
1921$ root = dirname (__DIR__ );
@@ -113,6 +115,11 @@ function parse_compose(string $path, array $env): array
113115 needs: []
114116 timeout: 4h
115117 image: 486234852809.dkr.ecr.us-east-1.amazonaws.com/docker:29.4.0-noble
118+ # Requested so `ddsign sign` (run after the push, see script below) can
119+ # authenticate as this CI job. https://datadoghq.atlassian.net/wiki/spaces/SECENG/pages/2744681107
120+ id_tokens:
121+ DDSIGN_ID_TOKEN:
122+ aud: image-integrity
116123 variables:
117124 DDCI_CONFIGURE_OTEL_EXPORTER: "true"
118125 # Compile runs on the buildx "ci" builder instance, not this job pod, so the
@@ -138,6 +145,27 @@ function parse_compose(string $path, array $env): array
138145 IMG_SOURCES: "${CI_REGISTRY_IMAGE}:${TAG}"
139146 IMG_DESTINATIONS: "dd-trace-ci:${TAG}"
140147
148+ # Signs an already-pushed tag in registry.ddbuild.io. Used for the Windows
149+ # images: they're built without buildx (see .windows_image_build), so unlike
150+ # the Linux builds they can't sign via `ddsign --docker-metadata-file` right
151+ # after the push. Runs on Linux regardless of build platform: it only needs
152+ # network access to inspect the pushed manifest, not the build runner itself.
153+ .image_sign:
154+ stage: ci-publish
155+ rules:
156+ - when: manual
157+ allow_failure: true
158+ needs: []
159+ image: 486234852809.dkr.ecr.us-east-1.amazonaws.com/docker:29.4.0-noble
160+ tags: ["arch:amd64"]
161+ id_tokens:
162+ DDSIGN_ID_TOKEN:
163+ aud: image-integrity
164+ # $TAG is supplied per matrix entry by the generated sign jobs.
165+ script:
166+ - DIGEST=$(docker buildx imagetools inspect "${CI_REGISTRY_IMAGE}:${TAG}" --format '{{.Manifest.Digest}}')
167+ - ddsign sign "${CI_REGISTRY_IMAGE}:${TAG}@${DIGEST}"
168+
141169.windows_image_build:
142170 stage: ci-build
143171 rules:
@@ -250,6 +278,15 @@ function parse_compose(string $path, array $env): array
250278<?php foreach ($ winServices as $ tag ): ?>
251279 - "<?= $ tag ?> "
252280<?php endforeach ; ?>
281+
282+ Windows sign:
283+ extends: .image_sign
284+ parallel:
285+ matrix:
286+ - TAG:
287+ <?php foreach ($ winServices as $ tag ): ?>
288+ - "<?= $ tag ?> "
289+ <?php endforeach ; ?>
253290<?php foreach ($ osList as ['name ' => $ os , 'dir ' => $ dir , 'services ' => $ services ]): ?>
254291<?php /*
255292 One build job per PHP version. buildx bake reads the x-bake platforms from
@@ -262,13 +299,22 @@ function parse_compose(string $path, array $env): array
262299 tags: ["arch:amd64"]
263300 parallel:
264301 matrix:
265- - PHP_VERSION:
266- <?php foreach ( array_keys ( $ services ) as $ svc): ?>
267- - <?= $ svc , "\n" ?>
302+ <?php foreach ( $ services as $ svc => $ tag ): ?>
303+ - PHP_VERSION: " <?= $ svc ?> "
304+ TAG: " <?= $ tag ?> "
268305<?php endforeach ; ?>
269306 script:
270307 - cd <?= $ dir , "\n" ?>
271- - docker buildx bake --no-cache --pull --push "${PHP_VERSION}"
308+ - METADATA_FILE=$(mktemp)
309+ - docker buildx bake --no-cache --pull --push --metadata-file "${METADATA_FILE}" "${PHP_VERSION}"
310+ # Unlike `docker buildx build`, `bake` nests its metadata under the target
311+ # name instead of writing it flat, so reslice it to what
312+ # `ddsign --docker-metadata-file` expects. Take the (only) top-level key
313+ # rather than looking up "${PHP_VERSION}" directly: bake sanitizes target
314+ # names for the metadata file (e.g. "7.0-alpine" -> "7_0-alpine"), so the
315+ # literal name doesn't always match.
316+ - jq 'keys[0] as $k | .[$k]' "${METADATA_FILE}" > "${METADATA_FILE}.flat"
317+ - ddsign sign "${CI_REGISTRY_IMAGE}:${TAG}" --docker-metadata-file "${METADATA_FILE}.flat"
272318<?php /*
273319 Mirror to Docker Hub: one matrix job per OS, independent (needs: [] via
274320 .image_publish) so it can sync existing images without rebuilding.
0 commit comments