Skip to content

Commit 8cdecbf

Browse files
fix(release): publish archive SBOMs from the sole tag workflow (#90)
Co-authored-by: Antoine Toussaint <312536060+antoinetoussaint-byte@users.noreply.github.com>
1 parent d9176bd commit 8cdecbf

4 files changed

Lines changed: 79 additions & 0 deletions

File tree

‎.github/workflows/releaser.yml‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,20 @@ jobs:
2727
# ARCHITECTURE: this maintained cross toolchain supplies the Linux and
2828
# macOS compilers required by Core's tree-sitter-backed project
2929
# inspection while preserving the GoReleaser artifact contract.
30+
- name: Install Syft for archive SBOMs
31+
id: syft
32+
uses: anchore/sbom-action/download-syft@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2
33+
with:
34+
syft-version: v1.44.0
3035
- name: Run CGO-capable GoReleaser
3136
run: >-
3237
docker run --rm
3338
-e GITHUB_TOKEN
3439
-v "$GITHUB_WORKSPACE:/workspace"
40+
-v "$SYFT_PATH:/usr/local/bin/syft:ro"
3541
-w /workspace
3642
ghcr.io/goreleaser/goreleaser-cross:v1.27.1-1
3743
release --clean
3844
env:
3945
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
46+
SYFT_PATH: ${{ steps.syft.outputs.cmd }}

‎.goreleaser.yaml‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
version: 2
22

3+
sboms:
4+
- id: archives
5+
artifacts: archive
6+
documents:
7+
- "${artifact}.sbom.json"
8+
disable: false
9+
310
project_name: service-python
411

512
builds:

‎agent.codefly.yaml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@ publisher: codefly.dev
22
kind: codefly:service
33
name: python
44
version: 0.0.63
5+
release:
6+
owner: workflow
7+
workflow: releaser.yml

‎release_test.go‎

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package main
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"strings"
7+
"testing"
8+
9+
"gopkg.in/yaml.v3"
10+
)
11+
12+
func TestReleaseDeclaresOnePublisherAndArchiveSBOMs(t *testing.T) {
13+
read := func(path string, target any) {
14+
t.Helper()
15+
payload, err := os.ReadFile(path)
16+
if err != nil {
17+
t.Fatal(err)
18+
}
19+
if err := yaml.Unmarshal(payload, target); err != nil {
20+
t.Fatal(err)
21+
}
22+
}
23+
var manifest struct {
24+
Release struct{ Owner, Workflow string }
25+
}
26+
read("agent.codefly.yaml", &manifest)
27+
if manifest.Release.Owner != "workflow" || manifest.Release.Workflow != "releaser.yml" {
28+
t.Fatal("the tag workflow must be the sole artifact publisher")
29+
}
30+
var config struct {
31+
SBOMs []struct {
32+
Artifacts string
33+
Documents []string
34+
Disable bool
35+
} `yaml:"sboms"`
36+
}
37+
read(".goreleaser.yaml", &config)
38+
if len(config.SBOMs) != 1 || config.SBOMs[0].Artifacts != "archive" || config.SBOMs[0].Disable || len(config.SBOMs[0].Documents) != 1 || config.SBOMs[0].Documents[0] != "${artifact}.sbom.json" {
39+
t.Fatal("each published archive must carry its canonical SBOM")
40+
}
41+
var workflow struct {
42+
Jobs map[string]struct {
43+
Steps []struct {
44+
ID, Uses, Run string
45+
Env map[string]string
46+
}
47+
}
48+
}
49+
read(filepath.Join(".github", "workflows", manifest.Release.Workflow), &workflow)
50+
installed, mounted := false, false
51+
for _, step := range workflow.Jobs["release"].Steps {
52+
if step.ID == "syft" && strings.HasPrefix(step.Uses, "anchore/sbom-action/download-syft@") {
53+
installed = true
54+
}
55+
if strings.Contains(step.Run, `-v "$SYFT_PATH:/usr/local/bin/syft:ro"`) && step.Env["SYFT_PATH"] == "${{ steps.syft.outputs.cmd }}" {
56+
mounted = true
57+
}
58+
}
59+
if !installed || !mounted {
60+
t.Fatal("the canonical cross build must have Syft installed and mounted")
61+
}
62+
}

0 commit comments

Comments
 (0)