Skip to content

Commit d94cd18

Browse files
fix(release): fail closed when the chart existence probe errors
The probe that decides whether cozy-installer:X.Y.Z is already published treated every non-zero skopeo exit as "not published yet". skopeo exits 1 for everything — an absent manifest, a 403, an expired token, a DNS failure, a registry 5xx — so a transient registry error fell straight through to an unconditional helm push, bypassing the content comparison and moving the stable chart tag onto freshly packaged bytes. That is the opposite of what this script exists to guarantee, and it would fire under exactly the flaky conditions that make a promotion need re-running. Classify the failure instead: an explicitly missing manifest, or a repository that does not exist yet (the first-ever push), counts as absent; anything else aborts with the registry's own diagnostic and pushes nothing. The patterns match the wording skopeo actually emits, checked against GHCR for a missing tag, a forbidden repository and an unreachable registry. Reported by CodeRabbit on #3456. Assisted-By: Claude <[email protected]> Signed-off-by: Myasnikov Daniil <[email protected]>
1 parent e834254 commit d94cd18

2 files changed

Lines changed: 68 additions & 7 deletions

File tree

‎hack/promote-publish-chart.sh‎

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,39 @@ helm package packages/core/installer \
8686
PKG="$WORKDIR/fresh/cozy-installer-${STABLE_VERSION}.tgz"
8787
[ -f "$PKG" ] || { echo "helm package did not produce $PKG" >&2; exit 1; }
8888

89-
# `--raw` is load-bearing: a Helm OCI artifact is not a container image, and the
90-
# image-shaped `skopeo inspect` rejects it on media type. Fetching the manifest
91-
# raw is media-type agnostic, so this existence probe works for charts and would
92-
# work for any other artifact type.
93-
if skopeo inspect --raw "docker://${CHART_REF}:${STABLE_VERSION}" >/dev/null 2>&1; then
89+
# Is this version already published? `--raw` is load-bearing: a Helm OCI artifact
90+
# is not a container image, and the image-shaped `skopeo inspect` rejects it on
91+
# media type. Fetching the manifest raw is media-type agnostic, so this probe
92+
# works for charts and would work for any other artifact type.
93+
#
94+
# The probe must fail CLOSED. skopeo exits 1 for everything — a genuinely absent
95+
# manifest, a 403, an expired token, a DNS failure, a registry 5xx — so treating
96+
# any non-zero exit as "not published yet" would turn a transient network error
97+
# into an unconditional `helm push`, silently bypassing the content comparison
98+
# below and moving the stable chart tag onto freshly packaged bytes. That is the
99+
# opposite of what this script exists to guarantee, and it would happen under
100+
# exactly the flaky conditions that cause a promotion to be re-run in the first
101+
# place. So classify the failure: only an explicitly missing manifest (or a
102+
# repository that does not exist yet, which is the first-ever push) counts as
103+
# absent; anything else aborts with the registry's own diagnostic.
104+
PROBE_LOG="$WORKDIR/probe.log"
105+
PROBE_RC=0
106+
skopeo inspect --raw "docker://${CHART_REF}:${STABLE_VERSION}" \
107+
>/dev/null 2>"$PROBE_LOG" || PROBE_RC=$?
108+
109+
if [ "$PROBE_RC" -eq 0 ]; then
110+
PUBLISHED=1
111+
elif grep -qiE 'manifest unknown|manifest not found|name unknown|repository name not known' \
112+
"$PROBE_LOG"; then
113+
PUBLISHED=0
114+
else
115+
echo "::error::Could not determine whether cozy-installer:${STABLE_VERSION} is already published (skopeo exit ${PROBE_RC})." >&2
116+
echo "::error::Refusing to push blind — a push here would overwrite a published chart. Fix the registry access and re-run." >&2
117+
cat "$PROBE_LOG" >&2
118+
exit 1
119+
fi
120+
121+
if [ "$PUBLISHED" -eq 1 ]; then
94122
helm pull "oci://${CHART_REF}" \
95123
--version "$STABLE_VERSION" --destination "$WORKDIR/published" >/dev/null
96124
tar -xzf "$PKG" -C "$WORKDIR/fresh-tree"

‎hack/promote-publish-chart_test.bats‎

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,16 @@ _chart_fixture() {
5050
echo "$*" >>"$FIXLOG_SKOPEO"
5151
case "$1" in
5252
inspect)
53-
# Existence probe: succeeds only when the fixture says a chart is published.
54-
[ -f "$FIXPUB" ] || exit 1
53+
# Existence probe. FIXPROBEERR injects a registry failure verbatim; without
54+
# it the probe reports the real GHCR wording for an absent manifest.
55+
if [ -n "${FIXPROBEERR:-}" ]; then
56+
echo "$FIXPROBEERR" >&2
57+
exit 1
58+
fi
59+
if [ ! -f "$FIXPUB" ]; then
60+
echo 'time="..." level=fatal msg="Error parsing image name \"docker://ghcr.io/cozystack/cozystack/cozy-installer:9.9.9\": reading manifest 9.9.9 in ghcr.io/cozystack/cozystack/cozy-installer: manifest unknown"' >&2
61+
exit 1
62+
fi
5563
echo '{"schemaVersion":2}'
5664
;;
5765
esac
@@ -188,6 +196,31 @@ SHIM
188196
[ -f "$FIXPUSHED" ]
189197
}
190198

199+
@test "a probe failure that is not a missing manifest aborts instead of pushing" {
200+
_chart_fixture
201+
cd "$FIX"
202+
203+
# skopeo exits 1 for everything: an absent manifest, a 403, an expired token,
204+
# a DNS failure. Reading any of those as "not published yet" would push
205+
# unconditionally and move the stable chart tag onto fresh bytes — under
206+
# exactly the flaky conditions that make a promotion need re-running. These
207+
# are the real GHCR/skopeo wordings for a forbidden repository and an
208+
# unreachable registry.
209+
for err in \
210+
'level=fatal msg="fetching manifest 9.9.9 in ghcr.io/cozystack/cozystack/cozy-installer: Requesting bearer token: received unexpected HTTP status: 403 Forbidden"' \
211+
'level=fatal msg="pinging container registry ghcr.io: Get \"https://ghcr.io/v2/\": dial tcp: connect: connection refused"' \
212+
'level=fatal msg="received unexpected HTTP status: 500 Internal Server Error"'
213+
do
214+
: >"$FIXLOG_HELM"
215+
rc=0
216+
FIXPROBEERR="$err" env -u REGISTRY "$ROOT/hack/promote-publish-chart.sh" v9.9.9 \
217+
>/dev/null 2>&1 || rc=$?
218+
[ "$rc" -eq 1 ]
219+
! grep -q '^push ' "$FIXLOG_HELM"
220+
[ ! -f "$FIXPUSHED" ]
221+
done
222+
}
223+
191224
@test "the latest chart tag moves only when MOVE_LATEST is set" {
192225
_chart_fixture
193226
cd "$FIX"

0 commit comments

Comments
 (0)