svcforge: reference implementation
ci / lint (push) Successful in 1m19s
ci / unit (push) Failing after 1m2s
ci / integration (push) Has been skipped
ci / types (push) Successful in 1m37s
ci / security (push) Failing after 38s
ci / dockerfile (push) Successful in 14s
ci / image (api) (push) Has been skipped
ci / image (reconciler) (push) Has been skipped
ci / image (worker) (push) Has been skipped
ci / bump (push) Has been skipped
ci / lint (push) Successful in 1m19s
ci / unit (push) Failing after 1m2s
ci / integration (push) Has been skipped
ci / types (push) Successful in 1m37s
ci / security (push) Failing after 38s
ci / dockerfile (push) Successful in 14s
ci / image (api) (push) Has been skipped
ci / image (reconciler) (push) Has been skipped
ci / image (worker) (push) Has been skipped
ci / bump (push) Has been skipped
Complete working build of the system learn-python/ teaches. 164 tests, mypy --strict clean, domain coverage 99%.
This commit is contained in:
Executable
+81
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# CI's last act.
|
||||
#
|
||||
# Resolves the digest each service's commit-SHA tag points at, writes those digests into
|
||||
# deploy/chart/values.yaml, and commits. That commit is the deploy: ArgoCD is watching
|
||||
# master and picks it up. This script does not, and must not, talk to the cluster.
|
||||
#
|
||||
# Called by .gitea/workflows/ci.yaml on master only. Runnable by hand for a re-bump:
|
||||
# REGISTRY=gitea.oci-oci.duckdns.org IMAGE_NS=gitea_admin IMAGE_TAG=<sha> ./scripts/bump-digests.sh
|
||||
#
|
||||
# -e a failed inspect must not lead to committing a stale digest
|
||||
# -u an unset REGISTRY would silently resolve the wrong image
|
||||
# -o pipefail the digest comes out of a pipe; without this, a failing inspect that pipes
|
||||
# into a successful grep exits 0 and writes garbage
|
||||
set -euo pipefail
|
||||
|
||||
: "${REGISTRY:?REGISTRY must be set}"
|
||||
: "${IMAGE_NS:?IMAGE_NS must be set}"
|
||||
: "${IMAGE_TAG:?IMAGE_TAG must be set (the commit sha the images were built from)}"
|
||||
|
||||
SERVICES=(api worker reconciler)
|
||||
CHART_VALUES="deploy/chart/values.yaml"
|
||||
|
||||
# yq, pinned by digest. Not python+pyyaml: a yaml round-trip strips every comment in
|
||||
# values.yaml, and those comments are the only thing explaining why the digests are there.
|
||||
# yq edits in place and leaves the rest of the file alone.
|
||||
YQ_IMAGE="mikefarah/yq:4.44.6@sha256:b1d117c609ba990436ad1649299e2f6c378f62cb562caf30b6f2fb6144713422"
|
||||
|
||||
WORKDIR="$(mktemp -d)"
|
||||
cleanup() {
|
||||
rm -rf "${WORKDIR}"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
yq() {
|
||||
docker run --rm -v "${PWD}:/work" -w /work -u "$(id -u):$(id -g)" "${YQ_IMAGE}" "$@"
|
||||
}
|
||||
|
||||
echo "==> resolving digests for tag ${IMAGE_TAG}"
|
||||
for svc in "${SERVICES[@]}"; do
|
||||
image="${REGISTRY}/${IMAGE_NS}/svcforge-${svc}"
|
||||
digest="$(docker buildx imagetools inspect "${image}:${IMAGE_TAG}" --format '{{.Manifest.Digest}}')"
|
||||
|
||||
# Defence against a silently empty inspect. Without this, `yq` would happily write an
|
||||
# empty digest and the chart's own guard would fail the release later, further from
|
||||
# the cause.
|
||||
if [[ ! "${digest}" =~ ^sha256:[0-9a-f]{64}$ ]]; then
|
||||
echo "!! ${svc}: refusing to write a non-digest: '${digest}'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo " ${svc} -> ${digest}"
|
||||
echo "${digest}" > "${WORKDIR}/${svc}.digest"
|
||||
done
|
||||
|
||||
echo "==> writing ${CHART_VALUES}"
|
||||
for svc in "${SERVICES[@]}"; do
|
||||
digest="$(cat "${WORKDIR}/${svc}.digest")"
|
||||
# env(...) rather than string interpolation: a digest is attacker-controlled only in
|
||||
# theory, but yq expression injection is not a thing worth leaving open.
|
||||
DIGEST="${digest}" yq -i ".image.${svc}.digest = strenv(DIGEST)" "${CHART_VALUES}"
|
||||
done
|
||||
|
||||
if git diff --quiet -- "${CHART_VALUES}"; then
|
||||
echo "==> no digest changed; nothing to commit"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "==> committing"
|
||||
git config user.name "svcforge-ci"
|
||||
git config user.email "ci@svcforge.invalid"
|
||||
git add "${CHART_VALUES}"
|
||||
git commit -m "ci: bump image digests to ${IMAGE_TAG}
|
||||
|
||||
Built and scanned by ${IMAGE_TAG}. ArgoCD syncs from this commit.
|
||||
|
||||
[skip ci]"
|
||||
git push origin HEAD:master
|
||||
|
||||
echo "==> done. ArgoCD owns it from here."
|
||||
Reference in New Issue
Block a user