Skip to content

imp: public api documentation #56

imp: public api documentation

imp: public api documentation #56

Workflow file for this run

# yaml-language-server: $schema=https://www.schemastore.org/github-workflow.json
name: Canary
on:
push:
branches:
- main
paths:
- "crates/**"
- "proto/**"
- "Cargo.toml"
- "Cargo.lock"
- "Dockerfile"
- ".github/workflows/canary.yml"
workflow_dispatch:
# Cancel in-progress runs when new runs are triggered
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: write
packages: write
env:
CARGO_TERM_COLOR: always
# GitHub Container Registry
GHCR_REGISTRY: ghcr.io
GHCR_IMAGE: ${{ github.repository }}
# Docker Hub
DOCKERHUB_IMAGE: inferadb/inferadb-ledger
jobs:
# Detect if library crates changed (vs server-only or CI-only changes)
changes:
name: Changes
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
outputs:
libraries: ${{ steps.filter.outputs.libraries }}
server: ${{ steps.filter.outputs.server }}
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@e3f713f2d8f53843e71c69a996d56f51aa9adfb9 # v2.14.1
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Check for changes
uses: step-security/paths-filter@6eee183b0d2fd101d3f8ee2935c127bca14c5625 # v3.0.5
id: filter
with:
filters: |
libraries:
- 'crates/types/**'
- 'crates/store/**'
- 'crates/state/**'
- 'crates/proto/**'
- 'crates/raft/**'
- 'crates/sdk/**'
- 'proto/**'
- 'Cargo.toml'
- 'Cargo.lock'
server:
- 'crates/server/**'
- 'Dockerfile'
# Compute canary version from release-please manifest
version:
name: Version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
short_sha: ${{ steps.version.outputs.short_sha }}
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@e3f713f2d8f53843e71c69a996d56f51aa9adfb9 # v2.14.1
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Compute canary version
id: version
run: |
# Read next version from release-please manifest
if [ -f ".release-please-manifest.json" ]; then
NEXT_VERSION=$(jq -r '.["." ] // .[] | select(. != null)' .release-please-manifest.json | head -1)
else
NEXT_VERSION="0.1.0"
fi
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
DATE=$(date -u +%Y%m%d)
# Use dev.YYYYMMDD.N format for chronological semver sorting
CANARY_VERSION="${NEXT_VERSION}-dev.${DATE}.${{ github.run_number }}+${SHORT_SHA}"
echo "version=${CANARY_VERSION}" >> $GITHUB_OUTPUT
echo "short_sha=${SHORT_SHA}" >> $GITHUB_OUTPUT
echo "Canary version: ${CANARY_VERSION}"
# Create GitHub pre-release
create-release:
name: Release
needs: version
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
version: ${{ needs.version.outputs.version }}
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@e3f713f2d8f53843e71c69a996d56f51aa9adfb9 # v2.14.1
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Create Pre-Release
uses: step-security/action-gh-release@d45511d7589f080cf54961ff056b9705a74fd160 # v2.5.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ needs.version.outputs.version }}
name: Canary v${{ needs.version.outputs.version }}
draft: false
prerelease: true
body: |
⚠️ **This is a canary release for testing purposes.**
Built from commit: ${{ github.sha }}
Install with Docker:
```bash
docker pull ${{ env.DOCKERHUB_IMAGE }}:canary
# or
docker pull ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE }}:canary
```
- name: Update canary tag
run: |
git tag -f canary
git push -f origin canary
# Build release binaries for multiple platforms (only if server changed)
build-binaries:
name: Build (${{ matrix.name }})
needs: [changes, version, create-release]
if: needs.changes.outputs.server == 'true'
runs-on: ${{ matrix.os }}
permissions:
contents: write
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
name: Linux AMD64
target: x86_64-unknown-linux-gnu
artifact_name: inferadb-ledger
asset_name: inferadb-ledger-linux-x86_64
- os: ubuntu-24.04-arm
name: Linux ARM64
target: aarch64-unknown-linux-gnu
artifact_name: inferadb-ledger
asset_name: inferadb-ledger-linux-aarch64
- os: macos-latest
name: macOS Apple Silicon
target: aarch64-apple-darwin
artifact_name: inferadb-ledger
asset_name: inferadb-ledger-macos-aarch64
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@e3f713f2d8f53843e71c69a996d56f51aa9adfb9 # v2.14.1
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
with:
toolchain: stable
targets: ${{ matrix.target }}
- name: Install build dependencies (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq mold protobuf-compiler
- name: Install build dependencies (macOS)
if: runner.os == 'macOS'
run: brew install protobuf
- name: Setup sccache
uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9
- name: Configure build environment
run: |
echo "SCCACHE_GHA_ENABLED=true" >> $GITHUB_ENV
echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV
echo "CARGO_INCREMENTAL=0" >> $GITHUB_ENV
if [[ "${{ runner.os }}" == "Linux" ]]; then
echo "RUSTFLAGS=-C codegen-units=16 -C link-arg=-fuse-ld=mold" >> $GITHUB_ENV
elif [[ "${{ runner.os }}" == "macOS" ]]; then
echo "RUSTFLAGS=-C codegen-units=16" >> $GITHUB_ENV
echo "MACOSX_DEPLOYMENT_TARGET=11.0" >> $GITHUB_ENV
fi
- name: Cache Rust dependencies
uses: step-security/rust-cache@9be15b830520fab0ec3939586e917e4855cf76bd # v2.8.3
with:
shared-key: canary-${{ matrix.os }}-${{ matrix.target }}
- name: Build release binary
run: cargo build --release --target ${{ matrix.target }} --package inferadb-ledger-server
- name: Strip binary
run: strip target/${{ matrix.target }}/release/${{ matrix.artifact_name }}
- name: Generate SBOM
run: |
cargo install cargo-sbom
cargo sbom --output-format spdx_json_2_3 > sbom-${{ matrix.target }}.spdx.json
- name: Compress binary
run: |
cd target/${{ matrix.target }}/release
tar czf ${{ matrix.asset_name }}.tar.gz ${{ matrix.artifact_name }}
- name: Upload binary to release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload "v${{ needs.version.outputs.version }}" \
"target/${{ matrix.target }}/release/${{ matrix.asset_name }}.tar.gz"
- name: Upload SBOM to release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload "v${{ needs.version.outputs.version }}" \
"sbom-${{ matrix.target }}.spdx.json"
# Build and push Docker images (only if server changed)
build-docker:
name: Docker (${{ matrix.name }})
needs: [changes, version, create-release]
if: needs.changes.outputs.server == 'true'
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
name: Linux AMD64
runner: ubuntu-latest
suffix: amd64
- platform: linux/arm64
name: Linux ARM64
runner: ubuntu-24.04-arm
suffix: arm64
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@e3f713f2d8f53843e71c69a996d56f51aa9adfb9 # v2.14.1
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Docker Buildx
uses: step-security/setup-buildx-action@8c8aef2d414c0b66518fee2b7084e0986f82d7ac # v3.11.1
- name: Log in to GitHub Container Registry
uses: step-security/docker-login-action@c3e677aae8393bc9c81cfdf9709648720ea4bd4d # v3.6.0
with:
registry: ${{ env.GHCR_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
with:
images: ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE }}
tags: |
type=raw,value=canary
type=raw,value=canary-${{ needs.version.outputs.short_sha }}
- name: Build and push by digest
id: build
uses: step-security/docker-build-push-action@a8c3d08b23f8be6aeed43eb1a14ce6fe51284438 # v6.18.0
with:
context: .
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=gha,scope=canary-${{ matrix.suffix }}
cache-to: type=gha,mode=max,scope=canary-${{ matrix.suffix }}
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: digests-canary-${{ matrix.suffix }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
# Merge platform-specific images into multi-arch manifest (only if server changed)
merge-docker:
name: Docker Manifest
runs-on: ubuntu-latest
needs: [changes, version, build-docker]
if: needs.changes.outputs.server == 'true'
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@e3f713f2d8f53843e71c69a996d56f51aa9adfb9 # v2.14.1
with:
egress-policy: audit
- name: Download digests
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
path: /tmp/digests
pattern: digests-canary-*
merge-multiple: true
- name: Set up Docker Buildx
uses: step-security/setup-buildx-action@8c8aef2d414c0b66518fee2b7084e0986f82d7ac # v3.11.1
- name: Log in to GitHub Container Registry
uses: step-security/docker-login-action@c3e677aae8393bc9c81cfdf9709648720ea4bd4d # v3.6.0
with:
registry: ${{ env.GHCR_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to Docker Hub
uses: step-security/docker-login-action@c3e677aae8393bc9c81cfdf9709648720ea4bd4d # v3.6.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Create and push manifest to ghcr.io
working-directory: /tmp/digests
run: |
docker buildx imagetools create \
-t ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE }}:canary \
-t ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE }}:canary-${{ needs.version.outputs.short_sha }} \
$(printf '${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE }}@sha256:%s ' *)
- name: Copy manifest to Docker Hub
run: |
docker buildx imagetools create \
-t ${{ env.DOCKERHUB_IMAGE }}:canary \
-t ${{ env.DOCKERHUB_IMAGE }}:canary-${{ needs.version.outputs.short_sha }} \
${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE }}:canary
- name: Inspect images
run: |
echo "=== ghcr.io ==="
docker buildx imagetools inspect ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE }}:canary
echo "=== Docker Hub ==="
docker buildx imagetools inspect ${{ env.DOCKERHUB_IMAGE }}:canary
# Generate SBOM for Docker image (only if server changed)
sbom-docker:
name: Docker SBOM
runs-on: ubuntu-latest
needs: [changes, version, merge-docker]
if: needs.changes.outputs.server == 'true'
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@e3f713f2d8f53843e71c69a996d56f51aa9adfb9 # v2.14.1
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Log in to GitHub Container Registry
uses: step-security/docker-login-action@c3e677aae8393bc9c81cfdf9709648720ea4bd4d # v3.6.0
with:
registry: ${{ env.GHCR_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate SBOM
uses: anchore/sbom-action@deef08a0db64bfad603422135db61477b16cef56 # v0.22.1
with:
image: ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE }}:canary
artifact-name: docker-sbom.spdx.json
output-file: docker-sbom.spdx.json
- name: Upload SBOM to release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload "v${{ needs.version.outputs.version }}" \
docker-sbom.spdx.json --clobber || true
# Publish crates to crates.io with canary version (only if libraries changed)
publish-crates:
name: Crates
needs: [changes, version, create-release]
if: needs.changes.outputs.libraries == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@e3f713f2d8f53843e71c69a996d56f51aa9adfb9 # v2.14.1
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@881ba7bf39a41cda34ac9e123fb41b44ed08232f # stable
- name: Install protobuf compiler
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq protobuf-compiler
- name: Update crate versions
env:
VERSION: ${{ needs.version.outputs.version }}
run: |
# Update workspace version (strip build metadata for crates.io)
# Dev versions are like 0.1.0-dev.20260201.123+abc1234, but crates.io
# doesn't support build metadata, so we use 0.1.0-dev.20260201.123
CRATE_VERSION="${VERSION%+*}"
sed -i "s/^version = \".*\"/version = \"${CRATE_VERSION}\"/" Cargo.toml
# Update inter-crate dependency versions to use exact prerelease version
# (semver ranges like ^0.1.0 don't match prereleases)
for crate in inferadb-ledger-types inferadb-ledger-store inferadb-ledger-state inferadb-ledger-proto inferadb-ledger-raft inferadb-ledger-sdk; do
sed -i "s/\(${crate} = { version = \)\"[^\"]*\"/\1\"=${CRATE_VERSION}\"/" Cargo.toml
done
- name: Cache Rust dependencies
uses: step-security/rust-cache@9be15b830520fab0ec3939586e917e4855cf76bd # v2.8.3
- name: Authenticate with crates.io
uses: rust-lang/crates-io-auth-action@b7e9a28eded4986ec6b1fa40eeee8f8f165559ec # v1.0.3
id: auth
- name: Publish crates
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
run: |
for crate in inferadb-ledger-types inferadb-ledger-store inferadb-ledger-state inferadb-ledger-proto inferadb-ledger-raft inferadb-ledger-sdk; do
echo "Publishing ${crate}..."
cargo publish -p "${crate}" --token "$CARGO_REGISTRY_TOKEN" --allow-dirty
echo "Waiting for crates.io to index..."
sleep 45
done
# Clean up old canary releases to avoid clutter
# Keeps the last 7 days of releases, or at least the last 10
cleanup:
name: Cleanup
needs: [create-release]
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
env:
REPO: ${{ github.repository }}
OWNER: ${{ github.repository_owner }}
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@e3f713f2d8f53843e71c69a996d56f51aa9adfb9 # v2.14.1
with:
egress-policy: audit
- name: Clean up old canary releases and tags
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
# Configuration
KEEP_DAYS=7
MIN_KEEP=10
echo "=== Cleaning up old canary releases ==="
# Get all canary releases sorted by date (oldest first)
RELEASES=$(gh api "repos/${REPO}/releases" \
--jq '[.[] | select(.tag_name | test("canary")) | {id: .id, tag: .tag_name, date: .created_at}] | sort_by(.date)')
TOTAL=$(echo "$RELEASES" | jq 'length')
echo "Found $TOTAL canary releases"
if [ "$TOTAL" -le "$MIN_KEEP" ]; then
echo "Only $TOTAL releases exist, keeping all (minimum: $MIN_KEEP)"
exit 0
fi
# Calculate cutoff date (7 days ago)
CUTOFF_DATE=$(date -d "-${KEEP_DAYS} days" -u +%Y-%m-%dT%H:%M:%SZ)
echo "Cutoff date: $CUTOFF_DATE"
# Find releases older than cutoff, but ensure we keep at least MIN_KEEP
OLD_RELEASES=$(echo "$RELEASES" | jq --arg cutoff "$CUTOFF_DATE" \
'[.[] | select(.date < $cutoff)]')
OLD_COUNT=$(echo "$OLD_RELEASES" | jq 'length')
# Calculate how many we can actually delete
CAN_DELETE=$((TOTAL - MIN_KEEP))
if [ "$OLD_COUNT" -gt "$CAN_DELETE" ]; then
TO_DELETE=$CAN_DELETE
else
TO_DELETE=$OLD_COUNT
fi
echo "Releases older than $KEEP_DAYS days: $OLD_COUNT"
echo "Will delete: $TO_DELETE (keeping at least $MIN_KEEP)"
if [ "$TO_DELETE" -eq 0 ]; then
echo "Nothing to delete"
exit 0
fi
# Delete oldest releases (up to TO_DELETE)
echo "$OLD_RELEASES" | jq -r ".[:$TO_DELETE][] | \"\(.id) \(.tag)\"" | while read -r ID TAG; do
echo "Deleting release: $TAG (ID: $ID)"
gh api -X DELETE "repos/${REPO}/releases/$ID" || true
# Also delete the associated tag
echo "Deleting tag: $TAG"
gh api -X DELETE "repos/${REPO}/git/refs/tags/$TAG" || true
done
echo "=== Cleanup complete ==="
- name: Clean up old GHCR images
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
# Configuration
KEEP_DAYS=7
MIN_KEEP=10
PACKAGE_NAME="ledger"
echo "=== Cleaning up old GHCR canary images ==="
# Get all versions of the package, filter to canary tags
VERSIONS=$(gh api "orgs/${OWNER}/packages/container/${PACKAGE_NAME}/versions" \
--jq '[.[] | select(.metadata.container.tags | any(test("^canary"))) | {id: .id, tags: .metadata.container.tags, date: .created_at}] | sort_by(.date)' 2>/dev/null || echo "[]")
TOTAL=$(echo "$VERSIONS" | jq 'length')
echo "Found $TOTAL canary image versions"
if [ "$TOTAL" -le "$MIN_KEEP" ]; then
echo "Only $TOTAL versions exist, keeping all (minimum: $MIN_KEEP)"
exit 0
fi
# Calculate cutoff date
CUTOFF_DATE=$(date -d "-${KEEP_DAYS} days" -u +%Y-%m-%dT%H:%M:%SZ)
echo "Cutoff date: $CUTOFF_DATE"
# Find versions older than cutoff
OLD_VERSIONS=$(echo "$VERSIONS" | jq --arg cutoff "$CUTOFF_DATE" \
'[.[] | select(.date < $cutoff)]')
OLD_COUNT=$(echo "$OLD_VERSIONS" | jq 'length')
# Calculate how many we can delete
CAN_DELETE=$((TOTAL - MIN_KEEP))
if [ "$OLD_COUNT" -gt "$CAN_DELETE" ]; then
TO_DELETE=$CAN_DELETE
else
TO_DELETE=$OLD_COUNT
fi
echo "Versions older than $KEEP_DAYS days: $OLD_COUNT"
echo "Will delete: $TO_DELETE (keeping at least $MIN_KEEP)"
if [ "$TO_DELETE" -eq 0 ]; then
echo "Nothing to delete"
exit 0
fi
# Delete oldest versions
echo "$OLD_VERSIONS" | jq -r ".[:$TO_DELETE][] | \"\(.id) \(.tags | join(\", \"))\"" | while read -r ID TAGS; do
echo "Deleting GHCR version: $TAGS (ID: $ID)"
gh api -X DELETE "orgs/${OWNER}/packages/container/${PACKAGE_NAME}/versions/$ID" || true
done
echo "=== GHCR cleanup complete ==="