ci: add batch image validation and publishing #1
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Batch service image | |
| on: | |
| pull_request: | |
| paths: | |
| - "batch-service/**" | |
| - ".github/workflows/batch-service-image.yaml" | |
| push: | |
| branches: | |
| - main | |
| - dev | |
| paths: | |
| - "batch-service/**" | |
| - ".github/workflows/batch-service-image.yaml" | |
| concurrency: | |
| group: batch-service-image-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| env: | |
| IMAGE_NAME: ghcr.io/phoenixvc/sluice-batch-service | |
| TEST_IMAGE: sluice-batch-service:contract-test | |
| jobs: | |
| validate: | |
| name: Test, build, and smoke image | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.13" | |
| cache: pip | |
| cache-dependency-path: batch-service/requirements-test.txt | |
| - name: Install test dependencies | |
| working-directory: batch-service | |
| run: python -m pip install --requirement requirements-test.txt | |
| - name: Run mocked contract tests | |
| working-directory: batch-service | |
| env: | |
| BATCH_JOB_ID_SIGNING_KEY: contract-tests-only | |
| run: python -m pytest -q | |
| - name: Build image | |
| run: docker build --tag "${TEST_IMAGE}" batch-service | |
| - name: Verify non-root runtime | |
| shell: bash | |
| run: | | |
| runtime_uid="$(docker run --rm "${TEST_IMAGE}" id -u)" | |
| if [[ "${runtime_uid}" == "0" ]]; then | |
| echo "::error::Batch service image runs as root" | |
| exit 1 | |
| fi | |
| echo "Runtime UID: ${runtime_uid}" | |
| - name: Start image | |
| run: | | |
| docker run \ | |
| --detach \ | |
| --name sluice-batch-service-smoke \ | |
| --env BATCH_JOB_ID_SIGNING_KEY=local-image-smoke-only \ | |
| --publish 127.0.0.1:8080:8080 \ | |
| "${TEST_IMAGE}" | |
| - name: Verify signed-job health | |
| shell: bash | |
| run: | | |
| for attempt in {1..30}; do | |
| if response="$(curl --fail --silent http://127.0.0.1:8080/healthz)"; then | |
| if python -c \ | |
| 'import json,sys; data=json.load(sys.stdin); sys.exit(0 if data == {"status":"ok","job_id_signing_configured":True} else 1)' \ | |
| <<< "${response}"; then | |
| echo "Batch service health check passed" | |
| exit 0 | |
| fi | |
| fi | |
| sleep 1 | |
| done | |
| docker logs sluice-batch-service-smoke | |
| echo "::error::Batch service did not report signing configured" | |
| exit 1 | |
| - name: Stop image | |
| if: always() | |
| run: docker rm --force sluice-batch-service-smoke || true | |
| publish: | |
| name: Publish immutable GHCR image | |
| if: github.event_name == 'push' | |
| needs: validate | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: read | |
| packages: write | |
| attestations: write | |
| id-token: write | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract OCI metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=raw,value=${{ github.sha }} | |
| type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} | |
| - name: Build and publish | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: batch-service | |
| file: batch-service/Dockerfile | |
| platforms: linux/amd64 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| provenance: mode=max | |
| sbom: true | |
| cache-from: type=gha,scope=batch-service | |
| cache-to: type=gha,mode=max,scope=batch-service | |
| - name: Write image summary | |
| shell: bash | |
| run: | | |
| { | |
| echo "## Batch service image published" | |
| echo "" | |
| echo "| Reference | Value |" | |
| echo "| --- | --- |" | |
| echo "| SHA tag | \`${IMAGE_NAME}:${GITHUB_SHA}\` |" | |
| echo "| Digest pin | \`${IMAGE_NAME}@${{ steps.build.outputs.digest }}\` |" | |
| } >> "${GITHUB_STEP_SUMMARY}" |