Files
lasuite-messages/.github/workflows/docker-publish.yml
T
BastienandGitHub ac387db978 🔒️(frontend) upgrade deps, add an ip allowlist for django admin, harden github actions
The Scalingo build script pins Caddy a second time, so both pins move
together. The checksums come from the official release checksum files.

DJANGO_ADMIN_IP_ALLOWLIST limits the Django admin URL to a CIDR
list; unset keeps the current open behavior. The client_ip matcher
reads X-Forwarded-For only from MESSAGES_FRONTEND_TRUSTED_PROXIES,
and trusted_proxies_strict takes the rightmost untrusted address, so
a spoofed or appended header never passes the filter. On Scalingo,
set the trusted proxies to private_ranges; the router IP ranges are
not published.

make test-front-distroless builds the production image and smoke-tests
it: heartbeat, lprobe healthcheck, allow/deny cases, spoofed headers,
and the trusted-proxy path. The CI runs it; the published image had no
test before. The script picks bridge or host network mode from the
daemon, so it also runs on Docker Desktop.

A moving major tag can change after a compromise of the action
repository. Each pin keeps the version as a comment. The pins also
upgrade every action to its latest major: the new majors only move the
runtime to node24 and remove inputs these workflows do not use.
crowdin v3 changes only custom CLI args, which we do not pass.

Set persist-credentials: false on every checkout step, so the job
token does not stay in .git/config for later steps. Remove the unused
GITHUB_TOKEN from the crowdin upload workflow: the action reads it
only in the push and pull-request paths, and this workflow disables
both. Restrict the crowdin workflow permissions to contents: read.
2026-09-06 20:50:32 +02:00

155 lines
6.6 KiB
YAML

name: Build and Push Container Image
"on":
workflow_call:
inputs:
registry:
type: string
required: false
default: ghcr.io
description: The container registry FQDN.
image_name:
type: string
required: true
description: The suffix for the image name, without the registry and without the repository path.
context:
type: string
required: true
description: The path to the context to start `docker build` into.
target:
type: string
required: false
default: ""
description: The Dockerfile target stage to build the image for.
arm64_reuse_amd64_build_arg:
type: string
required: false
default: ""
description: "Build arg name to pass first amd64 tag to arm64 build (skips arch-independent build steps)"
build_args:
type: string
required: false
default: ""
description: "Newline-separated KEY=value build args passed to both platform builds (e.g. PYTHON_UV_IMAGE=...)."
dockerfile:
type: string
required: false
default: ""
description: "Path to the Dockerfile (defaults to <context>/Dockerfile). E.g. src/mta-in/Dockerfile.pymta."
outputs:
image_ref:
description: "registry/name@sha256:digest of the published multi-arch image (for downstream `FROM`)."
value: ${{ jobs.docker-build-push.outputs.image_ref }}
# see https://docs.github.com/en/enterprise-cloud@latest/actions/how-tos/use-cases-and-examples/publishing-packages/publishing-docker-images#publishing-images-to-github-packages
jobs:
docker-build-push:
runs-on: ubuntu-latest
outputs:
image_ref: "${{ inputs.registry }}/${{ github.repository }}-${{ inputs.image_name }}@${{ steps.create-manifest.outputs.digest }}"
permissions:
contents: read
packages: write
attestations: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up QEMU
uses: docker/setup-qemu-action@1f40c72289eff860ee54a304f1438e3cff362e0a # v4.3.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0
- name: Log in to the Container registry
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ${{ inputs.registry }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ${{ inputs.registry }}/${{ github.repository }}-${{ inputs.image_name }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Generate platform-specific tags
id: platform-tags
run: |
AMD64_TAGS=$(echo "${{ steps.meta.outputs.tags }}" | sed 's/$/-amd64/')
ARM64_TAGS=$(echo "${{ steps.meta.outputs.tags }}" | sed 's/$/-arm64/')
FIRST_AMD64_TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -1)-amd64
{
echo "amd64<<EOF"
echo "$AMD64_TAGS"
echo "EOF"
echo "arm64<<EOF"
echo "$ARM64_TAGS"
echo "EOF"
echo "amd64_first=$FIRST_AMD64_TAG"
} >> "$GITHUB_OUTPUT"
- name: Build and push (amd64)
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: ${{ inputs.context }}
file: ${{ inputs.dockerfile || format('{0}/Dockerfile', inputs.context) }}
target: ${{ inputs.target }}
platforms: linux/amd64
push: true
provenance: false
tags: ${{ steps.platform-tags.outputs.amd64 }}
labels: ${{ steps.meta.outputs.labels }}
build-args: ${{ inputs.build_args }}
- name: Build and push (arm64)
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: ${{ inputs.context }}
file: ${{ inputs.dockerfile || format('{0}/Dockerfile', inputs.context) }}
target: ${{ inputs.target }}
platforms: linux/arm64
push: true
provenance: false
tags: ${{ steps.platform-tags.outputs.arm64 }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
${{ inputs.build_args }}
${{ inputs.arm64_reuse_amd64_build_arg && format('{0}={1}', inputs.arm64_reuse_amd64_build_arg, steps.platform-tags.outputs.amd64_first) || '' }}
- name: Create multi-arch manifests
id: create-manifest
run: |
IMAGE="${{ inputs.registry }}/${{ github.repository }}-${{ inputs.image_name }}"
readarray -t TAGS <<< "${{ steps.meta.outputs.tags }}"
FIRST_TAG=""
for tag in "${TAGS[@]}"; do
[ -z "$tag" ] && continue
docker buildx imagetools create -t "$tag" \
"${tag}-amd64" "${tag}-arm64"
if [ -z "$FIRST_TAG" ]; then
FIRST_TAG="$tag"
fi
done
# Get the digest of the multi-arch manifest for attestation
# Note: --format '{{.Manifest.Digest}}' is broken (docker/buildx#1175),
# so we compute it from the raw manifest JSON instead.
if [ -n "$FIRST_TAG" ]; then
DIGEST="sha256:$(docker buildx imagetools inspect "$FIRST_TAG" --raw | sha256sum | awk '{print $1}')"
echo "digest=$DIGEST" >> "$GITHUB_OUTPUT"
fi
# This pushes a signed SLSA provenance attestation to the registry,
# tagged as sha256-<digest>. It proves the image was built by this
# workflow from this repo. Verified with: gh attestation verify <image>
- name: Generate artifact attestation
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-name: ${{ inputs.registry }}/${{ github.repository }}-${{ inputs.image_name }}
subject-digest: ${{ steps.create-manifest.outputs.digest }}
push-to-registry: true
- name: Delete all untagged container images
uses: actions/delete-package-versions@e5bc658cc4c965c472efe991f8beea3981499c55 # v5.0.0
with:
package-name: messages-${{ inputs.image_name }}
package-type: 'container'
min-versions-to-keep: 0
delete-only-untagged-versions: true