-
Notifications
You must be signed in to change notification settings - Fork 49
282 lines (237 loc) · 12.6 KB
/
release.yaml
File metadata and controls
282 lines (237 loc) · 12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
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:
release_gate:
name: Release Gate
runs-on: ubuntu-latest
if: github.ref_type == 'tag'
permissions:
id-token: write # required for SLSA provenance
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Install Chainloop
run: |
curl -sfL https://dl.chainloop.dev/cli/install.sh | bash -s -- --ee
- name: Run Release Gate Attestation
run: |
chainloop attestation init --workflow release-gate --project chainloop
chainloop attestation push
env:
CHAINLOOP_TOKEN: ${{ secrets.CHAINLOOP_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Mark attestation as failed
if: ${{ failure() }}
run: |
chainloop attestation reset
env:
CHAINLOOP_TOKEN: ${{ secrets.CHAINLOOP_TOKEN }}
- name: Mark attestation as cancelled
if: ${{ cancelled() }}
run: |
chainloop attestation reset --trigger cancellation
env:
CHAINLOOP_TOKEN: ${{ secrets.CHAINLOOP_TOKEN }}
test:
uses: chainloop-dev/chainloop/.github/workflows/test.yml@d427768c0b07d50b485df0bcae87eb8ae8769e04
release:
name: Release CLI and control-plane/artifact-cas container images
needs: [release_gate, test]
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 }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Install Cosign
uses: sigstore/cosign-installer@ef6a6b364bbad08abd36a5f8af60b595d12702f8 # main
with:
cosign-release: "v2.2.3"
- name: Install Chainloop
run: |
# Need the ee CLI to have access to project management capabilities
curl -sfL https://dl.chainloop.dev/cli/install.sh | bash -s -- --ee
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- 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_WORKFLOW_NAME: "release"
CHAINLOOP_PROJECT_NAME: "chainloop"
# Needed for commit signature verification: https://docs.chainloop.dev/concepts/attestations#commit-verification
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- 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@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
with:
go-version-file: 'go.mod'
# 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: Install Grype
run: curl -sSfL https://raw.githubusercontent.com/anchore/grype/fe186c3e986dda3cb4c5e90798f82c52aefcb4b8/install.sh | 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"
ATTESTATION_ID: ${{ steps.init_attestation.outputs.attestation_id }}
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
# Add missing known licenses
# https://github.com/ariga/atlas/blob/master/LICENSE
${{ github.workspace }}/.github/workflows/utils/add-license-to-sbom.sh /tmp/sbom-$material_name.cyclonedx.json "ariga.io/atlas" "Apache-2.0" type="library"
${{ github.workspace }}/.github/workflows/utils/add-license-to-sbom.sh /tmp/sbom-$material_name.cyclonedx.json "ariga.io/atlas/cmd/atlas" "Apache-2.0" type="library"
${{ github.workspace }}/.github/workflows/utils/add-license-to-sbom.sh /tmp/sbom-$material_name.cyclonedx.json "github.com/ariga/language-tools/packages/language-server-go" "Apache-2.0" type="library"
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
# Run Grype vulnerability scan and attest result
grype --only-fixed -o sarif --file ./vuln-${container_name}.json $entry
chainloop attestation add --name ${container_name}-vulnerability-report --value ./vuln-${container_name}.json --attestation-id ${{ env.ATTESTATION_ID }}
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
env:
ATTESTATION_ID: ${{ steps.init_attestation.outputs.attestation_id }}
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: Read current project version
id: project_version
run: |
current_version="$(awk '/^projectVersion:/ {print $2}' .chainloop.yml)"
echo "current_version=$current_version" >> $GITHUB_OUTPUT
- 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 ${{ github.ref_name }}
- name: Create Pull Request
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
commit-message: Bump Chart and Dagger Version ${{ github.ref_name }}
signoff: true
sign-commits: 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
- name: Finish and Record Attestation
id: attestation_push
if: ${{ success() }}
env:
ATTESTATION_ID: ${{ steps.init_attestation.outputs.attestation_id }}
run: |
chainloop attestation push --attestation-id ${{ env.ATTESTATION_ID }}
attestation_sha=$(chainloop wf run describe --id ${{ env.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: Promote Chainloop Project Version
if: ${{ success() }}
env:
CURRENT_VERSION: ${{ steps.project_version.outputs.current_version }}
TARGET_VERSION: ${{ github.ref_name }}
run: |
echo "current_version=$CURRENT_VERSION"
echo "target_version=$TARGET_VERSION"
chainloop project version update --project chainloop --name "$CURRENT_VERSION" --new-name "$TARGET_VERSION" || true
- name: Add attestation link to release notes
if: ${{ success() }}
env:
ATTESTATION_SHA: ${{ steps.attestation_push.outputs.attestation_sha }}
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..."
- name: Mark attestation as failed
if: ${{ failure() }}
env:
ATTESTATION_ID: ${{ steps.init_attestation.outputs.attestation_id }}
run: |
chainloop attestation reset --attestation-id ${{ env.ATTESTATION_ID }}
- name: Mark attestation as cancelled
if: ${{ cancelled() }}
env:
ATTESTATION_ID: ${{ steps.init_attestation.outputs.attestation_id }}
run: |
chainloop attestation reset --trigger cancellation --attestation-id ${{ env.ATTESTATION_ID }}