Skip to content

feat(crafting-schema): support schema v2 during attestation process (… #298

feat(crafting-schema): support schema v2 during attestation process (…

feat(crafting-schema): support schema v2 during attestation process (… #298

Workflow file for this run

name: Build, Package and Release
on:
push:
tags:
- "v*.*.*"
# https://github.com/ossf/scorecard/blob/7ed886f1bd917d19cb9d6ce6c10e80e81fa31c39/docs/checks.md#token-permissions
permissions:
contents: read
jobs:
test:
uses: chainloop-dev/chainloop/.github/workflows/test.yml@main
init_attestation:
runs-on: ubuntu-latest
permissions:
id-token: write # required for SLSA provenance - https://docs.chainloop.dev/guides/slsa/
needs: test
if: github.ref_type == 'tag' # Guard to make sure we are releasing once
outputs:
attestation_id: ${{ steps.init_attestation.outputs.attestation_id }}
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Install Chainloop
run: |
curl -sfL https://dl.chainloop.dev/cli/install.sh | bash -s
- name: Initialize Attestation
id: init_attestation
run: |
attestation_id=$(chainloop attestation init --workflow ${CHAINLOOP_WORKFLOW_NAME} --project ${CHAINLOOP_PROJECT_NAME} --release --remote-state -o json | jq -r .attestationID)
echo "attestation_id=$attestation_id" >> $GITHUB_OUTPUT
env:
CHAINLOOP_TOKEN: ${{ secrets.CHAINLOOP_TOKEN }}
CHAINLOOP_WORKFLOW_NAME: "release"
CHAINLOOP_PROJECT_NAME: "chainloop"
release:
name: Release CLI and control-plane/artifact-cas container images
needs: init_attestation
runs-on: ubuntu-latest
if: github.ref_type == 'tag' # Guard to make sure we are releasing once
permissions:
contents: write # required for goreleaser to upload the release assets
packages: write # to push container images
pull-requests: write
id-token: write # required for SLSA provenance
attestations: write # required for SLSA provenance
env:
CHAINLOOP_TOKEN: ${{ secrets.CHAINLOOP_TOKEN }}
ATTESTATION_ID: ${{ needs.init_attestation.outputs.attestation_id }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
outputs:
attestation_hash: ${{ steps.attest_goreleaser.outputs.attestation_hash }}
steps:
- name: Install Cosign
uses: sigstore/cosign-installer@ef6a6b364bbad08abd36a5f8af60b595d12702f8 # main
with:
cosign-release: "v2.2.3"
- name: Install Chainloop
run: |
curl -sfL https://dl.chainloop.dev/cli/install.sh | bash -s
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Docker login to Github Packages
uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2.2.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Go
uses: actions/setup-go@be3c94b385c4f180051c996d336f57a34c397495 # v3.6.1
with:
go-version: "1.25.0"
# install qemu binaries for multiarch builds (needed by goreleaser/buildx)
- name: Setup qemu
id: qemu
uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3.3.0
- name: Install Syft
run: |
# Install Syft
wget --no-verbose https://raw.githubusercontent.com/anchore/syft/c43f4fb416c34c1c4b3997373689d8d4c0fb9b36/install.sh -O - | sh -s -- -b /usr/local/bin
- name: Run GoReleaser
id: release
uses: goreleaser/goreleaser-action@b508e2e3ef3b19d4e4146d4f8fb3ba9db644a757 # v3.2.0
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
COSIGN_KEY: ${{ secrets.COSIGN_KEY }}
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
POSTHOG_ENDPOINT: ${{ secrets.POSTHOG_ENDPOINT }}
- name: Generate SBOMs, upload to release and attest
id: attest_goreleaser
env:
SYFT_GOLANG_SEARCH_REMOTE_LICENSES: "true"
run: |
# goreleaser output resides in dist/artifacts.json
# Attest all built containers and manifests
images=$(cat dist/artifacts.json | jq -r '.[] | select(.type=="Docker Image" or .type=="Docker Manifest") | .path')
for entry in $images; do
# exclude latest tag
if [[ $entry != *latest ]]; then
material_name="$(echo $entry | sed 's#.*/##')"
# Extract repository with tag from the full image path (format: ghcr.io/org/repo:tag)
repo_with_tag="$(echo $entry | awk -F'/' '{print $4}')"
# Extract just the repository name by splitting at the colon and taking the first part
repo_name="$(echo $repo_with_tag | awk -F':' '{print $1}')"
# Extract the tag by splitting at the colon and taking the second part
tag="$(echo $repo_with_tag | awk -F':' '{print $2}')"
# Extract the architecture from the tag (assumed to be the last part after the dash)
# and replace dots with dashes for consistency
arch="$(echo $tag | awk -F'-' '{print $NF}' | tr '.' '-')"
container_name="${repo_name}-${arch}"
sbom_name="${repo_name}-sbom-${arch}"
syft -o cyclonedx-json=/tmp/sbom-$material_name.cyclonedx.json $entry
chainloop attestation add --name $container_name --value $entry --kind CONTAINER_IMAGE --attestation-id ${{ env.ATTESTATION_ID }}
chainloop attestation add --name $sbom_name --value /tmp/sbom-$material_name.cyclonedx.json --kind SBOM_CYCLONEDX_JSON --attestation-id ${{ env.ATTESTATION_ID }}
# Upload the SBOM to the release
gh release upload ${{ github.ref_name }} /tmp/sbom-$material_name.cyclonedx.json --clobber
fi
done
# Attest the cli binaries
binaries=$(cat dist/artifacts.json | jq -r '.[] | select(.type=="Binary" and .extra.ID!="binaries-cli") | select(.path | startswith("dist/cli")) | .path')
echo "$binaries" | while IFS= read -r entry; do
# Extract OS and ARCH
os_arch=$(echo "$entry" | sed -E 's|dist/cli_([^_]+)_([^/_]+).*|\1-\2|')
# Format as chainloop-OS-ARCH
material_name="chainloop-$os_arch"
chainloop attestation add --name $material_name --value $entry --kind ARTIFACT --attestation-id ${{ env.ATTESTATION_ID }}
done
- name: Include source code on attestation
run: |
# This needs to run AFTER goreleaser to make sure the source code is available
gh release download ${{ github.ref_name }} -A tar.gz -O /tmp/source-code.tar.gz
chainloop attestation add --name source-code --value /tmp/source-code.tar.gz --kind ARTIFACT --attestation-id ${{ env.ATTESTATION_ID }}
- name: Bump Chart and Dagger Version
run: .github/workflows/utils/bump-chart-and-dagger-version.sh deployment/chainloop extras/dagger ${{ github.ref_name }}
- name: Bump Project Version
run: .github/workflows/utils/bump-project-version.sh
- name: Create Pull Request
uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 # v5.0.2
with:
commit-message: Bump Chart and Dagger Version ${{ github.ref_name }}
signoff: true
base: main
title: Bump Helm Chart and Dagger Version => ${{ github.ref_name }}
body: |
A new Chainloop release is available! Bumping Helm Chart reference and Dagger version to ${{ github.ref_name }}
labels: |
automated
helm
finish_attestation:
name: Finish Attestation
runs-on: ubuntu-latest
needs:
- init_attestation
- release
env:
CHAINLOOP_TOKEN: ${{ secrets.CHAINLOOP_TOKEN }}
outputs:
attestation_hash: ${{ steps.attestation_push.outputs.attestation_sha }}
steps:
- name: Install Chainloop
run: |
curl -sfL https://dl.chainloop.dev/cli/install.sh | bash -s
- name: Finish and Record Attestation
id: attestation_push
if: ${{ success() }}
run: |
chainloop attestation push --attestation-id ${{ needs.init_attestation.outputs.attestation_id }}
attestation_sha=$(chainloop wf run describe --id ${{ needs.init_attestation.outputs.attestation_id }} -o json | jq -r '.attestation.digest')
# check that the command succeeded
if [ -n "$attestation_sha" ]; then
echo "attestation_sha=$attestation_sha" >> $GITHUB_OUTPUT
else
exit 1
fi
- name: Mark attestation as failed
if: ${{ failure() }}
run: |
chainloop attestation reset --attestation-id ${{ needs.init_attestation.outputs.attestation_id }}
- name: Mark attestation as cancelled
if: ${{ cancelled() }}
run: |
chainloop attestation reset --trigger cancellation --attestation-id ${{ needs.init_attestation.outputs.attestation_id }}
modify_release_notes:
if: ${{ success() }}
needs: finish_attestation
runs-on: ubuntu-latest
permissions:
packages: write
contents: write
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Add attestation link to release notes
if: ${{ success() }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ATTESTATION_SHA: ${{ needs.finish_attestation.outputs.attestation_hash }}
run: |
chainloop_release_url="## Chainloop Attestation"$'\n'"[View the attestation of this release](https://app.chainloop.dev/attestation/${{ env.ATTESTATION_SHA }})"
current_notes=$(gh release view ${{github.ref_name}} --json body -q '.body')
if echo "$current_notes" | grep -q "## Chainloop Attestation"; then
# Replace the existing Chainloop Attestation section with the new URL
modified_notes=$(echo "$current_notes" | sed -E "s|## Chainloop Attestation[^\n]*\n\[View the attestation of this release\]\(https://app\.chainloop\.dev/attestation/[^\)]*\)|$chainloop_release_url|")
else
# Add the Chainloop Attestation section to the top
modified_notes="$chainloop_release_url"$'\n\n'"$current_notes"
fi
# Update the release notes and ignore if it fails since we might be lacking permissions to update the release notes
gh release edit ${{github.ref_name}} -n "$modified_notes" || echo -n "Not enough permissions to edit the release notes. Skipping..."