Skip to content

Mirror Trivy Databases #131

Mirror Trivy Databases

Mirror Trivy Databases #131

name: Mirror Trivy Databases
on:
schedule:
# Every 6 hours at :15 to avoid the top-of-hour GitHub scheduler congestion.
# Upstream Trivy databases refresh roughly every 6h, so this stays within
# one refresh window of upstream.
- cron: "15 */6 * * *"
workflow_dispatch:
inputs:
dry_run:
description: "Resolve digests but skip pushing"
required: false
type: boolean
default: false
permissions:
contents: read
packages: write
id-token: write
attestations: write
concurrency:
group: mirror-trivy-db
cancel-in-progress: true
jobs:
resolve:
name: Resolve mirror targets
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.matrix.outputs.matrix }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Install yq
run: |
sudo curl -fsSL -o /usr/local/bin/yq \
https://github.com/mikefarah/yq/releases/download/v4.45.1/yq_linux_amd64
sudo chmod +x /usr/local/bin/yq
- name: Build matrix from build.yaml
id: matrix
run: |
matrix="$(yq -o=json -I=0 '{"include": .mirrors}' build.yaml)"
echo "matrix=${matrix}" >> "$GITHUB_OUTPUT"
printf 'Resolved matrix: %s\n' "${matrix}"
mirror:
name: Mirror ${{ matrix.name }}
needs: resolve
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.resolve.outputs.matrix) }}
steps:
- name: Install oras
uses: oras-project/setup-oras@v2
- name: Install cosign
uses: sigstore/cosign-installer@v4.1.2
- name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to GHCR for ORAS
run: |
printf '%s' '${{ secrets.GITHUB_TOKEN }}' | oras login ghcr.io \
--username '${{ github.actor }}' \
--password-stdin
- name: Resolve upstream digest
id: upstream
run: |
src="${{ matrix.source }}:${{ matrix.tag }}"
digest="$(oras resolve "${src}")"
echo "src=${src}" >> "$GITHUB_OUTPUT"
echo "digest=${digest}" >> "$GITHUB_OUTPUT"
printf 'Upstream %s resolved to %s\n' "${src}" "${digest}"
- name: Copy artifact
id: copy
if: inputs.dry_run != true
run: |
oras copy \
"${{ steps.upstream.outputs.src }}" \
"${{ matrix.target }}:${{ matrix.tag }}"
mirrored="$(oras resolve "${{ matrix.target }}:${{ matrix.tag }}")"
if [ "${mirrored}" != "${{ steps.upstream.outputs.digest }}" ]; then
echo "::error::Mirror digest ${mirrored} != upstream ${{ steps.upstream.outputs.digest }}"
exit 1
fi
echo "digest=${mirrored}" >> "$GITHUB_OUTPUT"
- name: Sign mirrored artifact
if: steps.copy.outputs.digest != ''
env:
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
run: |
cosign sign --yes --key env://COSIGN_PRIVATE_KEY \
"${{ matrix.target }}@${{ steps.copy.outputs.digest }}"
- name: Attest mirrored artifact
if: steps.copy.outputs.digest != ''
uses: actions/attest@v4
with:
subject-name: ${{ matrix.target }}
subject-digest: ${{ steps.copy.outputs.digest }}
push-to-registry: true
- name: Job summary
if: always()
run: |
{
echo "### ${{ matrix.name }}"
echo ""
echo "- Source: \`${{ steps.upstream.outputs.src }}\`"
echo "- Target: \`${{ matrix.target }}:${{ matrix.tag }}\`"
echo "- Upstream: \`${{ steps.upstream.outputs.digest }}\`"
if [ "${{ inputs.dry_run }}" = "true" ]; then
echo "- Result: dry-run (no push)"
else
echo "- Mirror now: \`${{ steps.copy.outputs.digest }}\`"
echo "- Signed: yes (cosign)"
echo "- Attested: yes (actions/attest@v4)"
fi
} >> "$GITHUB_STEP_SUMMARY"