Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
276 changes: 276 additions & 0 deletions .github/workflows/staging-dev-relay-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
name: Staging dev relay image

# Publishes pre-merge relay runtime images for bb-block staging only.
#
# Operators run this workflow from the default branch and provide a target ref in
# this repository. GitHub's workflow_dispatch permission model limits triggering
# to collaborators who can run repository workflows; no actor allowlist is kept
# here. The target ref is resolved to an immutable commit SHA before checkout,
# and the published tag is derived from that full SHA.

on:
workflow_dispatch:
inputs:
target_ref:
description: "Branch, tag, refs/heads/*, or refs/tags/* in block/buzz to publish for bb-block staging"
required: true
type: string

permissions: {}

env:
IMAGE_NAME: ghcr.io/block/buzz-staging-dev
ECR_REPOSITORY: 929862310821.dkr.ecr.us-west-2.amazonaws.com/ghcr.io/block/buzz-staging-dev

jobs:
resolve:
name: Resolve target ref
runs-on: ubuntu-24.04
timeout-minutes: 5
permissions:
contents: read
outputs:
target_sha: ${{ steps.resolve.outputs.target_sha }}
image_tag: ${{ steps.resolve.outputs.image_tag }}
steps:
- name: Require reviewed workflow from main in canonical repository
env:
DISPATCH_REF: ${{ github.ref }}
REPOSITORY: ${{ github.repository }}
run: |
set -euo pipefail
if [ "$REPOSITORY" != "block/buzz" ]; then
echo "::error::Staging dev relay image publication is restricted to block/buzz"
exit 1
fi

if [ "$DISPATCH_REF" != "refs/heads/main" ]; then
echo "::error::Dispatch this workflow from main, not $DISPATCH_REF"
exit 1
fi

