name: Reusable Image Security Checks on: workflow_call: inputs: image_name: required: true type: string image_tag: type: string default: "latest" scan_severity: type: string default: "HIGH,CRITICAL" secrets: REGISTRY_USERNAME: { required: true } REGISTRY_PASSWORD: { required: true } DOCKER_REGISTRY: { required: true } jobs: scan: 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: Docker Login run: | echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login "${{ secrets.DOCKER_REGISTRY }}" -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin - name: Pull Image shell: bash run: | set -euo pipefail FULL_IMAGE="${{ secrets.DOCKER_REGISTRY }}/${{ inputs.image_name }}:${{ inputs.image_tag }}" echo "=== Pulling ${FULL_IMAGE} ===" docker pull "${FULL_IMAGE}" - name: Image Vulnerability 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 FULL_IMAGE="${{ secrets.DOCKER_REGISTRY }}/${{ inputs.image_name }}:${{ inputs.image_tag }}" echo "=== Scanning ${FULL_IMAGE} (fail on fixable ${{ inputs.scan_severity }}) ===" trivy image \ --exit-code 1 \ --severity "${{ inputs.scan_severity }}" \ --ignore-unfixed \ --scanners vuln,secret \ "${FULL_IMAGE}"