fix(image-deploy): monotonic tag guard — refuse backwards newTag writes (#2)
validate / validate (push) Successful in 6s
validate / validate (push) Successful in 6s
This commit was merged in pull request #2.
This commit is contained in:
+32
@@ -2,6 +2,7 @@ name: Deploy Image (kustomize image-pin in apps repo)
|
|||||||
description: |
|
description: |
|
||||||
Pin an image tag in fritzlab/apps via `kustomize edit set image`, validate the
|
Pin an image tag in fritzlab/apps via `kustomize edit set image`, validate the
|
||||||
rendered manifests, and push to apps-repo main. Retries on push conflict.
|
rendered manifests, and push to apps-repo main. Retries on push conflict.
|
||||||
|
Refuses to lower the pinned tag (monotonic write guard).
|
||||||
inputs:
|
inputs:
|
||||||
image:
|
image:
|
||||||
description: Full image name without tag (must match an entry in the target kustomization.yaml `images:` block)
|
description: Full image name without tag (must match an entry in the target kustomization.yaml `images:` block)
|
||||||
@@ -52,7 +53,35 @@ runs:
|
|||||||
git config user.name ci-bot
|
git config user.name ci-bot
|
||||||
git config user.email ci-bot@fritzlab.net
|
git config user.email ci-bot@fritzlab.net
|
||||||
|
|
||||||
|
# Read the numeric newTag currently pinned for IMAGE in origin/main.
|
||||||
|
# Returns empty string when the image entry is absent.
|
||||||
|
_origin_tag() {
|
||||||
|
git -C "$WORK" show "origin/main:${PATH_IN_REPO}/kustomization.yaml" 2>/dev/null \
|
||||||
|
| awk -v img="$IMAGE" '
|
||||||
|
/^images:/ { in_b=1 }
|
||||||
|
in_b && /- name:/ { found=(index($0, img) > 0) }
|
||||||
|
found && /newTag:/ { gsub(/[^0-9]/, ""); print; exit }
|
||||||
|
'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Refuse to write a tag older than what origin/main already carries.
|
||||||
|
# Two concurrent releases can race such that the older build's deploy step
|
||||||
|
# runs after the newer build already committed its tag; without this guard
|
||||||
|
# the older run silently reverts the manifest to a stale image.
|
||||||
|
_monotonic_check() {
|
||||||
|
local existing
|
||||||
|
existing="$(_origin_tag)"
|
||||||
|
if [ -n "$existing" ] && [ "$existing" -gt "$TAG" ] 2>/dev/null; then
|
||||||
|
echo "SKIP: origin/main already has ${NAME}:${existing} > ${NAME}:${TAG} — refusing backwards write (bug-313bg8bgezp3)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
cd "$PATH_IN_REPO"
|
cd "$PATH_IN_REPO"
|
||||||
|
|
||||||
|
# Monotonic guard before touching the kustomization.
|
||||||
|
_monotonic_check
|
||||||
|
|
||||||
kustomize edit set image "${IMAGE}=${IMAGE}:${TAG}"
|
kustomize edit set image "${IMAGE}=${IMAGE}:${TAG}"
|
||||||
|
|
||||||
# Validate the kustomization renders cleanly before we push.
|
# Validate the kustomization renders cleanly before we push.
|
||||||
@@ -112,6 +141,9 @@ runs:
|
|||||||
fi
|
fi
|
||||||
echo "push rejected, attempt ${ATTEMPTS}; rebasing and retrying"
|
echo "push rejected, attempt ${ATTEMPTS}; rebasing and retrying"
|
||||||
git -C "$WORK" pull --rebase origin main
|
git -C "$WORK" pull --rebase origin main
|
||||||
|
# After rebase origin/main refs are updated; re-check the monotonic
|
||||||
|
# invariant before attempting to push the rebased commit.
|
||||||
|
_monotonic_check
|
||||||
sleep $((ATTEMPTS * 2))
|
sleep $((ATTEMPTS * 2))
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user