mirror of
https://github.com/data-privacy-stack/presidio.git
synced 2026-09-21 13:38:05 -05:00
ci: publish distroless variants and rebuild images weekly
Extract the release build/push and manifest jobs into a reusable build-images.yml workflow, extend it with a distroless variant, and add a weekly rebuild-images.yml so digest-pinned bases pick up security updates without a manual re-pin. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
Copilot App
parent
a04e702875
commit
a3f351261a
@@ -0,0 +1,166 @@
|
|||||||
|
name: Build and Push Images
|
||||||
|
|
||||||
|
# Reusable image build. Called by release.yml when cutting a release and by
|
||||||
|
# rebuild-images.yml on a schedule, so that published images pick up base image
|
||||||
|
# security updates without waiting for the next release.
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: Tag applied to the analyzer, anonymizer and CLI-adjacent images.
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
image-version:
|
||||||
|
description: Tag applied to the image-redactor image.
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
date-tag:
|
||||||
|
description: >
|
||||||
|
Optional immutable suffix, e.g. 20260909. When set, each image is also
|
||||||
|
pushed as <version>-<date-tag> so a specific rebuild can be pinned or
|
||||||
|
rolled back to.
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
|
||||||
|
permissions: read-all
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE_REGISTRY: ghcr.io
|
||||||
|
IMAGE_NAMESPACE: data-privacy-stack
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push-containers:
|
||||||
|
name: Build and Push ${{ matrix.image }}${{ matrix.tag_suffix }} (${{ matrix.platform }})
|
||||||
|
runs-on: ${{ matrix.platform == 'linux/arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
id-token: write
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
image: [presidio-anonymizer, presidio-analyzer, presidio-image-redactor]
|
||||||
|
platform: [linux/amd64, linux/arm64]
|
||||||
|
variant: [default, distroless]
|
||||||
|
exclude:
|
||||||
|
# No distroless variant is published for the image-redactor: it
|
||||||
|
# depends on the Tesseract OCR system packages, which are not
|
||||||
|
# available in a distroless base image.
|
||||||
|
- image: presidio-image-redactor
|
||||||
|
variant: distroless
|
||||||
|
include:
|
||||||
|
- platform: linux/amd64
|
||||||
|
platform_tag: linux-amd64
|
||||||
|
- platform: linux/arm64
|
||||||
|
platform_tag: linux-arm64
|
||||||
|
- variant: default
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
tag_suffix: ''
|
||||||
|
- variant: distroless
|
||||||
|
dockerfile: Dockerfile.distroless
|
||||||
|
tag_suffix: -distroless
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Log in to GitHub Container Registry
|
||||||
|
env:
|
||||||
|
GHCR_TOKEN: ${{ github.repository_owner == 'data-privacy-stack' && github.token || secrets.GHCR_TOKEN }}
|
||||||
|
GHCR_USERNAME: ${{ github.repository_owner == 'data-privacy-stack' && github.actor || vars.GHCR_USERNAME || github.actor }}
|
||||||
|
run: echo "${GHCR_TOKEN}" | docker login ${{ env.IMAGE_REGISTRY }} -u "${GHCR_USERNAME}" --password-stdin
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||||
|
|
||||||
|
- name: Build and Push ${{ matrix.image }}${{ matrix.tag_suffix }} for ${{ matrix.platform }}
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
repo="${IMAGE_REGISTRY}/${IMAGE_NAMESPACE}/${{ matrix.image }}"
|
||||||
|
version_tag="${VERSION}"
|
||||||
|
if [ "${{ matrix.image }}" = "presidio-image-redactor" ]; then
|
||||||
|
version_tag="${IMAGE_VERSION}"
|
||||||
|
fi
|
||||||
|
suffix="${{ matrix.tag_suffix }}"
|
||||||
|
platform_tag="${{ matrix.platform_tag }}"
|
||||||
|
|
||||||
|
tag_args="--tag ${repo}:latest${suffix}-${platform_tag}"
|
||||||
|
tag_args="${tag_args} --tag ${repo}:${version_tag}${suffix}-${platform_tag}"
|
||||||
|
if [ -n "${DATE_TAG}" ]; then
|
||||||
|
tag_args="${tag_args} --tag ${repo}:${version_tag}-${DATE_TAG}${suffix}-${platform_tag}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
docker buildx build \
|
||||||
|
--platform ${{ matrix.platform }} \
|
||||||
|
--file ./${{ matrix.image }}/${{ matrix.dockerfile }} \
|
||||||
|
--cache-from type=registry,ref=${repo}:latest${suffix} \
|
||||||
|
--cache-to type=inline \
|
||||||
|
${tag_args} \
|
||||||
|
--attest type=sbom \
|
||||||
|
--attest type=provenance,mode=max \
|
||||||
|
--push \
|
||||||
|
./${{ matrix.image }}
|
||||||
|
env:
|
||||||
|
VERSION: ${{ inputs.version }}
|
||||||
|
IMAGE_VERSION: ${{ inputs.image-version }}
|
||||||
|
DATE_TAG: ${{ inputs.date-tag }}
|
||||||
|
|
||||||
|
create-container-manifests:
|
||||||
|
name: Create Multi-Platform Container Manifests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build-and-push-containers
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
steps:
|
||||||
|
- name: Log in to GitHub Container Registry
|
||||||
|
env:
|
||||||
|
GHCR_TOKEN: ${{ github.repository_owner == 'data-privacy-stack' && github.token || secrets.GHCR_TOKEN }}
|
||||||
|
GHCR_USERNAME: ${{ github.repository_owner == 'data-privacy-stack' && github.actor || vars.GHCR_USERNAME || github.actor }}
|
||||||
|
run: echo "${GHCR_TOKEN}" | docker login ${{ env.IMAGE_REGISTRY }} -u "${GHCR_USERNAME}" --password-stdin
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||||
|
|
||||||
|
- name: Create multi-platform manifests
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
images=(presidio-anonymizer presidio-analyzer presidio-image-redactor)
|
||||||
|
platform_tags=(linux-amd64 linux-arm64)
|
||||||
|
|
||||||
|
for image in "${images[@]}"; do
|
||||||
|
repo="${IMAGE_REGISTRY}/${IMAGE_NAMESPACE}/${image}"
|
||||||
|
version_tag="${VERSION}"
|
||||||
|
suffixes=("" "-distroless")
|
||||||
|
if [ "${image}" = "presidio-image-redactor" ]; then
|
||||||
|
version_tag="${IMAGE_VERSION}"
|
||||||
|
suffixes=("")
|
||||||
|
fi
|
||||||
|
|
||||||
|
for suffix in "${suffixes[@]}"; do
|
||||||
|
tags=("latest${suffix}" "${version_tag}${suffix}")
|
||||||
|
if [ -n "${DATE_TAG}" ]; then
|
||||||
|
tags+=("${version_tag}-${DATE_TAG}${suffix}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
for tag in "${tags[@]}"; do
|
||||||
|
platform_refs=()
|
||||||
|
for platform_tag in "${platform_tags[@]}"; do
|
||||||
|
platform_refs+=("${repo}:${tag}-${platform_tag}")
|
||||||
|
done
|
||||||
|
|
||||||
|
docker buildx imagetools create \
|
||||||
|
--tag "${repo}:${tag}" \
|
||||||
|
"${platform_refs[@]}"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
env:
|
||||||
|
VERSION: ${{ inputs.version }}
|
||||||
|
IMAGE_VERSION: ${{ inputs.image-version }}
|
||||||
|
DATE_TAG: ${{ inputs.date-tag }}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
name: Rebuild Images
|
||||||
|
|
||||||
|
# Published images pin their base image by digest, so they never pick up
|
||||||
|
# operating system security updates on their own. Rebuilding on a schedule
|
||||||
|
# republishes the same versions on top of a freshly patched base, which is what
|
||||||
|
# container compliance scanners expect ("redeploy the image", "update the
|
||||||
|
# vulnerable image reference").
|
||||||
|
#
|
||||||
|
# Rebuilds do not change any application code: the workflow builds the current
|
||||||
|
# state of main and republishes the `latest` and current version tags, plus an
|
||||||
|
# immutable `<version>-<date>` tag so a specific rebuild can be pinned.
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
# Every Monday at 05:00 UTC.
|
||||||
|
- cron: '0 5 * * 1'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions: read-all
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
get-version:
|
||||||
|
name: Get Version Numbers
|
||||||
|
runs-on: ubuntu-slim
|
||||||
|
outputs:
|
||||||
|
version: ${{ steps.set-version.outputs.version }}
|
||||||
|
image-version: ${{ steps.set-image-version.outputs.image-version }}
|
||||||
|
date-tag: ${{ steps.set-date-tag.outputs.date-tag }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Extract main version
|
||||||
|
id: set-version
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
ver=$(grep -m 1 version presidio-analyzer/pyproject.toml | tr -s ' ' | tr -d '"' | tr -d "'" | cut -d' ' -f3)
|
||||||
|
echo "version=$ver" >> $GITHUB_OUTPUT
|
||||||
|
echo "Main version: $ver"
|
||||||
|
|
||||||
|
- name: Extract image-redactor version
|
||||||
|
id: set-image-version
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
imageVer=$(grep -m 1 version presidio-image-redactor/pyproject.toml | tr -s ' ' | tr -d '"' | tr -d "'" | cut -d' ' -f3)
|
||||||
|
echo "image-version=$imageVer" >> $GITHUB_OUTPUT
|
||||||
|
echo "Image-redactor version: $imageVer"
|
||||||
|
|
||||||
|
- name: Set date tag
|
||||||
|
id: set-date-tag
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
dateTag=$(date -u +'%Y%m%d')
|
||||||
|
echo "date-tag=$dateTag" >> $GITHUB_OUTPUT
|
||||||
|
echo "Date tag: $dateTag"
|
||||||
|
|
||||||
|
rebuild-and-push-containers:
|
||||||
|
name: Rebuild and Push Container Images
|
||||||
|
needs: get-version
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
id-token: write
|
||||||
|
uses: ./.github/workflows/build-images.yml
|
||||||
|
with:
|
||||||
|
version: ${{ needs.get-version.outputs.version }}
|
||||||
|
image-version: ${{ needs.get-version.outputs.image-version }}
|
||||||
|
date-tag: ${{ needs.get-version.outputs.date-tag }}
|
||||||
|
secrets: inherit
|
||||||
@@ -5,10 +5,6 @@ on:
|
|||||||
|
|
||||||
permissions: read-all
|
permissions: read-all
|
||||||
|
|
||||||
env:
|
|
||||||
IMAGE_REGISTRY: ghcr.io
|
|
||||||
IMAGE_NAMESPACE: data-privacy-stack
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
get-version:
|
get-version:
|
||||||
name: Get Version Numbers
|
name: Get Version Numbers
|
||||||
@@ -114,101 +110,14 @@ jobs:
|
|||||||
skip-existing: true
|
skip-existing: true
|
||||||
|
|
||||||
build-and-push-containers:
|
build-and-push-containers:
|
||||||
name: Build and Push ${{ matrix.image }} (${{ matrix.platform }})
|
name: Build and Push Container Images
|
||||||
runs-on: ${{ matrix.platform == 'linux/arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
|
|
||||||
needs: get-version
|
needs: get-version
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
id-token: write
|
id-token: write
|
||||||
strategy:
|
uses: ./.github/workflows/build-images.yml
|
||||||
fail-fast: false
|
with:
|
||||||
matrix:
|
version: ${{ needs.get-version.outputs.version }}
|
||||||
image: [presidio-anonymizer, presidio-analyzer, presidio-image-redactor]
|
image-version: ${{ needs.get-version.outputs.image-version }}
|
||||||
platform: [linux/amd64, linux/arm64]
|
secrets: inherit
|
||||||
include:
|
|
||||||
- platform: linux/amd64
|
|
||||||
platform_tag: linux-amd64
|
|
||||||
- platform: linux/arm64
|
|
||||||
platform_tag: linux-arm64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.0
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- name: Log in to GitHub Container Registry
|
|
||||||
env:
|
|
||||||
GHCR_TOKEN: ${{ github.repository_owner == 'data-privacy-stack' && github.token || secrets.GHCR_TOKEN }}
|
|
||||||
GHCR_USERNAME: ${{ github.repository_owner == 'data-privacy-stack' && github.actor || vars.GHCR_USERNAME || github.actor }}
|
|
||||||
run: echo "${GHCR_TOKEN}" | docker login ${{ env.IMAGE_REGISTRY }} -u "${GHCR_USERNAME}" --password-stdin
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
|
||||||
|
|
||||||
- name: Build and Push ${{ matrix.image }} for ${{ matrix.platform }}
|
|
||||||
run: |
|
|
||||||
repo="${IMAGE_REGISTRY}/${IMAGE_NAMESPACE}/${{ matrix.image }}"
|
|
||||||
version_tag="${VERSION}"
|
|
||||||
if [ "${{ matrix.image }}" = "presidio-image-redactor" ]; then
|
|
||||||
version_tag="${IMAGE_VERSION}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
docker buildx build \
|
|
||||||
--platform ${{ matrix.platform }} \
|
|
||||||
--cache-from type=registry,ref=${repo}:latest \
|
|
||||||
--cache-to type=inline \
|
|
||||||
--tag "${repo}:latest-${{ matrix.platform_tag }}" \
|
|
||||||
--tag "${repo}:${version_tag}-${{ matrix.platform_tag }}" \
|
|
||||||
--attest type=sbom \
|
|
||||||
--attest type=provenance,mode=max \
|
|
||||||
--push \
|
|
||||||
./${{ matrix.image }}
|
|
||||||
env:
|
|
||||||
VERSION: ${{ needs.get-version.outputs.version }}
|
|
||||||
IMAGE_VERSION: ${{ needs.get-version.outputs.image-version }}
|
|
||||||
|
|
||||||
create-container-manifests:
|
|
||||||
name: Create Multi-Platform Container Manifests
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [get-version, build-and-push-containers]
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
steps:
|
|
||||||
- name: Log in to GitHub Container Registry
|
|
||||||
env:
|
|
||||||
GHCR_TOKEN: ${{ github.repository_owner == 'data-privacy-stack' && github.token || secrets.GHCR_TOKEN }}
|
|
||||||
GHCR_USERNAME: ${{ github.repository_owner == 'data-privacy-stack' && github.actor || vars.GHCR_USERNAME || github.actor }}
|
|
||||||
run: echo "${GHCR_TOKEN}" | docker login ${{ env.IMAGE_REGISTRY }} -u "${GHCR_USERNAME}" --password-stdin
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
|
||||||
|
|
||||||
- name: Create multi-platform manifests
|
|
||||||
run: |
|
|
||||||
images=(presidio-anonymizer presidio-analyzer presidio-image-redactor)
|
|
||||||
platform_tags=(linux-amd64 linux-arm64)
|
|
||||||
|
|
||||||
for image in "${images[@]}"; do
|
|
||||||
repo="${IMAGE_REGISTRY}/${IMAGE_NAMESPACE}/${image}"
|
|
||||||
version_tag="${VERSION}"
|
|
||||||
if [ "${image}" = "presidio-image-redactor" ]; then
|
|
||||||
version_tag="${IMAGE_VERSION}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
for tag in latest "${version_tag}"; do
|
|
||||||
platform_refs=()
|
|
||||||
for platform_tag in "${platform_tags[@]}"; do
|
|
||||||
platform_refs+=("${repo}:${tag}-${platform_tag}")
|
|
||||||
done
|
|
||||||
|
|
||||||
docker buildx imagetools create \
|
|
||||||
--tag "${repo}:${tag}" \
|
|
||||||
"${platform_refs[@]}"
|
|
||||||
done
|
|
||||||
done
|
|
||||||
env:
|
|
||||||
VERSION: ${{ needs.get-version.outputs.version }}
|
|
||||||
IMAGE_VERSION: ${{ needs.get-version.outputs.image-version }}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user