fix(ci): real digests + matrix→service mapping for deploy-vendor-e2e

Bundle II Phases 1+15 shipped fabricated @sha256 digests across 11
sidecars (deploy/docker-compose.test.yml) plus the f5-mock-icontrol
Dockerfile golang FROM line. The H-001 bare-FROM CI guard passed
locally because it only regex-checks for the *presence* of @sha256:
— it does not verify the digest resolves on the registry. Result:
every deploy-vendor-e2e matrix job failed at `docker compose up`
with 'manifest unknown'.

Two classes of fix:

1. Replace the 11 fabricated digests with real, registry-resolved
   digests (verified via curl against registry-1.docker.io,
   ghcr.io, mcr.microsoft.com manifest endpoints):

   - httpd:2.4-alpine
   - haproxy:3.0-alpine
   - traefik:v3.1
   - caddy:2.8-alpine
   - envoyproxy/envoy:v1.32-latest
   - boky/postfix:latest
   - dovecot/dovecot:latest
   - lscr.io/linuxserver/openssh-server:latest (via ghcr.io)
   - kindest/node:v1.31.0
   - mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2022
     (manifest.v2 single-image digest — the image is Windows-only
     so there is no multi-arch list digest to follow)
   - golang:1.25.9-bookworm (in deploy/test/f5-mock-icontrol/Dockerfile)

   debian:bookworm-slim was also fabricated under the comment
   claiming it 'matches libest sidecar'; replaced with the real
   amd64-linux digest.

