mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 14:01:36 +00:00
360eaa75bc
Sprint 3 unified-master-audit closure. The production-shaped compose
(deploy/docker-compose.yml) — explicitly self-described as
'PRODUCTION-SHAPED (Bundle 2)' in its header — pulled two images by
floating tag:
image: alpine/openssl:latest
image: postgres:16-alpine
The certctl Dockerfiles have been digest-pinned for two bundles
(see Bundle A / H-001 + the digest-validity.sh CI guard). Compose
shipped on the lower bar — a registry-side tag swap could change
what an operator deploys without their seeing the diff in their
infra repo.
Fix:
- Pin both images by @sha256: (alpine/openssl looked up via Docker
Hub tag API on 2026-05-16; postgres:16-alpine the same).
- New scripts/ci-guards/H-002-bare-compose-image.sh — analogous
to H-001 — fails the build if any 'image:' line in
deploy/docker-compose.yml lacks a @sha256 digest. Test compose
files (deploy/docker-compose.test.yml + the loadtest stack)
and examples/ stay scoped out by design: those are throwaway
development-loop tooling where floating tags are intentional.
- The existing digest-validity.sh CI guard auto-discovers
digests via grep across deploy/ so the new pins get verified
on the same run that pulls them, without a separate change.
Closes DEPL-002.
51 lines
1.8 KiB
Bash
Executable File
51 lines
1.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# scripts/ci-guards/H-002-bare-compose-image.sh
|
|
#
|
|
# DEPL-002 closure (Sprint 3, 2026-05-16). Companion to H-001-bare-from.sh
|
|
# (which enforces digest pins on every Dockerfile FROM): every `image:`
|
|
# line in the production-shaped compose file MUST carry an @sha256
|
|
# digest. Pre-fix `deploy/docker-compose.yml` had two floating tags
|
|
# (alpine/openssl:latest and postgres:16-alpine), so a registry-side
|
|
# tag swap could change what an operator deploys without their seeing
|
|
# the diff.
|
|
#
|
|
# Scope is intentionally narrow: only the production-shaped compose
|
|
# under deploy/. Test compose files (deploy/docker-compose.test.yml,
|
|
# deploy/test/loadtest/docker-compose.yml) and the examples/ directory
|
|
# stay free of digest pins because they're development-loop tooling
|
|
# whose floating tags are intentional (developer pulls latest, runs
|
|
# the loop, throws it away). If a finding ever escalates one of those
|
|
# files to "ships in production," extend SCAN_FILES below.
|
|
|
|
set -e
|
|
|
|
SCAN_FILES=(
|
|
"deploy/docker-compose.yml"
|
|
)
|
|
|
|
failed=0
|
|
for f in "${SCAN_FILES[@]}"; do
|
|
if [ ! -f "$f" ]; then
|
|
echo "::error::H-002 misconfig: $f not found"
|
|
failed=1
|
|
continue
|
|
fi
|
|
# Match `image: something:tag` (with optional indent / quotes) that
|
|
# does NOT contain @sha256. Strip commented lines and YAML anchors.
|
|
BAD=$(grep -nE '^\s*image:\s+[^#@]+$' "$f" | grep -v '@sha256' || true)
|
|
if [ -n "$BAD" ]; then
|
|
echo "::error file=${f}::H-002 regression: compose has bare image (no @sha256 digest pin):"
|
|
echo "$BAD"
|
|
failed=1
|
|
fi
|
|
done
|
|
|
|
if [ "$failed" -ne 0 ]; then
|
|
echo ""
|
|
echo "Pin every production-compose image to an immutable digest."
|
|
echo "Look up current digests via:"
|
|
echo " curl -sS https://hub.docker.com/v2/repositories/<org>/<image>/tags/<tag> | jq -r .digest"
|
|
exit 1
|
|
fi
|
|
echo "H-002 bare-compose-image: clean."
|