mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 11:11:30 +00:00
fix(compose): DEPL-002 — pin alpine/openssl + postgres:16-alpine by digest + H-002 CI guard
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.
This commit is contained in:
@@ -62,7 +62,13 @@ services:
|
||||
# handshake. ECDSA-P256 with SHA-256 is universally supported. See
|
||||
# docs/tls.md Pattern 1.
|
||||
certctl-tls-init:
|
||||
image: alpine/openssl:latest
|
||||
# DEPL-002 closure (Sprint 3, 2026-05-16): digest-pin so the
|
||||
# production-shaped compose has the same supply-chain posture as
|
||||
# the certctl Dockerfiles (which CI guards via digest-validity.sh).
|
||||
# The :latest tag floats; the digest is captured at the time
|
||||
# this comment was written. Bump after running the digest-
|
||||
# validity guard to confirm the new digest is still pullable.
|
||||
image: alpine/openssl:latest@sha256:41036db23542ed4cc09bc278d8a7e23b3da01690abb4b0e353b1bb87d70520ed
|
||||
container_name: certctl-tls-init
|
||||
restart: "no"
|
||||
entrypoint: /bin/sh
|
||||
@@ -123,7 +129,12 @@ services:
|
||||
# `unhealthy` flap to cascade into certctl-server's `service_healthy`
|
||||
# depends_on, blocking the whole stack.
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
# DEPL-002 closure (Sprint 3, 2026-05-16): digest-pin matching the
|
||||
# alpine/openssl pin above. The `16-alpine` tag is the stable
|
||||
# major-version stream; the digest snapshots today's image so a
|
||||
# silent upstream rebuild can't slip into a production deploy
|
||||
# mid-rollout. Bump alongside dependency reviews.
|
||||
image: postgres:16-alpine@sha256:890480b08124ce7f79960a9bb16fe39729aa302bd384bfd7c408fee6c8f7adb7
|
||||
container_name: certctl-postgres
|
||||
environment:
|
||||
POSTGRES_DB: certctl
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
#!/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."
|
||||
Reference in New Issue
Block a user