Skip to content

Streamline docs

Streamline docs #112

name: Release Controller
on:
push:
tags:
- "controller-[0-9]+.[0-9]+.[0-9]+**"
jobs:
release:
runs-on: ubuntu-22.04
permissions:
attestations: write
contents: write
id-token: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.PUBLIC_REGISTRY_USERNAME }}
password: ${{ secrets.PUBLIC_REGISTRY_PASSWORD }}
- name: Setup Cosign
uses: sigstore/cosign-installer@v3
- name: Setup ORAS
uses: oras-project/setup-oras@v1
- name: Version
run: make print-v-controller
- name: Release image
run: |
make \
DOCKER_INTERNAL_REG=${{ secrets.PRIVATE_REGISTRY }} \
DOCKER_INTERNAL_URL=${{ secrets.PRIVATE_REGISTRY_URL }} \
DOCKER_INTERNAL_USER=${{ secrets.PRIVATE_REGISTRY_USERNAME }} \
DOCKER_INTERNAL_PASSW=${{ secrets.PRIVATE_REGISTRY_PASSWORD }} \
DOCKER_RELEASE_USER=${{ secrets.PUBLIC_REGISTRY_USERNAME }} \
DOCKER_RELEASE_PASSW=${{ secrets.PUBLIC_REGISTRY_PASSWORD }} \
DOCKER_RELEASE_REG=${{ secrets.PUBLIC_REGISTRY }} \
DOCKER_RELEASE_TAG=${GITHUB_REF##*/} \
release-controller
- name: Resolve released image digest
id: released-image
env:
RELEASE_REGISTRY: ${{ secrets.PUBLIC_REGISTRY }}
run: |
set -euo pipefail
IMAGE_REPOSITORY="docker.io/${RELEASE_REGISTRY#docker.io/}/azure-keyvault-controller"
IMAGE_REF="${IMAGE_REPOSITORY}:${GITHUB_REF_NAME#controller-}"
IMAGE_DIGEST="$(docker buildx imagetools inspect --format '{{json .Manifest}}' "$IMAGE_REF" | jq -r '.digest // empty')"
if [ -z "$IMAGE_DIGEST" ]; then
echo "Failed to resolve released image digest for $IMAGE_REF" >&2
exit 1
fi
printf 'image-repository=%s\n' "$IMAGE_REPOSITORY" >> "$GITHUB_OUTPUT"
printf 'image-digest=%s\n' "$IMAGE_DIGEST" >> "$GITHUB_OUTPUT"
- name: Attest released image provenance
uses: actions/attest-build-provenance@v2
with:
subject-name: ${{ steps.released-image.outputs.image-repository }}
subject-digest: ${{ steps.released-image.outputs.image-digest }}
push-to-registry: true
- name: Sign released image and attestations
env:
RELEASE_REGISTRY: ${{ secrets.PUBLIC_REGISTRY }}
run: |
set -euo pipefail
IMAGE_REF="docker.io/${RELEASE_REGISTRY#docker.io/}/azure-keyvault-controller:${GITHUB_REF_NAME#controller-}"
cosign sign --yes "$IMAGE_REF"
docker buildx imagetools inspect --raw "$IMAGE_REF" \
| jq -r '.manifests[] | select(.platform.architecture == "unknown" and .platform.os == "unknown") | .digest' \
| while read -r digest; do
cosign sign --yes "$IMAGE_REF@$digest"
done
- name: Extract SPDX SBOMs
env:
RELEASE_REGISTRY: ${{ secrets.PUBLIC_REGISTRY }}
run: |
set -euo pipefail
IMAGE_REF="docker.io/${RELEASE_REGISTRY#docker.io/}/azure-keyvault-controller:${GITHUB_REF_NAME#controller-}"
IMAGE_REPO="docker.io/${RELEASE_REGISTRY#docker.io/}/azure-keyvault-controller"
IMAGE_ORAS_REPO="docker.io/${RELEASE_REGISTRY#docker.io/}/azure-keyvault-controller"
VERSION="${GITHUB_REF_NAME#controller-}"
OUT_DIR="dist/sbom"
TMP_DIR="$(mktemp -d)"
mkdir -p "$OUT_DIR"
trap 'rm -rf "$TMP_DIR"' EXIT
docker buildx imagetools inspect --raw "$IMAGE_REF" > "$TMP_DIR/index.json"
jq . "$TMP_DIR/index.json"
jq -r '.manifests[] | select(.platform.os != "unknown" and .platform.architecture != "unknown") | "\(.platform.os) \(.platform.architecture) \(.digest)"' "$TMP_DIR/index.json" \
| while read -r os arch subject_digest; do
echo "Resolving SBOM for platform ${os}/${arch} with subject digest ${subject_digest}"
attestation_digest="$(jq -r --arg subject "$subject_digest" '.manifests[] | select(.platform.architecture == "unknown" and .platform.os == "unknown" and .annotations["vnd.docker.reference.type"] == "attestation-manifest" and .annotations["vnd.docker.reference.digest"] == $subject) | .digest' "$TMP_DIR/index.json")"
if [ -z "$attestation_digest" ]; then
echo "No attestation manifest found for subject digest ${subject_digest}" >&2
exit 1
fi
echo "Found attestation digest ${attestation_digest}"
docker buildx imagetools inspect --raw "$IMAGE_REPO@$attestation_digest" > "$TMP_DIR/attestation.json"
jq . "$TMP_DIR/attestation.json"
spdx_layer_digest="$(jq -r '.layers[] | select(.annotations["in-toto.io/predicate-type"] == "https://spdx.dev/Document") | .digest' "$TMP_DIR/attestation.json")"
if [ -z "$spdx_layer_digest" ]; then
echo "No SPDX layer found in attestation manifest ${attestation_digest}" >&2
exit 1
fi
echo "Found SPDX layer digest ${spdx_layer_digest}"
oras blob fetch --output - "$IMAGE_ORAS_REPO@$spdx_layer_digest" \
| jq '.predicate' \
> "$OUT_DIR/azure-keyvault-controller_${VERSION}_${os}_${arch}.spdx.json"
done
- name: Publish GitHub Release
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
TAG="${GITHUB_REF_NAME}"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
PREVIOUS_STABLE_TAG="$(git tag --list 'controller-*' --sort=-version:refname | grep -E '^controller-[0-9]+\.[0-9]+\.[0-9]+$' | grep -vx "$TAG" | head -n 1 || true)"
PRERELEASE=false
if [[ "$TAG" == *-alpha* ]] || [[ "$TAG" == *-beta* ]]; then
PRERELEASE=true
fi
if gh release view "$TAG" --repo "${GITHUB_REPOSITORY}" >/dev/null 2>&1; then
gh release delete "$TAG" --repo "${GITHUB_REPOSITORY}" --yes
fi
NOTES_JSON="$TMP_DIR/release-notes.json"
if [ -n "$PREVIOUS_STABLE_TAG" ]; then
gh api \
--method POST \
"repos/${GITHUB_REPOSITORY}/releases/generate-notes" \
-f tag_name="$TAG" \
-f target_commitish="$GITHUB_SHA" \
-f previous_tag_name="$PREVIOUS_STABLE_TAG" \
> "$NOTES_JSON"
else
gh api \
--method POST \
"repos/${GITHUB_REPOSITORY}/releases/generate-notes" \
-f tag_name="$TAG" \
-f target_commitish="$GITHUB_SHA" \
> "$NOTES_JSON"
fi
TITLE="$(jq -r '.name // empty' "$NOTES_JSON")"
if [ -z "$TITLE" ]; then
TITLE="$TAG"
fi
jq -r '.body' "$NOTES_JSON" > "$TMP_DIR/release-notes.md"
ASSETS=(dist/sbom/*.spdx.json)
CREATE_ARGS=("$TAG" "${ASSETS[@]}" "--repo" "${GITHUB_REPOSITORY}" "--verify-tag" "--title" "$TITLE" "--notes-file" "$TMP_DIR/release-notes.md")
if [ "$PRERELEASE" = true ]; then
CREATE_ARGS+=("--prerelease")
fi
gh release create "${CREATE_ARGS[@]}"