Skip to content

copy: read and write s3:// and http(s):// paths via an object store #12

copy: read and write s3:// and http(s):// paths via an object store

copy: read and write s3:// and http(s):// paths via an object store #12

# Copyright 2026 Query Farm LLC - https://query.farm
#
# Build and publish the multi-arch vgi-cbor image to ghcr.io. The heavy lifting
# (multi-arch build -> per-arch /health boot smoke -> image SQL suite -> push ->
# manifest -> cosign-sign) lives in the shared reusable workflow
# Query-farm/vgi-actions; this file gates on the repo's own test suite and
# supplies the worker-specific inputs.
#
# Tag-driven: vX.Y.Z -> :X.Y.Z/:X.Y/:latest, push to main -> :edge. Publishing a
# GitHub Release creates the tag, which fires this too.
name: Publish image to ghcr.io
on:
push:
branches: [main]
tags: ['v*.*.*']
workflow_dispatch:
permissions:
contents: read
concurrency:
group: docker-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# Gate every image on the full unit + vgi-extension integration suite, so a
# broken worker is never imaged. ci.yml's `audit` job requests `checks: write`
# (rustsec/audit-check posts its findings as a check-run); a called reusable
# workflow cannot request more than the calling job grants, so this gate job
# must grant it too or the whole publish run fails at startup (0s, no jobs).
ci:
permissions:
contents: read
checks: write
uses: ./.github/workflows/ci.yml
publish:
needs: [ci]
permissions:
contents: read
packages: write
id-token: write
attestations: write
uses: Query-farm/vgi-actions/.github/workflows/docker-publish.yml@v1
secrets: inherit
with:
image_name: vgi-cbor
# Rust binary — nothing to `import`, so the language-import smoke is
# skipped. The reusable workflow still runs its dual-arch HTTP /health
# boot smoke.
smoke_import: ""
health_port: "8000"
version_check_cmd: "ci/check-version.sh"
# Validate the built image's transports against the signed vgi extension.
# The worker *logic* is already exercised every run by the gating `ci` job;
# here we only prove the IMAGE's entrypoints speak the protocol:
# - stdio: smoke ONE file through `docker run … stdio` (the on-host mode);
# - HTTP : the FULL suite against a SINGLE warm container (end-to-end
# image check via the default `http` entrypoint + /health).
# $CITEST_IMAGE is the loaded <image>:citest-amd64 ref; GH_TOKEN is
# provided for the download.
image_test: |
echo "::group::download haybarn-unittest"
REL=$(gh release view --repo Query-farm-haybarn/haybarn --json tagName --jq .tagName)
gh release download "$REL" --repo Query-farm-haybarn/haybarn \
--pattern 'haybarn_unittest-linux-amd64.zip' --output hb.zip --clobber
mkdir -p hb && unzip -o -q hb.zip -d hb
export HAYBARN_UNITTEST="$PWD/$(find hb -name 'haybarn-unittest' -type f | head -1)"
chmod +x "$HAYBARN_UNITTEST"
echo "::endgroup::"
echo "::group::stdio entrypoint smoke (one file, cold container per ATTACH)"
TRANSPORT=subprocess \
TEST_PATTERN="test/sql/basic.test" \
VGI_CBOR_WORKER="docker run -i --rm $CITEST_IMAGE stdio" \
ci/run-integration.sh
echo "::endgroup::"
echo "::group::full SQL suite — HTTP transport (one warm container)"
CID=$(docker run -d -p 18000:8000 "$CITEST_IMAGE")
trap 'docker rm -f "$CID" >/dev/null 2>&1 || true' EXIT
for _ in $(seq 1 30); do curl -fsS -o /dev/null http://localhost:18000/health && break; sleep 1; done
TRANSPORT=http VGI_CBOR_WORKER="http://localhost:18000" ci/run-integration.sh
echo "::endgroup::"