531 lines
23 KiB
YAML
531 lines
23 KiB
YAML
name: Pub Docker Img
|
|
|
|
on:
|
|
push:
|
|
tags: ["v*"]
|
|
pull_request:
|
|
branches: [dev, main]
|
|
paths:
|
|
- "Dockerfile"
|
|
- ".dockerignore"
|
|
- "docker-compose.yml"
|
|
- "rust-toolchain.toml"
|
|
- "dev/config.template.toml"
|
|
- ".github/workflows/pub-docker-img.yml"
|
|
- ".github/release/ghcr-tag-policy.json"
|
|
- ".github/release/ghcr-vulnerability-policy.json"
|
|
- "scripts/ci/ghcr_publish_contract_guard.py"
|
|
- "scripts/ci/ghcr_vulnerability_gate.py"
|
|
workflow_dispatch:
|
|
inputs:
|
|
release_tag:
|
|
description: "Existing release tag to publish (e.g. v0.2.0). Leave empty for smoke-only run."
|
|
required: false
|
|
type: string
|
|
|
|
concurrency:
|
|
group: docker-${{ github.event.pull_request.number || github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
GIT_CONFIG_COUNT: "1"
|
|
GIT_CONFIG_KEY_0: core.hooksPath
|
|
GIT_CONFIG_VALUE_0: /dev/null
|
|
REGISTRY: ghcr.io
|
|
IMAGE_NAME: ${{ github.repository }}
|
|
TRIVY_IMAGE: aquasec/trivy:0.58.2
|
|
|
|
jobs:
|
|
pr-smoke:
|
|
name: PR Docker Smoke
|
|
if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || (github.event_name == 'workflow_dispatch' && inputs.release_tag == '')
|
|
runs-on: [self-hosted, Linux, X64, blacksmith-2vcpu-ubuntu-2404]
|
|
timeout-minutes: 25
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
|
|
- name: Resolve Docker API version
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
server_api="$(docker version --format '{{.Server.APIVersion}}')"
|
|
min_api="$(docker version --format '{{.Server.MinAPIVersion}}' 2>/dev/null || true)"
|
|
if [[ -z "${server_api}" || "${server_api}" == "<no value>" ]]; then
|
|
echo "::error::Unable to detect Docker server API version."
|
|
docker version || true
|
|
exit 1
|
|
fi
|
|
echo "DOCKER_API_VERSION=${server_api}" >> "$GITHUB_ENV"
|
|
echo "Using Docker API version ${server_api} (server min: ${min_api:-unknown})"
|
|
|
|
- name: Setup Buildx
|
|
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
|
|
|
- name: Extract metadata (tags, labels)
|
|
if: github.event_name == 'pull_request'
|
|
id: meta
|
|
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
|
|
with:
|
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
tags: |
|
|
type=ref,event=pr
|
|
|
|
- name: Build smoke image
|
|
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
|
|
with:
|
|
context: .
|
|
push: false
|
|
load: true
|
|
provenance: false
|
|
sbom: false
|
|
tags: zeroclaw-pr-smoke:latest
|
|
labels: ${{ steps.meta.outputs.labels || '' }}
|
|
platforms: linux/amd64
|
|
cache-from: type=gha,scope=pub-docker-pr-${{ github.event.pull_request.number || 'dispatch' }}
|
|
cache-to: type=gha,scope=pub-docker-pr-${{ github.event.pull_request.number || 'dispatch' }},mode=max
|
|
|
|
- name: Verify image
|
|
run: docker run --rm zeroclaw-pr-smoke:latest --version
|
|
|
|
publish:
|
|
name: Build and Push Docker Image
|
|
if: github.repository == 'zeroclaw-labs/zeroclaw' && ((github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) || (github.event_name == 'workflow_dispatch' && inputs.release_tag != ''))
|
|
runs-on: [self-hosted, Linux, X64, blacksmith-2vcpu-ubuntu-2404]
|
|
timeout-minutes: 90
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
security-events: write
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
with:
|
|
ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.release_tag) || github.ref }}
|
|
|
|
- name: Resolve Docker API version
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
server_api="$(docker version --format '{{.Server.APIVersion}}')"
|
|
min_api="$(docker version --format '{{.Server.MinAPIVersion}}' 2>/dev/null || true)"
|
|
if [[ -z "${server_api}" || "${server_api}" == "<no value>" ]]; then
|
|
echo "::error::Unable to detect Docker server API version."
|
|
docker version || true
|
|
exit 1
|
|
fi
|
|
echo "DOCKER_API_VERSION=${server_api}" >> "$GITHUB_ENV"
|
|
echo "Using Docker API version ${server_api} (server min: ${min_api:-unknown})"
|
|
|
|
- name: Setup Buildx
|
|
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
|
|
|
- name: Log in to Container Registry
|
|
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Compute tags
|
|
id: meta
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
|
|
if [[ "${GITHUB_EVENT_NAME}" == "push" ]]; then
|
|
if [[ "${GITHUB_REF}" != refs/tags/v* ]]; then
|
|
echo "::error::Docker publish is restricted to v* tag pushes."
|
|
exit 1
|
|
fi
|
|
RELEASE_TAG="${GITHUB_REF#refs/tags/}"
|
|
elif [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
|
|
RELEASE_TAG="${{ inputs.release_tag }}"
|
|
if [[ -z "${RELEASE_TAG}" ]]; then
|
|
echo "::error::workflow_dispatch publish requires inputs.release_tag"
|
|
exit 1
|
|
fi
|
|
if [[ ! "${RELEASE_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?$ ]]; then
|
|
echo "::error::release_tag must be vX.Y.Z or vX.Y.Z-suffix (received: ${RELEASE_TAG})"
|
|
exit 1
|
|
fi
|
|
if ! git rev-parse --verify "refs/tags/${RELEASE_TAG}" >/dev/null 2>&1; then
|
|
echo "::error::release tag not found in checkout: ${RELEASE_TAG}"
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "::error::Unsupported event for publish: ${GITHUB_EVENT_NAME}"
|
|
exit 1
|
|
fi
|
|
RELEASE_SHA="$(git rev-parse HEAD)"
|
|
SHA_SUFFIX="sha-${RELEASE_SHA::12}"
|
|
SHA_TAG="${IMAGE}:${SHA_SUFFIX}"
|
|
LATEST_SUFFIX="latest"
|
|
LATEST_TAG="${IMAGE}:${LATEST_SUFFIX}"
|
|
VERSION_TAG="${IMAGE}:${RELEASE_TAG}"
|
|
TAGS="${VERSION_TAG},${SHA_TAG},${LATEST_TAG}"
|
|
|
|
{
|
|
echo "tags=${TAGS}"
|
|
echo "release_tag=${RELEASE_TAG}"
|
|
echo "release_sha=${RELEASE_SHA}"
|
|
echo "sha_tag=${SHA_SUFFIX}"
|
|
echo "latest_tag=${LATEST_SUFFIX}"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Build release candidate image (pre-push scan)
|
|
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
|
|
with:
|
|
context: .
|
|
push: false
|
|
load: true
|
|
build-args: |
|
|
ZEROCLAW_CARGO_FEATURES=channel-matrix
|
|
tags: zeroclaw-release-candidate:${{ steps.meta.outputs.release_tag }}
|
|
platforms: linux/amd64
|
|
cache-from: type=gha,scope=pub-docker-release-${{ steps.meta.outputs.release_tag }}
|
|
cache-to: type=gha,scope=pub-docker-release-${{ steps.meta.outputs.release_tag }},mode=max
|
|
|
|
- name: Pre-push Trivy gate (CRITICAL blocks, HIGH warns)
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
mkdir -p artifacts
|
|
|
|
LOCAL_SCAN_IMAGE="zeroclaw-release-candidate:${{ steps.meta.outputs.release_tag }}"
|
|
|
|
docker run --rm \
|
|
-v "$PWD/artifacts:/work" \
|
|
"${TRIVY_IMAGE}" image \
|
|
--quiet \
|
|
--ignore-unfixed \
|
|
--severity CRITICAL \
|
|
--format json \
|
|
--output /work/trivy-prepush-critical.json \
|
|
"${LOCAL_SCAN_IMAGE}"
|
|
|
|
critical_count="$(python3 - <<'PY'
|
|
import json
|
|
from pathlib import Path
|
|
|
|
report = Path("artifacts/trivy-prepush-critical.json")
|
|
if not report.exists():
|
|
print(0)
|
|
raise SystemExit(0)
|
|
|
|
data = json.loads(report.read_text(encoding="utf-8"))
|
|
count = 0
|
|
for result in data.get("Results", []):
|
|
vulns = result.get("Vulnerabilities") or []
|
|
count += len(vulns)
|
|
print(count)
|
|
PY
|
|
)"
|
|
|
|
docker run --rm \
|
|
-v "$PWD/artifacts:/work" \
|
|
"${TRIVY_IMAGE}" image \
|
|
--quiet \
|
|
--ignore-unfixed \
|
|
--severity HIGH \
|
|
--format json \
|
|
--output /work/trivy-prepush-high.json \
|
|
"${LOCAL_SCAN_IMAGE}"
|
|
|
|
docker run --rm \
|
|
-v "$PWD/artifacts:/work" \
|
|
"${TRIVY_IMAGE}" image \
|
|
--quiet \
|
|
--ignore-unfixed \
|
|
--severity HIGH \
|
|
--format table \
|
|
--output /work/trivy-prepush-high.txt \
|
|
"${LOCAL_SCAN_IMAGE}"
|
|
|
|
high_count="$(python3 - <<'PY'
|
|
import json
|
|
from pathlib import Path
|
|
|
|
report = Path("artifacts/trivy-prepush-high.json")
|
|
if not report.exists():
|
|
print(0)
|
|
raise SystemExit(0)
|
|
|
|
data = json.loads(report.read_text(encoding="utf-8"))
|
|
count = 0
|
|
for result in data.get("Results", []):
|
|
vulns = result.get("Vulnerabilities") or []
|
|
count += len(vulns)
|
|
print(count)
|
|
PY
|
|
)"
|
|
|
|
{
|
|
echo "### Pre-push Trivy Gate"
|
|
echo "- Candidate image: \`${LOCAL_SCAN_IMAGE}\`"
|
|
echo "- CRITICAL findings: \`${critical_count}\` (blocking)"
|
|
echo "- HIGH findings: \`${high_count}\` (advisory)"
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
if [ "${high_count}" -gt 0 ]; then
|
|
echo "::warning::Pre-push Trivy found ${high_count} HIGH vulnerabilities (advisory only)."
|
|
fi
|
|
|
|
if [ "${critical_count}" -gt 0 ]; then
|
|
echo "::error::Pre-push Trivy found ${critical_count} CRITICAL vulnerabilities."
|
|
exit 1
|
|
fi
|
|
|
|
- name: Build and push Docker image
|
|
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
|
|
with:
|
|
context: .
|
|
push: true
|
|
build-args: |
|
|
ZEROCLAW_CARGO_FEATURES=channel-matrix
|
|
tags: ${{ steps.meta.outputs.tags }}
|
|
platforms: linux/amd64,linux/arm64
|
|
cache-from: type=gha,scope=pub-docker-release-${{ steps.meta.outputs.release_tag }}
|
|
cache-to: type=gha,scope=pub-docker-release-${{ steps.meta.outputs.release_tag }},mode=max
|
|
|
|
- name: Set GHCR package visibility to public
|
|
shell: bash
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
set -euo pipefail
|
|
owner="${GITHUB_REPOSITORY_OWNER,,}"
|
|
repo="${GITHUB_REPOSITORY#*/}"
|
|
|
|
# Package path can vary depending on repository/package linkage.
|
|
candidates=(
|
|
"$repo"
|
|
"${owner}%2F${repo}"
|
|
)
|
|
|
|
for scope in orgs users; do
|
|
for pkg in "${candidates[@]}"; do
|
|
code="$(curl -sS -o /tmp/ghcr-visibility.json -w "%{http_code}" \
|
|
-X PATCH \
|
|
-H "Authorization: Bearer ${GH_TOKEN}" \
|
|
-H "Accept: application/vnd.github+json" \
|
|
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
"https://api.github.com/${scope}/${owner}/packages/container/${pkg}/visibility" \
|
|
-d '{"visibility":"public"}' || true)"
|
|
|
|
if [ "$code" = "200" ] || [ "$code" = "204" ]; then
|
|
echo "GHCR package visibility is public (${scope}/${owner}/${pkg})."
|
|
exit 0
|
|
fi
|
|
|
|
echo "Visibility attempt ${scope}/${owner}/${pkg} returned HTTP ${code}."
|
|
done
|
|
done
|
|
|
|
echo "::warning::Unable to update GHCR visibility via API in this run; proceeding to GHCR publish contract verification."
|
|
|
|
- name: Validate GHCR publish contract
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
mkdir -p artifacts
|
|
python3 scripts/ci/ghcr_publish_contract_guard.py \
|
|
--repository "${GITHUB_REPOSITORY,,}" \
|
|
--release-tag "${{ steps.meta.outputs.release_tag }}" \
|
|
--sha "${{ steps.meta.outputs.release_sha }}" \
|
|
--policy-file .github/release/ghcr-tag-policy.json \
|
|
--output-json artifacts/ghcr-publish-contract.json \
|
|
--output-md artifacts/ghcr-publish-contract.md \
|
|
--fail-on-violation
|
|
|
|
- name: Emit GHCR publish contract audit event
|
|
if: always()
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
if [ -f artifacts/ghcr-publish-contract.json ]; then
|
|
python3 scripts/ci/emit_audit_event.py \
|
|
--event-type ghcr_publish_contract \
|
|
--input-json artifacts/ghcr-publish-contract.json \
|
|
--output-json artifacts/audit-event-ghcr-publish-contract.json \
|
|
--artifact-name ghcr-publish-contract \
|
|
--retention-days 21
|
|
fi
|
|
|
|
- name: Publish GHCR contract summary
|
|
if: always()
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
if [ -f artifacts/ghcr-publish-contract.md ]; then
|
|
cat artifacts/ghcr-publish-contract.md >> "$GITHUB_STEP_SUMMARY"
|
|
fi
|
|
|
|
- name: Upload GHCR publish contract artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ghcr-publish-contract
|
|
path: |
|
|
artifacts/ghcr-publish-contract.json
|
|
artifacts/ghcr-publish-contract.md
|
|
artifacts/audit-event-ghcr-publish-contract.json
|
|
if-no-files-found: ignore
|
|
retention-days: 21
|
|
|
|
- name: Scan published image for policy evidence (Trivy)
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
mkdir -p artifacts
|
|
|
|
TAG_NAME="${{ steps.meta.outputs.release_tag }}"
|
|
SHA_TAG="${{ steps.meta.outputs.sha_tag }}"
|
|
LATEST_TAG="${{ steps.meta.outputs.latest_tag }}"
|
|
IMAGE_BASE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
|
|
VERSION_REF="${IMAGE_BASE}:${TAG_NAME}"
|
|
SHA_REF="${IMAGE_BASE}:${SHA_TAG}"
|
|
LATEST_REF="${IMAGE_BASE}:${LATEST_TAG}"
|
|
SARIF_OUT="artifacts/trivy-${TAG_NAME}.sarif"
|
|
TABLE_OUT="artifacts/trivy-${TAG_NAME}.txt"
|
|
JSON_OUT="artifacts/trivy-${TAG_NAME}.json"
|
|
SHA_TABLE_OUT="artifacts/trivy-${SHA_TAG}.txt"
|
|
SHA_JSON_OUT="artifacts/trivy-${SHA_TAG}.json"
|
|
LATEST_TABLE_OUT="artifacts/trivy-${LATEST_TAG}.txt"
|
|
LATEST_JSON_OUT="artifacts/trivy-${LATEST_TAG}.json"
|
|
|
|
scan_trivy() {
|
|
local image_ref="$1"
|
|
local output_prefix="$2"
|
|
|
|
docker run --rm \
|
|
-v "$PWD/artifacts:/work" \
|
|
"${TRIVY_IMAGE}" image \
|
|
--quiet \
|
|
--ignore-unfixed \
|
|
--severity HIGH,CRITICAL \
|
|
--format json \
|
|
--output "/work/${output_prefix}.json" \
|
|
"${image_ref}"
|
|
|
|
docker run --rm \
|
|
-v "$PWD/artifacts:/work" \
|
|
"${TRIVY_IMAGE}" image \
|
|
--quiet \
|
|
--ignore-unfixed \
|
|
--severity HIGH,CRITICAL \
|
|
--format table \
|
|
--output "/work/${output_prefix}.txt" \
|
|
"${image_ref}"
|
|
}
|
|
|
|
docker run --rm \
|
|
-v "$PWD/artifacts:/work" \
|
|
"${TRIVY_IMAGE}" image \
|
|
--quiet \
|
|
--ignore-unfixed \
|
|
--severity HIGH,CRITICAL \
|
|
--format sarif \
|
|
--output "/work/trivy-${TAG_NAME}.sarif" \
|
|
"${VERSION_REF}"
|
|
|
|
scan_trivy "${VERSION_REF}" "trivy-${TAG_NAME}"
|
|
scan_trivy "${SHA_REF}" "trivy-${SHA_TAG}"
|
|
scan_trivy "${LATEST_REF}" "trivy-${LATEST_TAG}"
|
|
|
|
echo "Generated Trivy reports:"
|
|
ls -1 "$SARIF_OUT" "$TABLE_OUT" "$JSON_OUT" "$SHA_TABLE_OUT" "$SHA_JSON_OUT" "$LATEST_TABLE_OUT" "$LATEST_JSON_OUT"
|
|
|
|
- name: Validate GHCR vulnerability gate
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
python3 scripts/ci/ghcr_vulnerability_gate.py \
|
|
--release-tag "${{ steps.meta.outputs.release_tag }}" \
|
|
--sha-tag "${{ steps.meta.outputs.sha_tag }}" \
|
|
--latest-tag "${{ steps.meta.outputs.latest_tag }}" \
|
|
--release-report-json "artifacts/trivy-${{ steps.meta.outputs.release_tag }}.json" \
|
|
--sha-report-json "artifacts/trivy-${{ steps.meta.outputs.sha_tag }}.json" \
|
|
--latest-report-json "artifacts/trivy-${{ steps.meta.outputs.latest_tag }}.json" \
|
|
--policy-file .github/release/ghcr-vulnerability-policy.json \
|
|
--output-json artifacts/ghcr-vulnerability-gate.json \
|
|
--output-md artifacts/ghcr-vulnerability-gate.md \
|
|
--fail-on-violation
|
|
|
|
- name: Emit GHCR vulnerability gate audit event
|
|
if: always()
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
if [ -f artifacts/ghcr-vulnerability-gate.json ]; then
|
|
python3 scripts/ci/emit_audit_event.py \
|
|
--event-type ghcr_vulnerability_gate \
|
|
--input-json artifacts/ghcr-vulnerability-gate.json \
|
|
--output-json artifacts/audit-event-ghcr-vulnerability-gate.json \
|
|
--artifact-name ghcr-vulnerability-gate \
|
|
--retention-days 21
|
|
fi
|
|
|
|
- name: Publish GHCR vulnerability summary
|
|
if: always()
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
if [ -f artifacts/ghcr-vulnerability-gate.md ]; then
|
|
cat artifacts/ghcr-vulnerability-gate.md >> "$GITHUB_STEP_SUMMARY"
|
|
fi
|
|
|
|
- name: Upload GHCR vulnerability gate artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ghcr-vulnerability-gate
|
|
path: |
|
|
artifacts/ghcr-vulnerability-gate.json
|
|
artifacts/ghcr-vulnerability-gate.md
|
|
artifacts/audit-event-ghcr-vulnerability-gate.json
|
|
if-no-files-found: ignore
|
|
retention-days: 21
|
|
|
|
- name: Detect Trivy SARIF report
|
|
id: trivy-sarif
|
|
if: always()
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
sarif_path="artifacts/trivy-${{ steps.meta.outputs.release_tag }}.sarif"
|
|
if [ -f "${sarif_path}" ]; then
|
|
echo "exists=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "exists=false" >> "$GITHUB_OUTPUT"
|
|
echo "::notice::Trivy SARIF report not found at ${sarif_path}; skipping SARIF upload."
|
|
fi
|
|
|
|
- name: Upload Trivy SARIF
|
|
if: always() && steps.trivy-sarif.outputs.exists == 'true'
|
|
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4
|
|
with:
|
|
sarif_file: artifacts/trivy-${{ steps.meta.outputs.release_tag }}.sarif
|
|
category: ghcr-trivy
|
|
|
|
- name: Upload Trivy report artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: ghcr-trivy-report
|
|
path: |
|
|
artifacts/trivy-${{ steps.meta.outputs.release_tag }}.sarif
|
|
artifacts/trivy-${{ steps.meta.outputs.release_tag }}.txt
|
|
artifacts/trivy-${{ steps.meta.outputs.release_tag }}.json
|
|
artifacts/trivy-sha-*.txt
|
|
artifacts/trivy-sha-*.json
|
|
artifacts/trivy-latest.txt
|
|
artifacts/trivy-latest.json
|
|
artifacts/trivy-prepush-critical.json
|
|
artifacts/trivy-prepush-high.json
|
|
artifacts/trivy-prepush-high.txt
|
|
if-no-files-found: ignore
|
|
retention-days: 14
|