Skip to content

Commit 0c562f6

Browse files
Add support for fetching SBOMs (#2869)
Fixes: #2864.
1 parent 1a4b106 commit 0c562f6

File tree

6 files changed

+435
-0
lines changed

6 files changed

+435
-0
lines changed

github/dependency_graph.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright 2023 The go-github AUTHORS. All rights reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style
4+
// license that can be found in the LICENSE file.
5+
6+
package github
7+
8+
import (
9+
"context"
10+
"fmt"
11+
)
12+
13+
type DependencyGraphService service
14+
15+
// SBOM represents a software bill of materials, which describes the
16+
// packages/libraries that a repository depends on.
17+
type SBOM struct {
18+
SBOM *SBOMInfo `json:"sbom,omitempty"`
19+
}
20+
21+
// CreationInfo represents when the SBOM was created and who created it.
22+
type CreationInfo struct {
23+
Created *Timestamp `json:"created,omitempty"`
24+
Creators []string `json:"creators,omitempty"`
25+
}
26+
27+
// RepoDependencies represents the dependencies of a repo.
28+
type RepoDependencies struct {
29+
SPDXID *string `json:"SPDXID,omitempty"`
30+
// Package name
31+
Name *string `json:"name,omitempty"`
32+
VersionInfo *string `json:"versionInfo,omitempty"`
33+
DownloadLocation *string `json:"downloadLocation,omitempty"`
34+
FilesAnalyzed *bool `json:"filesAnalyzed,omitempty"`
35+
LicenseConcluded *string `json:"licenseConcluded,omitempty"`
36+
LicenseDeclared *string `json:"licenseDeclared,omitempty"`
37+
}
38+
39+
// SBOMInfo represents a software bill of materials (SBOM) using SPDX.
40+
// SPDX is an open standard for SBOMs that
41+
// identifies and catalogs components, licenses, copyrights, security
42+
// references, and other metadata relating to software.
43+
type SBOMInfo struct {
44+
SPDXID *string `json:"SPDXID,omitempty"`
45+
SPDXVersion *string `json:"spdxVersion,omitempty"`
46+
CreationInfo *CreationInfo `json:"creationInfo,omitempty"`
47+
48+
// Repo name
49+
Name *string `json:"name,omitempty"`
50+
DataLicense *string `json:"dataLicense,omitempty"`
51+
DocumentDescribes []string `json:"documentDescribes,omitempty"`
52+
DocumentNamespace *string `json:"documentNamespace,omitempty"`
53+
54+
// List of packages dependencies
55+
Packages []*RepoDependencies `json:"packages,omitempty"`
56+
}
57+
58+
func (s SBOM) String() string {
59+
return Stringify(s)
60+
}
61+
62+
// GetSBOM fetches the software bill of materials for a repository.
63+
//
64+
// GitHub API docs: https://docs.github.com/en/rest/dependency-graph/sboms
65+
func (s *DependencyGraphService) GetSBOM(ctx context.Context, owner, repo string) (*SBOM, *Response, error) {
66+
u := fmt.Sprintf("repos/%v/%v/dependency-graph/sbom", owner, repo)
67+
68+
req, err := s.client.NewRequest("GET", u, nil)
69+
if err != nil {
70+
return nil, nil, err
71+
}
72+
73+
var sbom *SBOM
74+
resp, err := s.client.Do(ctx, req, &sbom)
75+
if err != nil {
76+
return nil, resp, err
77+
}
78+
79+
return sbom, resp, nil
80+
}

github/dependency_graph_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright 2023 The go-github AUTHORS. All rights reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style
4+
// license that can be found in the LICENSE file.
5+
6+
package github
7+
8+
import (
9+
"context"
10+
"fmt"
11+
"net/http"
12+
"testing"
13+
"time"
14+
15+
"github.com/google/go-cmp/cmp"
16+
)
17+
18+
func TestDependencyGraphService_GetSBOM(t *testing.T) {
19+
client, mux, _, teardown := setup()
20+
defer teardown()
21+
22+
mux.HandleFunc("/repos/owner/repo/dependency-graph/sbom", func(w http.ResponseWriter, r *http.Request) {
23+
testMethod(t, r, "GET")
24+
fmt.Fprint(w, `{
25+
"sbom":{
26+
"creationInfo":{
27+
"created":"2021-09-01T00:00:00Z"
28+
},
29+
"name":"owner/repo",
30+
"packages":[
31+
{
32+
"name":"rubygems:rails",
33+
"versionInfo":"1.0.0"
34+
}
35+
]
36+
}
37+
}`)
38+
})
39+
40+
ctx := context.Background()
41+
sbom, _, err := client.DependencyGraph.GetSBOM(ctx, "owner", "repo")
42+
if err != nil {
43+
t.Errorf("DependencyGraph.GetSBOM returned error: %v", err)
44+
}
45+
46+
testTime := time.Date(2021, 9, 1, 0, 0, 0, 0, time.UTC)
47+
want := &SBOM{
48+
&SBOMInfo{
49+
CreationInfo: &CreationInfo{
50+
Created: &Timestamp{testTime},
51+
},
52+
Name: String("owner/repo"),
53+
Packages: []*RepoDependencies{
54+
{
55+
Name: String("rubygems:rails"),
56+
VersionInfo: String("1.0.0"),
57+
},
58+
},
59+
},
60+
}
61+
62+
if !cmp.Equal(sbom, want) {
63+
t.Errorf("DependencyGraph.GetSBOM returned %+v, want %+v", sbom, want)
64+
}
65+
66+
const methodName = "GetSBOM"
67+
testBadOptions(t, methodName, func() (err error) {
68+
_, _, err = client.DependencyGraph.GetSBOM(ctx, "\n", "\n")
69+
return err
70+
})
71+
72+
testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
73+
got, resp, err := client.DependencyGraph.GetSBOM(ctx, "owner", "repo")
74+
if got != nil {
75+
t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
76+
}
77+
return resp, err
78+
})
79+
}

github/github-accessors.go

Lines changed: 120 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)