mirror of
https://github.com/suitenumerique/messages.git
synced 2026-10-01 22:24:57 +02:00
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.
155 lines
6.6 KiB
YAML
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
|