mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 19:21:29 +00:00
b7a3162028
Bundle: ci-pipeline-cleanup, Phases 7-9 / frozen decisions 0.8 + 0.10 + 0.11.
NEW image-and-supply-chain job (Ubuntu, ~3 min). Three steps:
PHASE 7 — Digest validity
scripts/ci-guards/digest-validity.sh resolves every @sha256:<digest>
ref in deploy/**/*.{yml,Dockerfile*} against its registry. Closes the
H-001 lying-field gap that Bundle II hit (11 fabricated digests passed
H-001's regex-only check and failed docker pull in CI).
Sandbox verification: 16/16 digests in deploy/* + Dockerfiles all
return HTTP 200 from registry-1.docker.io / ghcr.io / mcr.microsoft.com.
PHASE 8 — Docker build smoke (all 4 Dockerfiles)
Per frozen decision 0.10: build Dockerfile, Dockerfile.agent,
deploy/test/f5-mock-icontrol/Dockerfile, deploy/test/libest/Dockerfile.
Catches syntax errors + COPY path drift before tag-time release.yml.
The test-sidecar Dockerfiles are load-bearing for vendor-e2e — a
syntax error there silently breaks the e2e suite.
PHASE 9 — OpenAPI ↔ handler operationId parity
scripts/ci-guards/openapi-handler-parity.sh extracts router routes
(r.mux.Handle / r.Register "METHOD /path" syntax — Go 1.22+ ServeMux),
extracts OpenAPI operations (paths × HTTP methods), and fails if any
router route has no operationId AND is not documented in the new
api/openapi-handler-exceptions.yaml.
Verified gap at HEAD c48a82c4 (root-caused):
142 router routes, 136 OpenAPI operations
6 router-only routes — all SCEP wire-protocol endpoints (RFC-shaped,
not REST). Documented in api/openapi-handler-exceptions.yaml with
one-line why: justifications.
0 OpenAPI-only operations.
Going forward: any new gap fails the build unless documented.
Status checks per push: now 7 (was 8 after Phase 5+6 dropped windows;
this Phase adds 1 = +1 net). Final acceptance gate target.
ci.yml: 383 → 432 lines (+49 for the new job + steps).
105 lines
3.5 KiB
Bash
Executable File
105 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# scripts/ci-guards/digest-validity.sh
|
|
#
|
|
# Verify every @sha256:<digest> reference in deploy/**/*.{yml,Dockerfile*}
|
|
# actually resolves on its registry. H-001 only checks for digest
|
|
# presence; this catches fabricated or stale digests.
|
|
#
|
|
# Per ci-pipeline-cleanup bundle Phase 7. The bug class this catches:
|
|
# Bundle II shipped 11 fabricated digests that passed H-001's
|
|
# regex-only check and failed `docker pull` in CI.
|
|
#
|
|
# Real registries supported:
|
|
# - Docker Hub library/* and non-library (auth.docker.io)
|
|
# - ghcr.io (lscr.io alias for linuxserver/*)
|
|
# - mcr.microsoft.com (no auth required for public images;
|
|
# Windows IIS image needs the manifest.v2 single-image digest,
|
|
# not the multi-arch list digest)
|
|
|
|
set -e
|
|
|
|
# Find every digest reference in compose files + Dockerfiles
|
|
mapfile -t REFS < <(
|
|
grep -rEho '[a-z0-9./-]+:[a-z0-9.-]+@sha256:[a-f0-9]{64}' \
|
|
deploy/ Dockerfile* deploy/test/*/Dockerfile 2>/dev/null \
|
|
| sort -u
|
|
)
|
|
|
|
if [ ${#REFS[@]} -eq 0 ]; then
|
|
echo "No @sha256 refs found — nothing to verify."
|
|
exit 0
|
|
fi
|
|
|
|
fail=0
|
|
for ref in "${REFS[@]}"; do
|
|
digest="${ref##*@}"
|
|
imgtag="${ref%@*}"
|
|
tag="${imgtag##*:}"
|
|
img="${imgtag%:*}"
|
|
|
|
# Determine registry + auth flow.
|
|
if [[ "$img" =~ ^lscr\.io/ ]]; then
|
|
img="${img#lscr.io/}"
|
|
registry="ghcr.io"
|
|
auth_url="https://ghcr.io/token?scope=repository:${img}:pull"
|
|
elif [[ "$img" =~ ^mcr\.microsoft\.com/ ]]; then
|
|
img="${img#mcr.microsoft.com/}"
|
|
registry="mcr.microsoft.com"
|
|
auth_url=""
|
|
elif [[ "$img" == */* ]]; then
|
|
# Non-library Docker Hub (e.g., envoyproxy/envoy, boky/postfix)
|
|
registry="registry-1.docker.io"
|
|
auth_url="https://auth.docker.io/token?service=registry.docker.io&scope=repository:${img}:pull"
|
|
else
|
|
# Library Docker Hub (e.g., httpd, golang)
|
|
img="library/$img"
|
|
registry="registry-1.docker.io"
|
|
auth_url="https://auth.docker.io/token?service=registry.docker.io&scope=repository:${img}:pull"
|
|
fi
|
|
|
|
# Get auth token if needed.
|
|
auth_header=""
|
|
if [ -n "$auth_url" ]; then
|
|
tok=$(curl -sS "$auth_url" | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])" 2>/dev/null)
|
|
if [ -z "$tok" ]; then
|
|
echo "::error::Failed to get auth token for $registry / $img"
|
|
fail=1
|
|
continue
|
|
fi
|
|
auth_header="Authorization: Bearer $tok"
|
|
fi
|
|
|
|
# HEAD the manifest by digest.
|
|
if [ -n "$auth_header" ]; then
|
|
code=$(curl -sS -o /dev/null -w "%{http_code}" \
|
|
-H "$auth_header" \
|
|
-H "Accept: application/vnd.oci.image.index.v1+json" \
|
|
-H "Accept: application/vnd.docker.distribution.manifest.list.v2+json" \
|
|
-H "Accept: application/vnd.oci.image.manifest.v1+json" \
|
|
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
|
|
"https://${registry}/v2/${img}/manifests/${digest}")
|
|
else
|
|
code=$(curl -sS -o /dev/null -w "%{http_code}" \
|
|
-H "Accept: application/vnd.oci.image.index.v1+json" \
|
|
-H "Accept: application/vnd.docker.distribution.manifest.list.v2+json" \
|
|
-H "Accept: application/vnd.oci.image.manifest.v1+json" \
|
|
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
|
|
"https://${registry}/v2/${img}/manifests/${digest}")
|
|
fi
|
|
|
|
if [ "$code" != "200" ]; then
|
|
echo "::error::digest does not resolve: ${ref}"
|
|
echo " registry: $registry"
|
|
echo " image: $img"
|
|
echo " digest: $digest"
|
|
echo " HTTP: $code"
|
|
fail=1
|
|
else
|
|
echo "OK $ref"
|
|
fi
|
|
done
|
|
|
|
[ $fail -eq 0 ] || exit 1
|
|
echo ""
|
|
echo "digest-validity: clean — all ${#REFS[@]} digest references resolve."
|