2. Special-case the matrix.vendor → docker-compose service mapping
   in .github/workflows/ci.yml::deploy-vendor-e2e step 'Bring up
   vendor sidecar'. The original step assumed a uniform
   '${{ matrix.vendor }}-test' suffix, but four matrix entries
   don't conform:

   - nginx → reuses apache-test (the legacy nginx sidecar in the
     compose file is named 'nginx' with no profile; the nginx
     vendor-edge tests in deploy/test/nginx_vendor_e2e_test.go
     call requireSidecar(t,"apache") because the sidecar map
     doesn't include an 'nginx' key — comment in source explains)
   - ssh → openssh-test
   - k8s → k8s-kind-test
   - f5-mock → f5-mock-icontrol (must be built first; no published image)
   - javakeystore → no sidecar (pure-Go placeholder stubs)

   Wraps the bring-up in a case statement that maps every matrix
   entry to its real sidecar name (or '' for the no-sidecar case),
   and exits 0 cleanly for vendors that don't need a sidecar.

Per the CLAUDE.md 'never go from memory' + 'complete path' rules,
this fix:
- ground-truths every digest against the actual registry (curl
  against the OCI v2 manifest endpoint with the right Accept
  header), not memory or grep
- closes the 'lying field' footgun: H-001 guard now validates a
  contract that's actually satisfied (digests exist + pull)

Verification: yaml parses on both files, H-001 guard simulation
returns no bare FROMs, all 12 manifest endpoints return HTTP 200
on the new digests.
This commit is contained in:
shankar0123
2026-04-30 18:46:02 +00:00
parent 26636aa9be
commit 1de61e91cf
3 changed files with 44 additions and 17 deletions
+32 -5
View File
@@ -1380,13 +1380,40 @@ jobs:
cache: true cache: true
- name: Bring up vendor sidecar - name: Bring up vendor sidecar
# Map matrix.vendor → docker-compose service name. The naming is
# NOT 1:1 because (a) the legacy NGINX vendor-edge tests reuse the
# apache-test sidecar via requireSidecar(t,"apache") — see the
# comment in deploy/test/nginx_vendor_e2e_test.go; (b) the openssh
# service is named openssh-test (not ssh-test); (c) the kind
# cluster service is named k8s-kind-test; (d) the F5 mock service
# is named f5-mock-icontrol and must be built first because it
# has no published image; (e) the JavaKeystore tests are pure-Go
# placeholder stubs that exercise no sidecar.
run: | run: |
if [ "${{ matrix.vendor }}" = "f5-mock" ]; then set -e
docker compose --profile deploy-e2e -f deploy/docker-compose.test.yml build f5-mock-icontrol case "${{ matrix.vendor }}" in
docker compose --profile deploy-e2e -f deploy/docker-compose.test.yml up -d f5-mock-icontrol nginx) SVC=apache-test ;; # nginx tests reuse apache sidecar
else apache) SVC=apache-test ;;
docker compose --profile deploy-e2e -f deploy/docker-compose.test.yml up -d ${{ matrix.vendor }}-test haproxy) SVC=haproxy-test ;;
traefik) SVC=traefik-test ;;
caddy) SVC=caddy-test ;;
envoy) SVC=envoy-test ;;
postfix) SVC=postfix-test ;;
dovecot) SVC=dovecot-test ;;
ssh) SVC=openssh-test ;;
k8s) SVC=k8s-kind-test ;;
f5-mock) SVC=f5-mock-icontrol ;;
javakeystore) SVC="" ;; # pure-Go placeholder stubs; no sidecar needed
*) echo "::error::unknown matrix vendor '${{ matrix.vendor }}'"; exit 1 ;;
esac
if [ -z "$SVC" ]; then
echo "vendor=${{ matrix.vendor }} runs without a sidecar (pure-Go placeholder tests)"
exit 0
fi fi
if [ "${{ matrix.vendor }}" = "f5-mock" ]; then
docker compose --profile deploy-e2e -f deploy/docker-compose.test.yml build "$SVC"
fi
docker compose --profile deploy-e2e -f deploy/docker-compose.test.yml up -d "$SVC"
sleep 5 sleep 5
- name: Run vendor-edge e2e - name: Run vendor-edge e2e
+10 -10
View File
@@ -486,7 +486,7 @@ services:
# docs/deployment-vendor-matrix.md. # docs/deployment-vendor-matrix.md.
apache-test: apache-test:
image: httpd:2.4-alpine@sha256:8e8ee9929d4d8ddbed9ff3e5aaad26cdb46c40a4e51d8fdd02c41bff37d1d65a image: httpd:2.4-alpine@sha256:f9061a65c6e8f50d5636e10806da3d5a238877c11d6bc0149dc5131be0a1a19f
container_name: certctl-test-apache container_name: certctl-test-apache
ports: ports:
- "20443:443" - "20443:443"
@@ -500,7 +500,7 @@ services:
profiles: [deploy-e2e] profiles: [deploy-e2e]
haproxy-test: haproxy-test:
image: haproxy:3.0-alpine@sha256:2e8a7b9f3c91c2c46a90e3a98a7e44e0f7c89def96b3f2bd2a7d0a48a9f4d36a image: haproxy:3.0-alpine@sha256:5b645ad4f3294cf5bc50ab8b201fdeb73732eca2928185df335735c698e8c3e2
container_name: certctl-test-haproxy container_name: certctl-test-haproxy
ports: ports:
- "20444:443" - "20444:443"
@@ -513,7 +513,7 @@ services:
profiles: [deploy-e2e] profiles: [deploy-e2e]
traefik-test: traefik-test:
image: traefik:v3.1@sha256:c5a92b19a3a77a3a60b9d9cdf3f60d7f08e7e9a2e4cdbcfb4a08b2e8a9e86e7c image: traefik:v3.1@sha256:8516638b18e67e999d293e4ff0e5baf7807674cd4bdd3d36d448497bcbf0a174
container_name: certctl-test-traefik container_name: certctl-test-traefik
command: command:
- --providers.file.directory=/etc/traefik/dynamic - --providers.file.directory=/etc/traefik/dynamic
@@ -531,7 +531,7 @@ services:
profiles: [deploy-e2e] profiles: [deploy-e2e]
caddy-test: caddy-test:
image: caddy:2.8-alpine@sha256:0afbb4bbcdaf0b3036020168f2796e6c80ddf95a7f5de2d3a5d8d7d80796a3df image: caddy:2.8-alpine@sha256:b95ed06fbc6d74d24a40902090c8cc6086ce7d08ba60a3a7e8e62bf164a9d7bb
container_name: certctl-test-caddy container_name: certctl-test-caddy
command: caddy run --config /etc/caddy/Caddyfile --adapter caddyfile command: caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
ports: ports:
@@ -546,7 +546,7 @@ services:
profiles: [deploy-e2e] profiles: [deploy-e2e]
envoy-test: envoy-test:
image: envoyproxy/envoy:v1.32-latest@sha256:b87f1a50f78ce96a5bca7eaa6c8d5e0e6d4edd6c8e9c2b9d7d2c39b5f6a2e3a4 image: envoyproxy/envoy:v1.32-latest@sha256:6ed0d4f28b8122df896062c425b34f18b8287e8c71c6badb3b84ca2e2f47c519
container_name: certctl-test-envoy container_name: certctl-test-envoy
command: envoy -c /etc/envoy/envoy.yaml --log-level error command: envoy -c /etc/envoy/envoy.yaml --log-level error
ports: ports:
@@ -560,7 +560,7 @@ services:
profiles: [deploy-e2e] profiles: [deploy-e2e]
postfix-test: postfix-test:
image: boky/postfix:latest@sha256:8d4f1ad9d2e1c4f9e3d4f9c1d7e6c0e9e8c5f5b3d1a4f7c4e1f2d6c5b3e9c8a7 image: boky/postfix:latest@sha256:cd7e192900bfc49a67291a572b5f645f9e7d1b8d7f2b79b0364b4b4176964e21
container_name: certctl-test-postfix container_name: certctl-test-postfix
environment: environment:
ALLOWED_SENDER_DOMAINS: "test.local" ALLOWED_SENDER_DOMAINS: "test.local"
@@ -575,7 +575,7 @@ services:
profiles: [deploy-e2e] profiles: [deploy-e2e]
dovecot-test: dovecot-test:
image: dovecot/dovecot:latest@sha256:7f4e2c1b6d4a5f7c8e6d9b3f4e7c2a8d6e3f1c4b9a8e7d6c5b4a3f2e1d0c9b8a image: dovecot/dovecot:latest@sha256:4046993478e8c8bcb841fdbff2d8de1b233484cc0196b3723f6c588e7eaf7301
container_name: certctl-test-dovecot container_name: certctl-test-dovecot
ports: ports:
- "20993:993" - "20993:993"
@@ -589,7 +589,7 @@ services:
profiles: [deploy-e2e] profiles: [deploy-e2e]
openssh-test: openssh-test:
image: lscr.io/linuxserver/openssh-server:latest@sha256:d6a7e4c3b2f1a0d9c8b7e6f5d4c3b2a1f0e9d8c7b6a5f4e3d2c1b0a9f8e7d6c5 image: lscr.io/linuxserver/openssh-server:latest@sha256:742f577d4100f5ad3b38f270d722931bbe98b997444c13b1a2a838df12a9971e
container_name: certctl-test-openssh container_name: certctl-test-openssh
environment: environment:
USER_NAME: "certctl" USER_NAME: "certctl"
@@ -629,7 +629,7 @@ services:
# The kind binary lives in the test image; the Docker socket is mounted # The kind binary lives in the test image; the Docker socket is mounted
# so kind can manage child containers. # so kind can manage child containers.
k8s-kind-test: k8s-kind-test:
image: kindest/node:v1.31.0@sha256:53df588e04085fd41ae12de0c3fe4c72f7013bba32a20e7325357a1ac94ba865 image: kindest/node:v1.31.0@sha256:7fbc5644a803286a69ff9c5695f03bb01b512896835e15df7df17f756f7245ac
container_name: certctl-test-kind container_name: certctl-test-kind
privileged: true privileged: true
networks: networks:
@@ -646,7 +646,7 @@ services:
# Image not pulled by default (no profile match on Linux); included # Image not pulled by default (no profile match on Linux); included
# here so Windows operators get the same compose surface. # here so Windows operators get the same compose surface.
windows-iis-test: windows-iis-test:
image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2022@sha256:placeholder-operator-pins-on-windows image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2022@sha256:8d0b0e651ad514e3fb05978db66f38036118812e1b9314a48f10419cad8a3462
container_name: certctl-test-iis container_name: certctl-test-iis
ports: ports:
- "20448:443" - "20448:443"
+2 -2
View File
@@ -7,13 +7,13 @@
# quarterly per docs/deployment-vendor-matrix.md. # quarterly per docs/deployment-vendor-matrix.md.
# golang:1.25.9-bookworm digest pinned per H-001. # golang:1.25.9-bookworm digest pinned per H-001.
FROM golang:1.25.9-bookworm@sha256:a3a4d83e8e83bf9bb6bf6c5e41bcde5a8e8e1d8e6b9cbcd3b9e7c5d4e7f9c1d5 AS builder FROM golang:1.25.9-bookworm@sha256:1a1408bf8d2d3077f9508880caf0e8bb0fde195fe3c890e7ea480dfb66dc7827 AS builder
WORKDIR /src WORKDIR /src
COPY deploy/test/f5-mock-icontrol/ ./ COPY deploy/test/f5-mock-icontrol/ ./
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags "-s -w" -o /out/f5-mock-icontrol . RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags "-s -w" -o /out/f5-mock-icontrol .
# debian:bookworm-slim digest pinned per H-001 (matches libest sidecar). # debian:bookworm-slim digest pinned per H-001 (matches libest sidecar).
FROM debian:bookworm-slim@sha256:f9c6a2fd2ddbc23e336b6257a5245e31f996953ef06cd13a59fa0a1df2d5c252 FROM debian:bookworm-slim@sha256:5a2a80d11944804c01b8619bc967e31801ec39bf3257ab80b91070eb23625644
RUN useradd --create-home --shell /bin/bash mockf5 RUN useradd --create-home --shell /bin/bash mockf5
COPY --from=builder /out/f5-mock-icontrol /usr/local/bin/f5-mock-icontrol COPY --from=builder /out/f5-mock-icontrol /usr/local/bin/f5-mock-icontrol
USER mockf5 USER mockf5