ORCH-058: implement fail-closed provenance guard in deploy-hook + GIT_SHA OCI label in Dockerfile
All checks were successful
CI / test (push) Successful in 16s

- deploy-hook: REVISION_LABEL/EXPECTED_REVISION (default unset -> backward-compat)
- deploy-hook: fail-closed guard inspects SOURCE_IMAGE revision label before docker tag, normalises <no value>, exit 1 on empty/mismatch
- deploy-hook: new --build-staging mode rebuilds staging image stamping GIT_SHA
- Dockerfile: ARG GIT_SHA + LABEL org.opencontainers.image.revision=$GIT_SHA

Closes TC07/TC08 (tests/test_deploy_hook_provenance.py).
This commit is contained in:
Dev Agent
2026-06-07 11:20:38 +03:00
parent 83397570fe
commit f0c2986477
2 changed files with 36 additions and 0 deletions

View File

@@ -1,5 +1,9 @@
FROM python:3.12-slim
WORKDIR /app
# ORCH-58: stamp the validated git commit into the OCI revision label so the
# deploy hook provenance guard can fail-closed on it before the prod retag.
ARG GIT_SHA
LABEL org.opencontainers.image.revision=$GIT_SHA
RUN apt-get update -qq && apt-get install -y -qq openssh-client git && rm -rf /var/lib/apt/lists/*
# git operations run as root over bind-mounted /repos (may be owned by host uid) -> trust it.
RUN git config --system --add safe.directory '*'

View File

@@ -32,6 +32,11 @@ PREV_IMAGE_FILE="${PREV_IMAGE_FILE:-$REPO/.deploy-prev-image-staging}"
# Build-once (ORCH-36): optional prevalidated source image to retag onto
# TARGET_IMAGE. Unset -> backward-compatible (no retag), exit-code contract intact.
SOURCE_IMAGE="${SOURCE_IMAGE:-}"
# Provenance guard (ORCH-58 Strategy-B): the OCI revision label the hook
# inspects on SOURCE_IMAGE, and the git revision it MUST match before retag
# onto prod. EXPECTED_REVISION unset -> backward-compatible (guard skipped).
REVISION_LABEL="org.opencontainers.image.revision"
EXPECTED_REVISION="${EXPECTED_REVISION:-}"
# ---- Log setup -------------------------------------------------------------
LOG_DIR=/var/log/orchestrator
@@ -118,6 +123,17 @@ do_rollback() {
# ============================================================================
# MANUAL --rollback mode
# ============================================================================
if [[ "${1:-}" == "--build-staging" ]]; then
# Strategy-A rebuild mode (ORCH-58): rebuild the staging image stamping
# the validated commit SHA into the OCI revision label so the provenance
# guard above can fail-closed on it during the subsequent prod retag.
GIT_SHA=$(git rev-parse HEAD)
log "BUILD-STAGING: rebuilding $TARGET_IMAGE stamping GIT_SHA=$GIT_SHA"
docker build --build-arg GIT_SHA="$GIT_SHA" -t "$TARGET_IMAGE" "$REPO" >> "$LOG" 2>&1
log "BUILD-STAGING: built $TARGET_IMAGE (revision=$GIT_SHA)"
exit 0
fi
if [[ "${1:-}" == "--rollback" ]]; then
log "Manual ROLLBACK requested"
if do_rollback; then
@@ -156,6 +172,22 @@ git pull origin main >> "$LOG" 2>&1
# Backward compatible: skipped when SOURCE_IMAGE is unset.
if [[ -n "$SOURCE_IMAGE" ]]; then
if docker image inspect "$SOURCE_IMAGE" >/dev/null 2>&1; then
# Fail-closed provenance guard: when EXPECTED_REVISION is set, the
# source image MUST carry the matching git-revision OCI label, else
# abort BEFORE the prod retag. Empty EXPECTED_REVISION -> guard
# skipped (ORCH-36 backward-compat).
if [[ -n "$EXPECTED_REVISION" ]]; then
IMG_REV=$(docker image inspect --format '{{ index .Config.Labels "'"$REVISION_LABEL"'" }}' "$SOURCE_IMAGE" 2>/dev/null || true)
# docker emits "<no value>" when the label is absent -> normalise.
if [[ "$IMG_REV" == "<no value>" ]]; then
IMG_REV=""
fi
if [[ -z "$IMG_REV" || "$IMG_REV" != "$EXPECTED_REVISION" ]]; then
log "PROVENANCE: SOURCE_IMAGE revision '$IMG_REV' != expected '$EXPECTED_REVISION' - aborting before retag (exit 1)"
exit 1
fi
log "PROVENANCE: SOURCE_IMAGE revision matches expected ($EXPECTED_REVISION)"
fi
log "BUILD-ONCE: retagging $SOURCE_IMAGE -> $TARGET_IMAGE (no rebuild)"
docker tag "$SOURCE_IMAGE" "$TARGET_IMAGE" >> "$LOG" 2>&1
else