From 12aa310b8d4f2e403c75fbb442456387c649be8e Mon Sep 17 00:00:00 2001 From: pat-s Date: Mon, 29 Jun 2026 13:00:26 +0200 Subject: [PATCH] fix(ci): detect existing R versions via public object HEAD probe The existing-version check listed the bucket with an anonymous curl, but Backblaze B2 requires authentication for the list-bucket API, so it returned AccessDenied and r-versions-existing.txt was always empty -> every version was rebuilt despite already existing in s3. Signing the request is not workable here: the B2 credentials are scoped to the plugin-s3 image in crow and are not injected into this plain alpine step. Individual artifacts are public-read, so probe each expected object URL with an anonymous HEAD instead. The filename mirrors what nfpm produces (version and release pinned to 1): r-_1_.{apk,deb} for alpine/ubuntu and R--1-1..rpm for el*. Verified against the live bucket for all three packager families. Shell variables use bare $name rather than ${name}: crow runs its own ${VAR} substitution over the commands before the shell executes, so a ${VAR} naming a shell var (BASE, VERSION) was blanked to empty -- only matrix vars resolve at that stage. Build the filename with printf to avoid the ${VERSION}_1 brace requirement entirely. --- .crow/build.yaml | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/.crow/build.yaml b/.crow/build.yaml index b3b6c0e..18f126f 100644 --- a/.crow/build.yaml +++ b/.crow/build.yaml @@ -158,28 +158,29 @@ steps: - name: Check which R versions already exist in s3 image: reg.devxy.io/docker.io/library/alpine:3.23 privileged: true - environment: - AWS_ACCESS_KEY_ID: - from_secret: B2_S3_ACCESS_KEY_ID - AWS_SECRET_ACCESS_KEY: - from_secret: B2_S3_SECRET_KEY commands: - ip link set dev eth0 mtu 1280 2>/dev/null || true - for i in 1 2 3 4 5; do apk add -q --no-cache curl && break; sleep 5; done - | - # Backblaze B2 requires authentication for the list-bucket API (anonymous - # GET works only for individual public-read objects), so the request must be - # SigV4-signed with the same credentials used for the upload step. Without - # this the listing returns AccessDenied, r-versions-existing.txt stays empty, - # and every version is rebuilt even though it already exists. - LISTING=$(curl -s --aws-sigv4 "aws:amz:eu-central-003:s3" \ - --user "${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}" \ - "https://s3.eu-central-003.backblazeb2.com/devxy-r-builds?prefix=${PLATFORM_ID}/" | \ - grep -oE '[^<]+' | sed 's/<[^>]*>//g') + # Backblaze B2's list-bucket API requires authentication, but the upload + # credentials are scoped to the plugin-s3 image and aren't available here. + # Individual objects are public-read, so probe each expected artifact URL + # with an anonymous HEAD instead of listing the bucket. The filename mirrors + # what nfpm produces in builder/package.${PLATFORM} (version/release pinned + # to 1): r-_1_.{apk,deb} for alpine/ubuntu, R--1-1..rpm + # for el*. Shell variables must use bare $name, not ${name}: crow performs + # its own ${VAR} substitution on these commands before the shell runs, so + # ${VAR} for a shell var would be blanked out (only matrix vars resolve there). + case "${PLATFORM}" in + alpine-*) FMT="r-%s_1_%s.apk" ;; + ubuntu-*) FMT="r-%s_1_%s.deb" ;; + *) FMT="R-%s-1-1.%s.rpm" ;; + esac + BASE="https://s3.eu-central-003.backblazeb2.com/devxy-r-builds/${PLATFORM_ID}" : > r-versions-existing.txt for VERSION in $(cat r-versions-to-build.txt); do - if printf '%s\n' "$LISTING" | \ - awk -v arch="${ARCH_ID}" -v ver="$VERSION" 'index($0, arch) && index($0, ver) { found=1 } END { exit !found }'; then + URL="$BASE/$(printf "$FMT" "$VERSION" "${ARCH_ID}")" + if [ "$(curl -s -o /dev/null -w '%{http_code}' -I "$URL")" = "200" ]; then echo "$VERSION" >> r-versions-existing.txt fi done