Skip to content

hooks: fix non-unix gate_socket_transport stub signature (Windows build) #13

hooks: fix non-unix gate_socket_transport stub signature (Windows build)

hooks: fix non-unix gate_socket_transport stub signature (Windows build) #13

Workflow file for this run

name: Docker
# Build and publish the busbar container image (Docker Hub + GHCR) as a multi-arch
# manifest (linux/amd64 + linux/arm64), FROM scratch over static musl binaries.
#
# Triggers:
# - v* tags: publish with the semver tag cascade (X.Y.Z, X.Y, X, latest)
# - workflow_dispatch: publish a `test` tag only — end-to-end pipeline check
# without cutting a release.
#
# Supply chain: both registries carry a GitHub build-provenance attestation
# (stored by GitHub — no extra tags on the repo). Verify with:
# gh attestation verify oci://index.docker.io/getbusbar/busbar:<tag> --repo MattJackson/busbarAI
# Cosign signatures are additionally pushed for the GHCR image only — cosign
# stores signatures as sha256-*.sig tags, which we keep off the Docker Hub tag
# list deliberately (clean public page; GHCR carries them for cosign users):
# cosign verify ghcr.io/mattjackson/busbar:<tag> \
# --certificate-identity-regexp 'https://github.com/MattJackson/busbarAI/\.github/workflows/docker\.yml@.*' \
# --certificate-oidc-issuer https://token.actions.githubusercontent.com
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
version:
description: >-
Publish as this version (e.g. 1.1.0) with the full semver tag cascade +
latest. Only use when the dispatched ref is source-identical to that
release. Leave empty to publish only a `test` tag.
required: false
default: ""
retag_from:
description: >-
Point `latest` at an ALREADY-PUBLISHED version (e.g. 1.1.1) with a
manifest-only retag — no rebuild, and the immutable X.Y.Z tag is never
re-pushed. Skips the build. Leave empty for a normal build.
required: false
default: ""
env:
DOCKERHUB_IMAGE: getbusbar/busbar
GHCR_IMAGE: ghcr.io/mattjackson/busbar
permissions:
contents: read
packages: write # push to GHCR
id-token: write # keyless cosign signing
attestations: write # build-provenance attestation
jobs:
# Manifest-only retag: point `latest` at an already-published version, no rebuild.
# Used when version tags are immutable — the immutable X.Y.Z is never re-pushed.
retag-latest:
name: point latest at ${{ inputs.retag_from }}
if: ${{ inputs.retag_from != '' }}
runs-on: ubuntu-latest
steps:
- uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Retag latest -> ${{ inputs.retag_from }} (multi-arch preserved)
env:
V: ${{ inputs.retag_from }}
run: |
set -euo pipefail
# Docker Hub: point latest at the (immutable) version. Idempotent.
docker buildx imagetools create -t "${DOCKERHUB_IMAGE}:latest" "${DOCKERHUB_IMAGE}:${V}"
# GHCR may be MISSING this version if a prior combined build-push aborted mid-way
# (e.g. Docker Hub tag-immutability rejected `latest` before GHCR finished). Mirror the
# version from Docker Hub into GHCR (cross-registry manifest copy, no rebuild), then move
# GHCR latest onto it. `imagetools create` is a no-op-safe overwrite if it already exists.
docker buildx imagetools create -t "${GHCR_IMAGE}:${V}" "${DOCKERHUB_IMAGE}:${V}"
docker buildx imagetools create -t "${GHCR_IMAGE}:latest" "${GHCR_IMAGE}:${V}"
echo "== Docker Hub latest =="; docker buildx imagetools inspect "${DOCKERHUB_IMAGE}:latest" | grep -iE 'name|platform'
echo "== GHCR ${V} =="; docker buildx imagetools inspect "${GHCR_IMAGE}:${V}" | grep -iE 'name|platform'
# Static musl binaries, one per architecture, built on native runners (no QEMU).
build-binaries:
name: musl ${{ matrix.arch }}
if: ${{ inputs.retag_from == '' }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: true
matrix:
include:
- arch: amd64
os: ubuntu-latest
target: x86_64-unknown-linux-musl
- arch: arm64
os: ubuntu-24.04-arm
target: aarch64-unknown-linux-musl
steps:
- uses: actions/checkout@v7
- name: Install musl toolchain
run: sudo apt-get update && sudo apt-get install -y musl-tools
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Build static binary
env:
# musl-gcc drives both the C compiles (bundled SQLite) and the final link.
CC: musl-gcc
CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER: musl-gcc
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER: musl-gcc
run: |
cargo build --release --target ${{ matrix.target }}
file "target/${{ matrix.target }}/release/busbar"
# Fail loudly if the binary is not fully static — FROM scratch has no loader.
if ldd "target/${{ matrix.target }}/release/busbar" 2>&1 | grep -qv 'not a dynamic\|statically linked'; then
echo "binary is dynamically linked; refusing to ship in FROM scratch" && exit 1
fi
- uses: actions/upload-artifact@v4
with:
name: busbar-${{ matrix.arch }}
path: target/${{ matrix.target }}/release/busbar
if-no-files-found: error
publish:
name: build & push image
needs: build-binaries
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Stage binaries into build context
uses: actions/download-artifact@v4
with:
pattern: busbar-*
path: staged
- name: Arrange per-arch layout
run: |
mkdir -p binaries/amd64 binaries/arm64
mv staged/busbar-amd64/busbar binaries/amd64/busbar
mv staged/busbar-arm64/busbar binaries/arm64/busbar
chmod +x binaries/amd64/busbar binaries/arm64/busbar
- uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# The version being published: the pushed v* tag, or the workflow_dispatch
# `version` input. Empty (bare dispatch) → publish only a `test` tag.
- name: Resolve version
id: ver
run: |
VER="${{ inputs.version }}"
if [ -z "$VER" ] && [ "$GITHUB_REF_TYPE" = "tag" ]; then VER="$GITHUB_REF_NAME"; fi
echo "ver=${VER#v}" >> "$GITHUB_OUTPUT"
- name: Compute tags and labels
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.DOCKERHUB_IMAGE }}
${{ env.GHCR_IMAGE }}
# version resolved → X.Y.Z + latest (exact pins only, no floating
# major/minor aliases — one consistent tag shape); bare dispatch → `test` only.
tags: |
type=semver,pattern={{version}},value=v${{ steps.ver.outputs.ver }},enable=${{ steps.ver.outputs.ver != '' }}
type=raw,value=test,enable=${{ steps.ver.outputs.ver == '' }}
labels: |
org.opencontainers.image.title=busbar
org.opencontainers.image.description=The reliability layer for LLM traffic — one endpoint, six wire protocols, fault-attributed circuit breaking, in-flight failover.
org.opencontainers.image.url=https://getbusbar.com
org.opencontainers.image.documentation=https://getbusbar.com/docs/getting-started/
org.opencontainers.image.licenses=Apache-2.0
- name: Build and push
id: push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Install cosign
uses: sigstore/cosign-installer@v3
# GHCR only: cosign stores signatures as sha256-*.sig tags, which we keep
# off the Docker Hub tag list (clean public page). Hub verification runs
# through the GitHub build-provenance attestation instead.
- name: Sign GHCR image (keyless)
env:
DIGEST: ${{ steps.push.outputs.digest }}
run: cosign sign --yes "${GHCR_IMAGE}@${DIGEST}"
- name: Attest build provenance (Docker Hub)
uses: actions/attest-build-provenance@v4
with:
subject-name: index.docker.io/${{ env.DOCKERHUB_IMAGE }}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: false
- name: Attest build provenance (GHCR)
uses: actions/attest-build-provenance@v4
with:
subject-name: ${{ env.GHCR_IMAGE }}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true