- name: Resolve target ref in this repository
id: resolve
env:
TARGET_REF_INPUT: ${{ inputs.target_ref }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: |
set -euo pipefail

target_ref=$(printf '%s' "$TARGET_REF_INPUT" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')

if [ -z "$target_ref" ]; then
echo "target_ref must not be empty" >&2
exit 1
fi

if [ ${#target_ref} -gt 255 ]; then
echo "target_ref is too long" >&2
exit 1
fi

if [[ ! "$target_ref" =~ ^[A-Za-z0-9._/@-]+$ ]]; then
echo "target_ref contains unsupported characters; use a branch, tag, or full refs/heads/* or refs/tags/* name" >&2
exit 1
fi

case "$target_ref" in
-*|*..*|*.lock|refs/pull/*|pull/*|*/pull/*)
echo "target_ref is not an allowed repository branch/tag/ref" >&2
exit 1
;;
esac

workdir=$(mktemp -d)
trap 'rm -rf "$workdir"' EXIT
git -C "$workdir" init --quiet
git -C "$workdir" remote add origin "https://github.com/${GITHUB_REPOSITORY}.git"

fetch_commit() {
local ref=$1
git -C "$workdir" fetch --no-tags --depth=1 origin "$ref" >/dev/null 2>&1
git -C "$workdir" rev-parse --verify "FETCH_HEAD^{commit}"
}

target_sha=""
if [[ "$target_ref" == refs/heads/* || "$target_ref" == refs/tags/* ]]; then
target_sha=$(fetch_commit "$target_ref") || {
echo "target_ref did not resolve in ${GITHUB_REPOSITORY}: $target_ref" >&2
exit 1
}
else
if target_sha=$(fetch_commit "refs/heads/${target_ref}"); then
:
elif target_sha=$(fetch_commit "refs/tags/${target_ref}"); then
:
else
echo "target_ref did not resolve as a branch or tag in ${GITHUB_REPOSITORY}: $target_ref" >&2
exit 1
fi
fi

target_sha=$(printf '%s' "$target_sha" | tr '[:upper:]' '[:lower:]')
if [[ ! "$target_sha" =~ ^[0-9a-f]{40}$ ]]; then
echo "resolved target SHA is invalid: $target_sha" >&2
exit 1
fi

image_tag="dev-sha-${target_sha}-run-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
{
echo "target_sha=${target_sha}"
echo "image_tag=${image_tag}"
} >> "$GITHUB_OUTPUT"

printf "Resolved \`%s\` to \`%s\`; image tag \`%s\`.\n" "$target_ref" "$target_sha" "$image_tag" >> "$GITHUB_STEP_SUMMARY"

build:
name: Build staging relay runtime (${{ matrix.platform }})
runs-on: ${{ matrix.runner }}
needs: resolve
timeout-minutes: 60
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-24.04
arch: amd64
- platform: linux/arm64
runner: ubuntu-24.04-arm
arch: arm64
steps:
- name: Checkout resolved target
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
ref: ${{ needs.resolve.outputs.target_sha }}
fetch-depth: 1
persist-credentials: false

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
with:
buildkitd-config-inline: |
[worker.oci]
max-parallelism = 2

- name: Log in to GHCR
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
with:
images: ${{ env.IMAGE_NAME }}
labels: |
org.opencontainers.image.title=Buzz staging dev relay
org.opencontainers.image.description=Pre-merge Buzz relay runtime image for bb-block staging only
org.opencontainers.image.licenses=Apache-2.0
org.opencontainers.image.revision=${{ needs.resolve.outputs.target_sha }}

- name: Build and push runtime image by digest
id: build
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
context: .
file: ./Dockerfile
target: runtime
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
cache-from: |
type=registry,ref=${{ env.IMAGE_NAME }}-buildcache:${{ matrix.arch }}
cache-to: |
type=registry,ref=${{ env.IMAGE_NAME }}-buildcache:${{ matrix.arch }},mode=max,compression=zstd

- name: Export digest
env:
DIGEST: ${{ steps.build.outputs.digest }}
run: |
set -euo pipefail
mkdir -p /tmp/digests-release
touch "/tmp/digests-release/${DIGEST#sha256:}"

- name: Upload digest
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: staging-dev-relay-digests-${{ matrix.arch }}
path: /tmp/digests-release/*
if-no-files-found: error
retention-days: 1

merge:
name: Publish staging relay runtime manifest
runs-on: ubuntu-24.04
needs:
- resolve
- build
timeout-minutes: 15
permissions:
contents: read
packages: write
steps:
- name: Download per-arch digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: /tmp/digests
pattern: staging-dev-relay-digests-*
merge-multiple: true

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0

- name: Log in to GHCR
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Create and push manifest list
id: manifest
working-directory: /tmp/digests
env:
IMAGE_NAME: ${{ env.IMAGE_NAME }}
IMAGE_TAG: ${{ needs.resolve.outputs.image_tag }}
run: |
set -euo pipefail
digests=()
for digest in *; do
digests+=("${IMAGE_NAME}@sha256:${digest}")
done

docker buildx imagetools create -t "${IMAGE_NAME}:${IMAGE_TAG}" "${digests[@]}"
merged_digest=$(docker buildx imagetools inspect "${IMAGE_NAME}:${IMAGE_TAG}" \
--format '{{json .Manifest}}' | jq -r '.digest')
echo "digest=${merged_digest}" >> "$GITHUB_OUTPUT"

- name: Deployment summary
env:
IMAGE_NAME: ${{ env.IMAGE_NAME }}
ECR_REPOSITORY: ${{ env.ECR_REPOSITORY }}
IMAGE_TAG: ${{ needs.resolve.outputs.image_tag }}
TARGET_SHA: ${{ needs.resolve.outputs.target_sha }}
MERGED_DIGEST: ${{ steps.manifest.outputs.digest }}
run: |
{
echo "### Published bb-block staging dev relay image"
echo
echo "**Source commit:** \`${TARGET_SHA}\`"
echo "**GHCR image:** \`${IMAGE_NAME}:${IMAGE_TAG}\`"
echo "**Manifest digest:** \`${MERGED_DIGEST}\`"
echo
echo "Set bb-block staging BPCI values to:"
echo '```yaml'
echo "buzz:"
echo " image:"
echo " repository: ${ECR_REPOSITORY}"
echo " tag: ${IMAGE_TAG}"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
26 changes: 26 additions & 0 deletions docs/staging-dev-relay-images.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Staging dev relay images

Use the **Staging dev relay image** GitHub Actions workflow to publish a pre-merge Buzz relay runtime image for bb-block staging.

1. Run `.github/workflows/staging-dev-relay-image.yml` from the default branch.
2. Enter a `target_ref` from `block/buzz` (`my-branch`, `refs/heads/my-branch`, `my-tag`, or `refs/tags/my-tag`).
3. Wait for the workflow summary. It resolves that ref to a commit and publishes only the relay `runtime` image to:

```text
ghcr.io/block/buzz-staging-dev:dev-sha-<40-character-commit-sha>-run-<run-id>-<run-attempt>
```

4. In `squareup/builderbot-platform-core-infrastructure`, set bb-block staging values to the distinct pull-through ECR path and immutable tag from the workflow summary:

```yaml
buzz:
image:
repository: 929862310821.dkr.ecr.us-west-2.amazonaws.com/ghcr.io/block/buzz-staging-dev
tag: dev-sha-<40-character-commit-sha>-run-<run-id>-<run-attempt>
```

This path is intentionally separate from the production/main relay image path (`ghcr.io/block/buzz`) so a staging-only branch deployment is obvious in BPCI.
Comment thread
TheSentinel454 marked this conversation as resolved.

These images are for manual, pre-merge staging evaluation only. They are not release-qualified and must not be promoted to production or used by the canonical Kargo promotion path.

While bb-block remains a shared staging environment, do not deploy a target ref through this runtime-only path if it changes `migrations/` or requires changes to `deploy/charts/buzz/`. Backwards-compatible migrations can still leave the shared database ahead of the restored `main` image. Use an isolated environment or deployment-time enforcement for those changes.
Loading