Files
SharedWorkflows/.gitea/workflows/docker-publish.yml
T
2026-07-20 23:03:08 +02:00

206 lines
7.8 KiB
YAML

name: Reusable Docker Publish
on:
workflow_call:
inputs:
image_name:
required: true
type: string
dockerfile_path:
type: string
default: "."
floating_tag:
type: string
default: "edge"
run_image_scan:
type: boolean
default: true
scan_severity:
type: string
default: "HIGH,CRITICAL"
use_private_index:
# pass the private Gitea PyPI index into the build as a BuildKit secret, for images
# whose Dockerfile installs the in-house BB* packages. The Dockerfile must consume it
# via `RUN --mount=type=secret,id=pip_extra_index`, never as an ARG or ENV, so the
# token is not baked into an image layer.
type: boolean
default: false
secrets:
REGISTRY_USERNAME: { required: true }
REGISTRY_PASSWORD: { required: true }
DOCKER_REGISTRY: { required: true }
NTFY_TOPIC: { required: true }
NTFY_TOKEN: { required: true }
NTFY_SERVER: { required: true }
PIP_EXTRA_INDEX_URL: { required: false }
jobs:
publish:
runs-on: docker
container:
image: gitea.tech-buddy.at/bitbuddydev/gitea_runner_python314:dev-bda315b82bb23d83065b77d91fedf0e20d9accf1
credentials:
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Extract Tags
id: vars
shell: bash
run: |
SHA_SHORT="$(git rev-parse --short HEAD)"
FULL_IMAGE="${{ secrets.DOCKER_REGISTRY }}/${{ inputs.image_name }}"
TAGS="-t ${FULL_IMAGE}:${SHA_SHORT}"
if echo "${{ gitea.ref }}" | grep -q '^refs/tags/v'; then
VERSION="${{ gitea.ref_name }}"
VERSION="${VERSION#v}"
MAJOR="$(echo "$VERSION" | cut -d. -f1)"
MINOR="$(echo "$VERSION" | cut -d. -f1,2)"
TAGS="${TAGS} -t ${FULL_IMAGE}:latest -t ${FULL_IMAGE}:${VERSION} -t ${FULL_IMAGE}:${MINOR} -t ${FULL_IMAGE}:${MAJOR}"
fi
echo "docker_tags=${TAGS}" >> "$GITEA_OUTPUT"
echo "full_image=${FULL_IMAGE}" >> "$GITEA_OUTPUT"
- name: Docker Login
run: |
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login "${{ secrets.DOCKER_REGISTRY }}" -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
- name: Build image
shell: bash
env:
PIP_EXTRA_INDEX_URL: ${{ secrets.PIP_EXTRA_INDEX_URL }}
run: |
set -euo pipefail
SHA_SHORT="$(git rev-parse --short HEAD)"
FULL_IMAGE="${{ secrets.DOCKER_REGISTRY }}/${{ inputs.image_name }}"
# optionally hand the private package index to the build as a BuildKit secret so the
# Dockerfile can install the in-house BB* packages without the token entering a layer
SECRET_ARGS=""
if [ "${{ inputs.use_private_index }}" = "true" ]; then
if [ -z "${PIP_EXTRA_INDEX_URL:-}" ]; then
echo "use_private_index=true but the PIP_EXTRA_INDEX_URL secret is empty or not set"
exit 1
fi
SECRET_ARGS="--secret id=pip_extra_index,env=PIP_EXTRA_INDEX_URL"
fi
DOCKER_BUILDKIT=1 docker build \
${SECRET_ARGS} \
-t "${FULL_IMAGE}:${SHA_SHORT}" \
${{ inputs.dockerfile_path }}
# Floating tag points at the most recent build on any branch/tag, so
# the nightly image-security scan always has a stable target even
# before a release exists. ":latest" stays release-only (below).
docker tag "${FULL_IMAGE}:${SHA_SHORT}" "${FULL_IMAGE}:${{ inputs.floating_tag }}"
if echo "${{ gitea.ref }}" | grep -q '^refs/tags/v'; then
VERSION="${{ gitea.ref_name }}"
VERSION="${VERSION#v}"
MAJOR="$(echo "$VERSION" | cut -d. -f1)"
MINOR="$(echo "$VERSION" | cut -d. -f1,2)"
docker tag "${FULL_IMAGE}:${SHA_SHORT}" "${FULL_IMAGE}:latest"
docker tag "${FULL_IMAGE}:${SHA_SHORT}" "${FULL_IMAGE}:${VERSION}"
docker tag "${FULL_IMAGE}:${SHA_SHORT}" "${FULL_IMAGE}:${MINOR}"
docker tag "${FULL_IMAGE}:${SHA_SHORT}" "${FULL_IMAGE}:${MAJOR}"
fi
- name: Image Vulnerability Scan
if: ${{ inputs.run_image_scan }}
shell: bash
run: |
set -euo pipefail
# Fallback for runner images without Trivy baked in. Pinned version +
# checksum, never "latest": Trivy releases were compromised in the
# March 2026 supply-chain incident (malicious v0.69.4). Keep in sync
# with the ARGs in the PipelineImage Dockerfiles.
TRIVY_VERSION=0.71.0
TRIVY_SHA256=30a3d22b23f88c233f1658f562fb477cae3b3e8b4761109d515b7698daf85814
if ! command -v trivy >/dev/null 2>&1; then
echo "=== Trivy not in runner image, installing v${TRIVY_VERSION} ==="
curl -sSfLO "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz"
echo "${TRIVY_SHA256} trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz" | sha256sum -c -
tar -xzf "trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz" -C /usr/local/bin trivy
rm "trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz"
fi
trivy --version
SHA_SHORT="$(git rev-parse --short HEAD)"
FULL_IMAGE="${{ secrets.DOCKER_REGISTRY }}/${{ inputs.image_name }}"
echo "=== Scanning ${FULL_IMAGE}:${SHA_SHORT} (fail on fixable ${{ inputs.scan_severity }}) ==="
trivy image \
--exit-code 1 \
--severity "${{ inputs.scan_severity }}" \
--ignore-unfixed \
--scanners vuln,secret \
"${FULL_IMAGE}:${SHA_SHORT}"
- name: Push image
shell: bash
run: |
set -euxo pipefail
echo "=== Git / Ref Info ==="
git rev-parse HEAD
git rev-parse --short HEAD
echo "gitea.ref=${{ gitea.ref }}"
echo "gitea.ref_name=${{ gitea.ref_name }}"
SHA_SHORT="$(git rev-parse --short HEAD)"
FULL_IMAGE="${{ secrets.DOCKER_REGISTRY }}/${{ inputs.image_name }}"
echo "=== Image Info ==="
echo "FULL_IMAGE=${FULL_IMAGE}"
echo "SHA_SHORT=${SHA_SHORT}"
echo "Expected image: ${FULL_IMAGE}:${SHA_SHORT}"
echo "=== Local Docker Images ==="
docker images | grep "${{ inputs.image_name }}" || true
echo "=== Inspect Image ==="
docker image inspect "${FULL_IMAGE}:${SHA_SHORT}" >/dev/null
echo "=== Docker Auth Check ==="
docker info
echo "=== Push SHA tag ==="
docker push "${FULL_IMAGE}:${SHA_SHORT}"
echo "=== Push floating tag (${{ inputs.floating_tag }}) ==="
docker push "${FULL_IMAGE}:${{ inputs.floating_tag }}"
if echo "${{ gitea.ref }}" | grep -q '^refs/tags/v'; then
echo "=== Version tag detected ==="
VERSION="${{ gitea.ref_name }}"
VERSION="${VERSION#v}"
MAJOR="$(echo "$VERSION" | cut -d. -f1)"
MINOR="$(echo "$VERSION" | cut -d. -f1,2)"
echo "VERSION=${VERSION}"
echo "MINOR=${MINOR}"
echo "MAJOR=${MAJOR}"
echo "=== Push latest ==="
docker push "${FULL_IMAGE}:latest"
echo "=== Push version ==="
docker push "${FULL_IMAGE}:${VERSION}"
echo "=== Push minor ==="
docker push "${FULL_IMAGE}:${MINOR}"
echo "=== Push major ==="
docker push "${FULL_IMAGE}:${MAJOR}"
else
echo "=== No version tag detected, only SHA tag pushed ==="
fi