Skip to content

Commit 572eec1

Browse files
authored
Merge pull request #19 from philips-labs/chore/add-provenance-sbom
2 parents 4df5c3b + b08a1f6 commit 572eec1

File tree

3 files changed

+179
-0
lines changed

3 files changed

+179
-0
lines changed

.github/workflows/ci.yaml

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ jobs:
6868
release:
6969
name: release
7070
needs: [build]
71+
outputs:
72+
container_digest: ${{ steps.container_info.outputs.container_digest }}
73+
container_tags: ${{ steps.container_info.outputs.container_tags }}
7174

7275
runs-on: ubuntu-20.04
7376

@@ -87,6 +90,9 @@ jobs:
8790
with:
8891
cosign-release: 'v1.6.0'
8992

93+
- name: Install Syft
94+
uses: anchore/sbom-action/[email protected]
95+
9096
- name: Checkout
9197
uses: actions/checkout@v3
9298
with:
@@ -126,6 +132,149 @@ jobs:
126132
GIT_HASH: ${{ steps.release-vars.outputs.GIT_HASH }}
127133
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
128134

135+
- name: Get container info
136+
id: container_info
137+
if: startsWith(github.ref, 'refs/tags/')
138+
run: |
139+
export CONTAINER_DIGEST=$(make container-digest GITHUB_REF=${{ github.ref_name }})
140+
echo "::set-output name=container_digest::$CONTAINER_DIGEST"
141+
echo "::set-output name=container_tags::$(make container-tags CONTAINER_DIGEST="${CONTAINER_DIGEST}" | paste -s -d ',' -)"
142+
129143
- name: Cleanup signing keys
130144
if: ${{ always() }}
131145
run: rm -f cosign.key
146+
147+
sbom:
148+
name: sbom
149+
needs: [release]
150+
if: startsWith(github.ref, 'refs/tags/')
151+
runs-on: ubuntu-20.04
152+
env:
153+
TAGS: "${{ needs.release.outputs.container_tags }}"
154+
155+
steps:
156+
- name: Install cosign
157+
uses: sigstore/[email protected]
158+
with:
159+
cosign-release: 'v1.6.0'
160+
161+
- name: Install Syft
162+
uses: anchore/sbom-action/[email protected]
163+
164+
- name: Login to ghcr.io
165+
uses: docker/[email protected]
166+
with:
167+
registry: ghcr.io
168+
username: ${{ github.actor }}
169+
password: ${{ secrets.GITHUB_TOKEN }}
170+
171+
- name: Attach SBOM
172+
env:
173+
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
174+
REPO: ghcr.io/philips-labs/fatt
175+
run: |
176+
echo '${{ secrets.COSIGN_PUBLIC_KEY }}' > cosign.pub
177+
echo '${{ secrets.COSIGN_PRIVATE_KEY }}' > cosign.key
178+
IFS=,
179+
for t in ${TAGS}; do
180+
cosign verify --key cosign.pub ${REPO}:${t}
181+
syft ${REPO}:${t} -o spdx-json > sbom-spdx.json
182+
cosign attach sbom --sbom sbom-spdx.json --type spdx ${REPO}:${t}
183+
cosign attest --predicate sbom-spdx.json --type spdx --key cosign.key ${REPO}:${t}
184+
cosign verify-attestation -o verified-sbom-spdx.json --key cosign.pub ${REPO}:${t}
185+
done
186+
187+
- name: Clean up signing keys
188+
if: ${{ always() }}
189+
run: |
190+
rm -f cosign.key
191+
192+
provenance:
193+
name: provenance
194+
needs: [release]
195+
if: startsWith(github.ref, 'refs/tags/')
196+
runs-on: ubuntu-20.04
197+
198+
steps:
199+
- name: Generate provenance for Release
200+
uses: philips-labs/[email protected]
201+
with:
202+
command: generate
203+
subcommand: github-release
204+
arguments: --artifact-path release-assets --output-path provenance.att --tag-name ${{ github.ref_name }}
205+
env:
206+
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
207+
208+
- name: Install cosign
209+
uses: sigstore/[email protected]
210+
with:
211+
cosign-release: 'v1.6.0'
212+
213+
- name: Sign provenance
214+
run: |
215+
echo '${{ secrets.COSIGN_PRIVATE_KEY }}' > cosign.key
216+
cosign sign-blob --key cosign.key --output-signature "${SIGNATURE}" provenance.att
217+
cat "${SIGNATURE}"
218+
curl_args=(-s -H "Authorization: token ${GITHUB_TOKEN}")
219+
curl_args+=(-H "Accept: application/vnd.github.v3+json")
220+
release_id="$(curl "${curl_args[@]}" "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases?per_page=10" | jq "map(select(.name == \"${GITHUB_REF_NAME}\"))" | jq -r '.[0].id')"
221+
echo "Upload ${SIGNATURE} to release with id ${release_id}…"
222+
curl_args+=(-H "Content-Type: $(file -b --mime-type "${SIGNATURE}")")
223+
curl "${curl_args[@]}" \
224+
--data-binary @"${SIGNATURE}" \
225+
"https://uploads.github.com/repos/${GITHUB_REPOSITORY}/releases/${release_id}/assets?name=${SIGNATURE}"
226+
env:
227+
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
228+
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
229+
SIGNATURE: provenance.att.sig
230+
231+
container-provenance:
232+
name: container-provenance
233+
needs: [release]
234+
if: startsWith(github.ref, 'refs/tags/')
235+
runs-on: ubuntu-20.04
236+
env:
237+
REPO: ghcr.io/philips-labs/fatt
238+
239+
steps:
240+
- name: Install cosign
241+
uses: sigstore/[email protected]
242+
with:
243+
cosign-release: 'v1.6.0'
244+
245+
- name: Generate provenance for ${REPO}
246+
uses: philips-labs/[email protected]
247+
with:
248+
command: generate
249+
subcommand: container
250+
arguments: --repository ${REPO} --output-path provenance.att --digest ${{ needs.release.outputs.container_digest }} --tags ${{ needs.release.outputs.container_tags }}
251+
env:
252+
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
253+
254+
- name: Get slsa-provenance predicate
255+
run: |
256+
cat provenance.att | jq .predicate > provenance-predicate.att
257+
258+
- name: Login to ghcr.io
259+
uses: docker/[email protected]
260+
with:
261+
registry: ghcr.io
262+
username: ${{ github.actor }}
263+
password: ${{ secrets.GITHUB_TOKEN }}
264+
265+
- name: Attach provenance to image
266+
run: |
267+
echo '${{ secrets.COSIGN_PRIVATE_KEY }}' > cosign.key
268+
cosign attest --predicate provenance-predicate.att --type slsaprovenance --key cosign.key ${REPO}@${{ needs.release.outputs.container_digest }}
269+
env:
270+
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
271+
272+
- name: Verify attestation
273+
run: |
274+
echo '${{ secrets.COSIGN_PUBLIC_KEY }}' > cosign.pub
275+
cosign verify-attestation --key cosign.pub ${REPO}@${{ needs.release.outputs.container_digest }}
276+
277+
- name: Cleanup signing keys
278+
if: ${{ always() }}
279+
run: |
280+
rm -f cosign.key

.goreleaser.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ archives:
3636
- goos: windows
3737
format: zip
3838

39+
sboms:
40+
- id: archive-sbom
41+
cmd: syft
42+
args: ["${artifact}", "--file", "${artifact}.sbom.json", "--output", "spdx-json"]
43+
documents:
44+
- "${artifact}.sbom.json"
45+
artifacts: archive
46+
3947
checksum:
4048
name_template: 'checksums.txt'
4149

@@ -100,6 +108,18 @@ signs:
100108
- '--output-certificate=${certificate}'
101109
- '--output-signature=${signature}'
102110
- '${artifact}'
111+
- id: sboms
112+
cmd: cosign
113+
stdin: '{{ .Env.COSIGN_PASSWORD }}'
114+
output: true
115+
artifacts: sbom
116+
args:
117+
- sign-blob
118+
- --key
119+
- cosign.key
120+
- '--output-certificate=${certificate}'
121+
- '--output-signature=${signature}'
122+
- '${artifact}'
103123

104124
docker_signs:
105125
- cmd: cosign

Makefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,13 @@ release: $(GO_PATH)/bin/goreleaser ## creates a release using goreleaser
9696
.PHONY: release-vars
9797
release-vars: ## print the release variables for goreleaser
9898
@echo export LDFLAGS=\"$(LDFLAGS)\"
99+
100+
.PHONY: container-digest
101+
container-digest: ## retrieves the container digest from the given tag
102+
@:$(call check_defined, GITHUB_REF)
103+
@docker inspect $(GHCR_REPO):$(subst refs/tags/,,$(GITHUB_REF)) --format '{{ index .RepoDigests 0 }}' | cut -d '@' -f 2
104+
105+
.PHONY: container-tags
106+
container-tags: ## retrieves the container tags applied to the image with a given digest
107+
@:$(call check_defined, CONTAINER_DIGEST)
108+
@docker inspect ghcr.io/philips-labs/fatt@$(CONTAINER_DIGEST) --format '{{ join .RepoTags "\n" }}' | sed 's/.*://' | awk '!_[$$0]++'

0 commit comments

Comments
 (0)