Files
sencho/.github/workflows/docker-dev.yml
T
dependabot[bot] 5264cf1888 chore(deps): bump the all-actions group across 2 directories with 4 updates (#1544)
Bumps the all-actions group with 3 updates in the / directory: [docker/build-push-action](https://github.com/docker/build-push-action), [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) and [actions/github-script](https://github.com/actions/github-script).
Bumps the all-actions group with 1 update in the /.github/actions/start-app directory: [actions/cache](https://github.com/actions/cache).


Updates `docker/build-push-action` from 7.2.0 to 7.3.0
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/f9f3042f7e2789586610d6e8b85c8f03e5195baf...53b7df96c91f9c12dcc8a07bcb9ccacbed38856a)

Updates `docker/setup-qemu-action` from 4.1.0 to 4.2.0
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/06116385d9baf250c9f4dcb4858b16962ea869c3...96fe6ef7f33517b61c61be40b68a1882f3264fb8)

Updates `actions/github-script` from 8.0.0 to 9.0.0
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/ed597411d8f924073f98dfc5c65a23a2325f34cd...3a2844b7e9c422d3c10d287c895573f7108da1b3)

Updates `actions/cache` from 6.0.0 to 6.1.0
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/2c8a9bd7457de244a408f35966fab2fb45fda9c8...55cc8345863c7cc4c66a329aec7e433d2d1c52a9)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 7.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-actions
- dependency-name: docker/setup-qemu-action
  dependency-version: 4.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-actions
- dependency-name: actions/github-script
  dependency-version: 9.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all-actions
- dependency-name: actions/cache
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-01 12:49:15 -04:00

166 lines
7.4 KiB
YAML

name: Build and Publish Dev Image
# ---------------------------------------------------------------------------
# Integration (dev) build vs release build
# ---------------------------------------------------------------------------
# This workflow produces the INTEGRATION image: the running artifact of main
# HEAD, published so a maintainer can pull and smoke-test the exact code queued
# for the next release BEFORE it is ever promoted to a public release tag.
#
# Integration build (this file) Release build (docker-publish.yml)
# ---------------------------------- -----------------------------------
# trigger: push to main trigger: push of a v* tag
# registry: GHCR only registries: Docker Hub + GHCR
# image: ghcr.io/studio-saelix/ images: saelix/sencho (Docker Hub)
# sencho-dev ghcr.io/studio-saelix/sencho
# tags: :dev (moving) + :dev-<sha> tags: latest, X.Y.Z, X.Y
# signing / SBOM / VEX / Release: no signing / SBOM / VEX / Release: yes
# approval gate: none approval gate: production environment
#
# Public release tags (latest, semver, moving-minor), Docker Hub publishing,
# cosign signatures, SBOM/VEX attestations, and GitHub Releases are RELEASE-ONLY
# and live exclusively in docker-publish.yml. The dev tags here are never
# promoted: `:dev` is a moving pointer at main HEAD, and `:dev-<short-sha>` pins
# one build for reproducible testing on a host. Nothing in this file touches
# Docker Hub or the `latest` tag.
# ---------------------------------------------------------------------------
on:
push:
branches:
- main
workflow_dispatch:
concurrency:
# A moving `:dev` tag only ever needs to reflect the newest main commit, so a
# superseded in-flight build can be cancelled. Ref-scoped to match the rest of
# the workflow suite.
group: docker-dev-${{ github.ref }}
cancel-in-progress: true
# Least-privilege: GHCR push only. No id-token (no cosign) and no contents:write
# (no GitHub Release). Deliberately no `production` environment, so an
# integration image publishes automatically with no Docker Hub credentials ever
# in scope for this workflow.
permissions:
contents: read
packages: write
jobs:
push_dev_image:
name: Build and push dev image to GHCR
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Check out the repo
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up QEMU
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4
with:
platforms: arm64
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
# Feeds the Dockerfile's APK_CACHE_BUST arg so the `apk upgrade` layer
# rebuilds at least once per calendar day even when every other input is
# cached, so the Trivy scan below sees a fresh layer. Same rationale as the
# release workflow; see the APK_CACHE_BUST arg in the Dockerfile.
- name: Compute daily apk cache bust value
id: apk-bust
run: echo "date=$(date -u +%Y-%m-%d)" >> "$GITHUB_OUTPUT"
- name: Log in to GitHub Container Registry
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
with:
registry: ghcr.io
# repository_owner is a fixed value (studio-saelix) on every event
# type; GITHUB_TOKEN is what actually authenticates the GHCR push.
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6
with:
# Dedicated dev package, separate from the release package
# ghcr.io/studio-saelix/sencho. Never published to Docker Hub.
images: ghcr.io/studio-saelix/sencho-dev
# :dev moving pointer at the latest main build
# :dev-<sha> immutable per-commit tag for pinning a build on a host
# No latest / semver / moving-minor here: those are release-only and
# live in docker-publish.yml.
tags: |
type=raw,value=dev
type=sha,prefix=dev-,format=short
# Build an amd64-only variant into the local daemon first so Trivy scans
# the exact image before it is pushed, and the multi-arch push below reuses
# these layers from the buildkit daemon cache. Same gate the PR and release
# builds apply. Scanning only amd64 is a defensible proxy for the multi-arch
# manifest: distro package CVEs are arch-agnostic.
- name: Build dev image for pre-publish scan (amd64, loaded)
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
with:
context: .
push: false
load: true
platforms: linux/amd64
tags: localhost/sencho:dev-scan
cache-from: type=gha
build-args: |
APK_CACHE_BUST=${{ steps.apk-bust.outputs.date }}
- name: Scan dev image for vulnerabilities (Trivy)
# Same HIGH/CRITICAL policy and OpenVEX source of truth (trivy.yaml ->
# security/vex/sencho.openvex.json) as PR and release CI. A failing scan
# blocks the `:dev` push, so a vulnerable integration image is never
# published for testing.
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
image-ref: localhost/sencho:dev-scan
exit-code: '1'
severity: 'CRITICAL,HIGH'
format: 'table'
trivy-config: trivy.yaml
# Mirror of the release pre-publish smoke gate in docker-publish.yml:
# verify the source-built Docker CLI/Compose binaries exec, then start the
# container and poll /api/health until it returns 200. Runs BEFORE the push
# so a broken image never moves the `:dev` tag.
- name: Smoke test dev image (pre-publish)
run: |
set -euo pipefail
docker run --rm --entrypoint sh localhost/sencho:dev-scan -c \
'docker --version && docker compose version'
docker run -d --name sencho-dev-smoke -p 1852:1852 localhost/sencho:dev-scan
trap 'docker logs sencho-dev-smoke 2>&1 || true; docker rm -f sencho-dev-smoke >/dev/null 2>&1 || true' EXIT
for i in $(seq 1 30); do
if curl -fsS http://localhost:1852/api/health >/dev/null 2>&1; then
echo "Container healthy after ${i}s"
curl -s http://localhost:1852/api/health
exit 0
fi
sleep 1
done
echo "FAILED: /api/health did not become ready within 30s"
exit 1
- name: Build and push dev image
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# gha cache, kept separate from the release buildcache
# (saelix/sencho:buildcache) so integration builds never pollute the
# cache that release publishes pull from.
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
APK_CACHE_BUST=${{ steps.apk-bust.outputs.date }}