name: Attestation Health Check
on:
schedule:
- cron: '23 3 * * 1' workflow_dispatch:
jobs:
verify:
name: Verify Latest Release Attestations
runs-on: cachekit
permissions:
contents: read
issues: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- name: Get latest release tag
id: release
run: |
TAG=$(gh release list --repo ${{ github.repository }} --limit 1 --json tagName --jq '.[0].tagName' 2>/dev/null || echo "")
if [ -z "$TAG" ]; then
echo "No releases found, skipping"
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Download release asset
if: steps.release.outputs.skip != 'true'
id: asset
run: |
TAG="${{ steps.release.outputs.tag }}"
mkdir -p /tmp/release-assets
gh release download "$TAG" --repo ${{ github.repository }} \
--pattern "*.crate" --dir /tmp/release-assets 2>/dev/null || true
CRATE=$(find /tmp/release-assets -name '*.crate' -print -quit)
if [ -z "$CRATE" ]; then
echo "::warning::No .crate asset found for $TAG, checking repo-level attestations"
echo "has_asset=false" >> "$GITHUB_OUTPUT"
else
echo "asset=$CRATE" >> "$GITHUB_OUTPUT"
echo "has_asset=true" >> "$GITHUB_OUTPUT"
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Verify provenance attestation
if: steps.release.outputs.skip != 'true'
run: |
TAG="${{ steps.release.outputs.tag }}"
echo "Verifying provenance attestation for $TAG"
if [ "${{ steps.asset.outputs.has_asset }}" = "true" ]; then
gh attestation verify "${{ steps.asset.outputs.asset }}" \
--repo ${{ github.repository }} \
--predicate-type https://slsa.dev/provenance/v1
else
# No downloadable .crate asset — verify attestations exist for the repo
PROVENANCE=$(gh attestation list --repo ${{ github.repository }} \
--predicate-type https://slsa.dev/provenance/v1 --limit 1 --jq 'length')
if [ "$PROVENANCE" = "0" ] || [ -z "$PROVENANCE" ]; then
echo "::error::No provenance attestation found"
exit 1
fi
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Verify SBOM attestation
if: steps.release.outputs.skip != 'true'
run: |
TAG="${{ steps.release.outputs.tag }}"
echo "Verifying SBOM attestation for $TAG"
if [ "${{ steps.asset.outputs.has_asset }}" = "true" ]; then
gh attestation verify "${{ steps.asset.outputs.asset }}" \
--repo ${{ github.repository }} \
--predicate-type https://spdx.dev/Document/v2.3 || \
gh attestation verify "${{ steps.asset.outputs.asset }}" \
--repo ${{ github.repository }} \
--predicate-type https://cyclonedx.org/bom/v1.6
else
SBOM=$(gh attestation list --repo ${{ github.repository }} \
--predicate-type https://cyclonedx.org/bom/v1.6 --limit 1 --jq 'length' 2>/dev/null || echo "0")
SPDX=$(gh attestation list --repo ${{ github.repository }} \
--predicate-type https://spdx.dev/Document/v2.3 --limit 1 --jq 'length' 2>/dev/null || echo "0")
if [ "$SBOM" = "0" ] && [ "$SPDX" = "0" ]; then
echo "::error::No SBOM attestation found (checked CycloneDX and SPDX)"
exit 1
fi
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Open issue on failure
if: failure()
run: |
gh issue create \
--repo ${{ github.repository }} \
--title "Attestation verification failed for ${{ steps.release.outputs.tag }}" \
--body "Weekly attestation health check failed. Verify that the release workflow produced valid provenance and SBOM attestations." \
--label "bug"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}