unos-repository

APK repository for unos
git clone git://git.finwo.net/misc/unos-repository
Log | Files | Refs | README

bootstrap-repo.sh (5423B)


      1 #!/bin/sh
      2 # mk/bootstrap-repo.sh - ensure an APKINDEX exists in the S3 repo.
      3 #
      4 # If the bucket already has x86_64/APKINDEX.tar.gz, do nothing.
      5 # Otherwise publish an empty signed index so `apk add` against the
      6 # repo stops 404ing before the first real package has been published.
      7 set -eu
      8 
      9 HERE=$(cd "$(dirname "$0")" && pwd)
     10 ROOT=$(cd "${HERE}/.." && pwd)
     11 
     12 # shellcheck disable=SC1091
     13 . "${HERE}/channels.inc"
     14 
     15 CHANNEL="${UNOS_CHANNEL:-lts}"
     16 case "${1:-}" in
     17   --channel) CHANNEL="${2:?--channel needs a value}"; shift 2 ;;
     18   --channel=*) CHANNEL="${1#--channel=}"; shift ;;
     19 esac
     20 
     21 ARCH=$(chan_arch "${ARCH:-x86_64}")
     22 PREFIX=$(chan_prefix "${CHANNEL}" "${ARCH}")
     23 
     24 for v in BUCKET_ACCESS_KEY BUCKET_SECRET_KEY BUCKET_NAME BUCKET_ENDPOINT BUCKET_REGION BUCKET_PUBLIC_URL; do
     25   eval "val=\${${v}:-}"
     26   [ -n "${val}" ] || { echo "bootstrap-repo.sh: ${v} is not set" >&2; exit 1; }
     27 done
     28 
     29 url="${BUCKET_ENDPOINT%/}/${BUCKET_NAME}/${PREFIX}/APKINDEX.tar.gz"
     30 public_url=$(chan_url "${BUCKET_PUBLIC_URL}" "${CHANNEL}" "${ARCH}" APKINDEX.tar.gz)
     31 tmp_body=$(mktemp)
     32 code=$(curl -sS -o "${tmp_body}" -w '%{http_code}' \
     33   --aws-sigv4 "aws:amz:${BUCKET_REGION}:s3" \
     34   --user "${BUCKET_ACCESS_KEY}:${BUCKET_SECRET_KEY}" \
     35   -H "x-amz-content-sha256: UNSIGNED-PAYLOAD" \
     36   "${url}") || code=000
     37 
     38 case "${code}" in
     39   2*) rm -f "${tmp_body}"
     40       anon_code=$(curl -sS -o /dev/null -w '%{http_code}' "${public_url}") || anon_code=000
     41       case "${anon_code}" in 2*) echo "==> repo already has ${PREFIX}/APKINDEX.tar.gz (${code}, anon ${anon_code}), nothing to do"; exit 0 ;; *) echo "==> repo has ${PREFIX}/APKINDEX.tar.gz but public fetch is ${anon_code}, re-publishing" ;; esac
     42       ;;
     43   404) rm -f "${tmp_body}"; echo "==> no ${PREFIX}/APKINDEX.tar.gz (404), bootstrapping empty index" ;;
     44   000) echo "bootstrap-repo.sh: could not reach ${url} (curl failed)" >&2; cat "${tmp_body}" >&2 2>/dev/null || true; rm -f "${tmp_body}"; exit 1 ;;
     45   400) echo "bootstrap-repo.sh: bad request (400) for ${url} -- check BUCKET_ENDPOINT/BUCKET_NAME/BUCKET_REGION" >&2; echo "--- S3 response ---" >&2; cat "${tmp_body}" >&2 2>/dev/null || true; echo "--- env ---" >&2; echo "ENDPOINT=${BUCKET_ENDPOINT} NAME=${BUCKET_NAME} REGION=${BUCKET_REGION}" >&2; rm -f "${tmp_body}"; exit 1 ;;
     46   403) echo "bootstrap-repo.sh: permission denied (403) for ${url} -- check BUCKET credentials/region" >&2; echo "--- S3 response ---" >&2; cat "${tmp_body}" >&2 2>/dev/null || true; rm -f "${tmp_body}"; exit 1 ;;
     47   *) echo "bootstrap-repo.sh: unexpected HTTP ${code} for ${url}" >&2; cat "${tmp_body}" >&2 2>/dev/null || true; rm -f "${tmp_body}"; exit 1 ;;
     48 esac
     49 
     50 REPODIR=$(chan_repodir "${CHANNEL}" "${ARCH}")
     51 mkdir -p "${REPODIR}"
     52 
     53 export PATH="${ROOT}/build/host/bin:${PATH}"
     54 command -v apk >/dev/null 2>&1 || { echo "bootstrap-repo.sh: no apk on PATH; run mk/bootstrap-host.sh first" >&2; exit 1; }
     55 
     56 . "${HERE}/sign-key.inc"
     57 KEY=$(resolve_sign_key) || { echo "bootstrap-repo.sh: no signing key" >&2; exit 1; }
     58 KEYNAME=$(basename "${KEY}" .rsa)
     59 
     60 if [ ! -x "${HERE}/pax-tar" ] || [ "${HERE}/pax-tar.c" -nt "${HERE}/pax-tar" ]; then
     61   cc -std=c99 -O2 -Wall -Wextra -o "${HERE}/pax-tar" "${HERE}/pax-tar.c"
     62 fi
     63 
     64 cd "${REPODIR}"
     65 
     66 # apk index with no inputs still needs to produce a valid archive;
     67 # `echo` avoids the shell expanding *.apk to a literal when empty.
     68 echo -n "" | tar -czf APKINDEX.tar.gz -T /dev/null 2>/dev/null || true
     69 # Try the real tool first; fall back to the empty tar if it produced nothing.
     70 if [ ! -s APKINDEX.tar.gz ] || ! tar -tzf APKINDEX.tar.gz >/dev/null 2>&1; then
     71   : > APKINDEX
     72   tar -czf APKINDEX.tar.gz APKINDEX
     73   rm -f APKINDEX
     74 fi
     75 
     76 # Rebuild properly if apk can do it (covers the signed-index header fixup below)
     77 # and ensures the index is well-formed even when empty.
     78 if ls ./*.apk >/dev/null 2>&1; then
     79   apk index --allow-untrusted -o APKINDEX.tar.gz ./*.apk
     80 else
     81   # empty repo: create minimal index that `apk add` accepts
     82   rm -f APKINDEX.tar.gz
     83   mkdir -p .idx-empty
     84   : > .idx-empty/APKINDEX
     85   tar -czf APKINDEX.tar.gz -C .idx-empty APKINDEX
     86   rm -rf .idx-empty
     87 fi
     88 
     89 echo "==> signing APKINDEX.tar.gz with ${KEYNAME}"
     90 openssl dgst -sha1 -sign "${KEY}" -out ".SIGN.RSA.${KEYNAME}.rsa.pub" APKINDEX.tar.gz
     91 mkdir -p "${ROOT}/build/work/.idxsig"
     92 cp ".SIGN.RSA.${KEYNAME}.rsa.pub" "${ROOT}/build/work/.idxsig/"
     93 "${HERE}/pax-tar" --no-checksum "${ROOT}/build/work/.idxsig" idxsig.tar
     94 sigsiz=$(stat -c%s idxsig.tar)
     95 head -c $((sigsiz - 1024)) idxsig.tar > idxsignotr.tar
     96 gzip -n -9 -f idxsignotr.tar
     97 cat idxsignotr.tar.gz APKINDEX.tar.gz > APKINDEX.signed.tar.gz
     98 mv APKINDEX.signed.tar.gz APKINDEX.tar.gz
     99 rm -f ".SIGN.RSA.${KEYNAME}.rsa.pub" idxsig.tar idxsignotr.tar.gz
    100 rm -rf "${ROOT}/build/work/.idxsig"
    101 
    102 echo "==> publishing ${PREFIX}/APKINDEX.tar.gz"
    103 sha=$(sha256sum APKINDEX.tar.gz | cut -d' ' -f1)
    104 tmp_put=$(mktemp)
    105 code=$(curl -sS -o "${tmp_put}" -w '%{http_code}' \
    106   --aws-sigv4 "aws:amz:${BUCKET_REGION}:s3" \
    107   --user "${BUCKET_ACCESS_KEY}:${BUCKET_SECRET_KEY}" \
    108   -H "x-amz-content-sha256: ${sha}" \
    109   -X PUT --upload-file APKINDEX.tar.gz \
    110   "${url}") || { echo "bootstrap-repo.sh: upload failed" >&2; cat "${tmp_put}" >&2 2>/dev/null || true; rm -f "${tmp_put}"; exit 1; }
    111 case "${code}" in 2*) rm -f "${tmp_put}"; echo "==> bootstrapped ${PREFIX}/APKINDEX.tar.gz (${code})" ;; *) echo "bootstrap-repo.sh: upload returned HTTP ${code}" >&2; cat "${tmp_put}" >&2 2>/dev/null || true; rm -f "${tmp_put}"; exit 1 ;; esac