Files
zot/.github/workflows/publish.yaml
Benoit Tigeot d97953f101 Pin actions and tighten workflow permissions (#3954)
* ci: Reduce chance of installing corrupt packages

See: https://dev.to/hsbt/should-rubygemsbundler-have-a-cooldown-feature-40cp
Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>

* ci: prevent credential leakage from checkout steps

Add `persist-credentials: false` to all `actions/checkout` calls across
22 workflow files. Without this, the GitHub token used for checkout is
written into `.git/config` and remains accessible to all subsequent steps
and any uploaded artifacts (artipacked finding).

Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>

* ci: prevent template injection from github context in run steps

`${{ github.* }}` expressions used directly inside `run:` blocks are
expanded before the shell sees them. A crafted value (e.g. a tag name
containing shell metacharacters) would execute arbitrary code.

Move the values into `env:` variables (e.g. GITHUB_EVENT_RELEASE_TAG_NAME,
GITHUB_ACTOR) and reference them as `${VAR}` in the shell, so the runtime
never interprets them as code (template-injection finding).

Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>

* ci: prevent injection in yq commands via release tag name

`${{ github.event.release.tag_name }}` was interpolated directly into
yq `cmd:` inputs. A crafted tag name could inject shell commands since
the expression is expanded before the action runs. Use yq's `strenv()`
with an `env:` variable instead so the value is always treated as data.

Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>

* ci: pin all GitHub Actions to full commit SHAs

Actions pinned to mutable tags (e.g. @v6, @main) can change under us if
the upstream repo is compromised or tags are moved, enabling supply-chain
attacks. Pinning to the full 40-char commit SHA locks the exact code that
runs. Version tags are preserved as inline comments (e.g. # v6.0.2) for
readability and Dependabot compatibility.

Used `pinact` for standard tagged versions; remaining branch-based
references (mikefarah/yq, jlumbroso/free-disk-space,
project-stacker/stacker-build-push-action, aquasecurity/trivy-action)
resolved manually via the GitHub API.

Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>

* ci: slow down GitHub Actions dependency updates to biweekly

Dependabot has no native biweekly interval. Combining weekly checks with
a 14-day cooldown achieves the same effect: Dependabot scans every Monday
but won't open a PR for a new action version until 14 days after release,
giving the ecosystem time to stabilize before we adopt it.

Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>

* ci: group all Dependabot updates into single PRs per ecosystem

Without groups, Dependabot opens one PR per dependency. With `patterns: "*"`,
all Go module bumps land in one PR and all GitHub Actions pin updates in
another, reducing review noise.

Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>

* ci: restore credential persistence for helm-charts push

`persist-credentials: false` was too broad — the helm-charts checkout
uses HELM_PUSH_TOKEN specifically so the subsequent `git push` can
authenticate. Only the main repo checkout should have credentials disabled.

Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>

* ci: use --password-stdin for oras login

Passing the token via `-p` exposes it in process listings and debug
logs. Piping via stdin is the standard secure pattern for CLI auth.

Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>

* ci: pin actions to versioned release SHAs

jmgilman/actions-generate-checksum: v1 branch HEAD -> v1.0.1 release
mikefarah/yq: arbitrary master HEAD -> v4.52.5 release

Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>

---------

Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>
2026-04-10 15:35:22 -07:00

376 lines
15 KiB
YAML

on:
release:
types:
- published
name: Publish OCI images
permissions: read-all
jobs:
push-singlearch-image:
name: Push single arch OCI images to GitHub Packages
runs-on: ubuntu-22.04
permissions:
contents: read
packages: write
strategy:
matrix:
os: [linux, freebsd]
arch: [amd64, arm64]
steps:
- name: Setup base image
run: |
if [ ${{ matrix.os }} = 'freebsd' ]; then
echo "BASE_IMAGE=freebsd/freebsd-static:14.3" >> "$GITHUB_ENV"
else
ARCH=${{ matrix.arch }}
echo "BASE_IMAGE=gcr.io/distroless/base-nossl-debian13:latest-${ARCH}" >> "$GITHUB_ENV"
fi
- name: Check out the repo
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Log in to GitHub Docker Registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push zot container image
uses: project-stacker/stacker-build-push-action@093acb5ad50bed0012616f46fdba73a8a7169db7 # main
with:
version: v1.1.0-rc3
file: 'build/stacker.yaml'
build-args: |
RELEASE_TAG=${{ github.event.release.tag_name }}
COMMIT=${{ github.event.release.tag_name }}-${{ github.sha }}
OS=${{ matrix.os }}
ARCH=${{ matrix.arch }}
REPO_NAME=zot-${{ matrix.os }}-${{ matrix.arch }}
BASE_IMAGE=${{ env.BASE_IMAGE }}
url: docker://ghcr.io/${{ github.repository_owner }}
tags: ${{ github.event.release.tag_name }} latest
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push zot-minimal container image
uses: project-stacker/stacker-build-push-action@093acb5ad50bed0012616f46fdba73a8a7169db7 # main
with:
version: v1.1.0-rc3
file: 'build/stacker-minimal.yaml'
build-args: |
RELEASE_TAG=${{ github.event.release.tag_name }}
COMMIT=${{ github.event.release.tag_name }}-${{ github.sha }}
OS=${{ matrix.os }}
ARCH=${{ matrix.arch }}
EXT=-minimal
REPO_NAME=zot-minimal-${{ matrix.os }}-${{ matrix.arch }}
BASE_IMAGE=${{ env.BASE_IMAGE }}
url: docker://ghcr.io/${{ github.repository_owner }}
tags: ${{ github.event.release.tag_name }} latest
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push zot-exporter container image
uses: project-stacker/stacker-build-push-action@093acb5ad50bed0012616f46fdba73a8a7169db7 # main
with:
version: v1.1.0-rc3
file: 'build/stacker-zxp.yaml'
build-args: |
RELEASE_TAG=${{ github.event.release.tag_name }}
COMMIT=${{ github.event.release.tag_name }}-${{ github.sha }}
OS=${{ matrix.os }}
ARCH=${{ matrix.arch }}
REPO_NAME=zxp-${{ matrix.os }}-${{ matrix.arch }}
BASE_IMAGE=${{ env.BASE_IMAGE }}
url: docker://ghcr.io/${{ github.repository_owner }}
tags: ${{ github.event.release.tag_name }} latest
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push zb container image
uses: project-stacker/stacker-build-push-action@093acb5ad50bed0012616f46fdba73a8a7169db7 # main
with:
version: v1.1.0-rc3
file: 'build/stacker-zb.yaml'
build-args: |
RELEASE_TAG=${{ github.event.release.tag_name }}
COMMIT=${{ github.event.release.tag_name }}-${{ github.sha }}
OS=${{ matrix.os }}
ARCH=${{ matrix.arch }}
REPO_NAME=zb-${{ matrix.os }}-${{ matrix.arch }}
BASE_IMAGE=${{ env.BASE_IMAGE }}
url: docker://ghcr.io/${{ github.repository_owner }}
tags: ${{ github.event.release.tag_name }} latest
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
push-multiarch-image:
name: Push multiarch OCI images to GitHub Packages
needs: push-singlearch-image
runs-on: ubuntu-22.04
permissions:
contents: read
packages: write
strategy:
matrix:
image: [zot, zot-minimal, zxp, zb]
steps:
- name: Check out the repo
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Log in to GitHub Docker Registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Run build
run: |
echo "Building multiarch image for ${{ matrix.image }}"
cd $GITHUB_WORKSPACE
make check-blackbox-prerequisites
export PATH=${PATH}:${GITHUB_WORKSPACE}/hack/tools/bin
./scripts/build_multiarch_image.sh --registry ghcr.io/${GITHUB_REPOSITORY_OWNER} \
--source-tag ${GITHUB_EVENT_RELEASE_TAG_NAME} \
--destination-tags "${GITHUB_EVENT_RELEASE_TAG_NAME} latest" \
--file build/multiarch-${{ matrix.image }}.json
env:
GITHUB_EVENT_RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
test-image:
name: Test OCI images published to GitHub Packages
needs: push-multiarch-image
runs-on: ubuntu-22.04
permissions:
packages: read
steps:
- name: Log in to GitHub Docker Registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Run zot container image with docker
run: |
docker run -d -p 5000:5000 ghcr.io/${GITHUB_REPOSITORY_OWNER}/zot:${GITHUB_EVENT_RELEASE_TAG_NAME}
sleep 2
curl --connect-timeout 5 \
--max-time 10 \
--retry 12 \
--retry-max-time 360 \
--retry-connrefused \
'http://localhost:5000/v2/'
docker kill $(docker ps -q)
env:
GITHUB_EVENT_RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
- name: Run zot container image with podman
run: |
podman run -d -p 5000:5000 ghcr.io/${GITHUB_REPOSITORY_OWNER}/zot:${GITHUB_EVENT_RELEASE_TAG_NAME}
sleep 2
curl --connect-timeout 5 \
--max-time 10 \
--retry 12 \
--retry-max-time 360 \
--retry-connrefused \
'http://localhost:5000/v2/'
podman kill --all
env:
GITHUB_EVENT_RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
- name: Run zot-minimal container image with docker
run: |
docker run -d -p 5000:5000 ghcr.io/${GITHUB_REPOSITORY_OWNER}/zot-minimal:${GITHUB_EVENT_RELEASE_TAG_NAME}
sleep 2
curl --connect-timeout 5 \
--max-time 10 \
--retry 12 \
--retry-max-time 360 \
--retry-connrefused \
'http://localhost:5000/v2/'
docker kill $(docker ps -q)
env:
GITHUB_EVENT_RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
- name: Run zot-minimal container image with podman
run: |
podman run -d -p 5000:5000 ghcr.io/${GITHUB_REPOSITORY_OWNER}/zot-minimal:${GITHUB_EVENT_RELEASE_TAG_NAME}
sleep 2
curl --connect-timeout 5 \
--max-time 10 \
--retry 12 \
--retry-max-time 360 \
--retry-connrefused \
'http://localhost:5000/v2/'
podman kill --all
env:
GITHUB_EVENT_RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
- name: Run zot-exporter container image with docker
run: |
docker run -d -p 5001:5001 ghcr.io/${GITHUB_REPOSITORY_OWNER}/zxp:${GITHUB_EVENT_RELEASE_TAG_NAME}
sleep 2
curl --connect-timeout 5 \
--max-time 10 \
--retry 12 \
--retry-max-time 360 \
--retry-connrefused \
'http://localhost:5001/metrics'
docker kill $(docker ps -q)
env:
GITHUB_EVENT_RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
- name: Run zot-exporter container image with podman
run: |
podman run -d -p 5001:5001 ghcr.io/${GITHUB_REPOSITORY_OWNER}/zxp:${GITHUB_EVENT_RELEASE_TAG_NAME}
sleep 2
curl --connect-timeout 5 \
--max-time 10 \
--retry 12 \
--retry-max-time 360 \
--retry-connrefused \
'http://localhost:5001/metrics'
podman kill --all
env:
GITHUB_EVENT_RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
- name: Run zb container image with docker
run: |
docker run ghcr.io/${GITHUB_REPOSITORY_OWNER}/zb:${GITHUB_EVENT_RELEASE_TAG_NAME} --help
env:
GITHUB_EVENT_RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
- name: Run zb container image with podman
run: |
podman run ghcr.io/${GITHUB_REPOSITORY_OWNER}/zb:${GITHUB_EVENT_RELEASE_TAG_NAME} --help
env:
GITHUB_EVENT_RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
scan-image:
name: Run Trivy scan on OCI images published to GitHub Packages
needs: push-singlearch-image
runs-on: ubuntu-22.04
permissions:
security-events: write
packages: read
strategy:
matrix:
os: [linux, freebsd]
arch: [amd64, arm64]
steps:
- name: Log in to GitHub Docker Registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 57a97c7
with:
image-ref: 'ghcr.io/${{ github.repository_owner }}/zot-${{ matrix.os }}-${{ matrix.arch }}:${{ github.event.release.tag_name }}'
format: 'sarif'
output: 'trivy-results.sarif'
env:
TRIVY_USERNAME: ${{ github.actor }}
TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
- name: Run Trivy vulnerability scanner (minimal)
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 57a97c7
with:
image-ref: 'ghcr.io/${{ github.repository_owner }}/zot-minimal-${{ matrix.os }}-${{ matrix.arch }}:${{ github.event.release.tag_name }}'
format: 'sarif'
output: 'trivy-results.sarif'
env:
TRIVY_USERNAME: ${{ github.actor }}
TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
with:
sarif_file: 'trivy-results.sarif'
scan-multiarch-image:
name: Run Trivy scan on OCI multiarch images published to GitHub Packages
needs: push-multiarch-image
runs-on: ubuntu-22.04
permissions:
security-events: write
packages: read
steps:
- name: Log in to GitHub Docker Registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 57a97c7
with:
image-ref: 'ghcr.io/${{ github.repository_owner }}/zot:${{ github.event.release.tag_name }}'
format: 'sarif'
output: 'trivy-results.sarif'
env:
TRIVY_USERNAME: ${{ github.actor }}
TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
- name: Run Trivy vulnerability scanner (minimal)
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 57a97c7
with:
image-ref: 'ghcr.io/${{ github.repository_owner }}/zot-minimal:${{ github.event.release.tag_name }}'
format: 'sarif'
output: 'trivy-results.sarif'
env:
TRIVY_USERNAME: ${{ github.actor }}
TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
with:
sarif_file: 'trivy-results.sarif'
update-helm-chart:
if: ${{ github.event_name == 'release' && github.event.action == 'published' && !contains(github.event.release.tag_name, 'rc') }}
needs: push-multiarch-image
name: Update Helm Chart
permissions:
contents: write
packages: write
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: main
fetch-depth: '0'
persist-credentials: false
- name: Checkout project-zot/helm-charts
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: project-zot/helm-charts
ref: main
fetch-depth: '0'
token: ${{ secrets.HELM_PUSH_TOKEN }}
path: ./helm-charts
persist-credentials: true
- name: Configure Git
run: |
git config --global user.name 'github-actions'
git config --global user.email 'github-actions@users.noreply.github.com'
- name: Update appVersion
uses: mikefarah/yq@0f4fb8d35ec1a939d78dd6862f494d19ec589f19 # v4.52.5
with:
cmd: yq -i '.appVersion = strenv(RELEASE_TAG)' 'helm-charts/charts/zot/Chart.yaml'
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
- name: Update image tag
uses: mikefarah/yq@0f4fb8d35ec1a939d78dd6862f494d19ec589f19 # v4.52.5
with:
cmd: |
yq e '.image.tag = strenv(RELEASE_TAG)' 'helm-charts/charts/zot/values.yaml' > values-updated.yaml
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
- name: Patch values.yaml file
run: |
diff -b 'helm-charts/charts/zot/values.yaml' values-updated.yaml > values.diff || true
patch 'helm-charts/charts/zot/values.yaml' < values.diff
rm values-updated.yaml values.diff
- name: Update version
run: |
sudo apt-get install pip
pip install pybump
pybump bump --file helm-charts/charts/zot/Chart.yaml --level patch
- name: Push changes to project-zot/helm-charts
run: |
cd ./helm-charts
git commit -am "build: automated update of Helm Chart"
git push