Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit 022a6eb

Browse files
committed
Add function to send Sbom
1 parent 4205c9f commit 022a6eb

File tree

5 files changed

+140
-25
lines changed

5 files changed

+140
-25
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ require (
77
github.com/anchore/stereoscope v0.0.0-20221006201143-d24c9d626b33
88
github.com/anchore/syft v0.62.1
99
github.com/aquasecurity/trivy v0.30.4
10-
github.com/atomist-skills/go-skill v0.0.6-0.20221003172518-c3d268e1f3f1
10+
github.com/atomist-skills/go-skill v0.0.6-0.20221221214636-a7de163fd901
1111
github.com/briandowns/spinner v1.12.0
1212
github.com/docker/cli v20.10.21+incompatible
1313
github.com/docker/docker v20.10.17+incompatible

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l
209209
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
210210
github.com/atomist-skills/go-skill v0.0.6-0.20221003172518-c3d268e1f3f1 h1:EzSOh9LLtL/3IzbPUFSp/6OF4DrgiCPxCC3x3jjD9Bs=
211211
github.com/atomist-skills/go-skill v0.0.6-0.20221003172518-c3d268e1f3f1/go.mod h1:DRmwrZL5kG68Mn8VDw/Xr7rDhyl+laD7NFHIrQr54yo=
212+
github.com/atomist-skills/go-skill v0.0.6-0.20221221214636-a7de163fd901 h1:0fqUAo4MmWXnWIDCG7JBe903M3WJ+tqQetPIkVfcXKo=
213+
github.com/atomist-skills/go-skill v0.0.6-0.20221221214636-a7de163fd901/go.mod h1:DRmwrZL5kG68Mn8VDw/Xr7rDhyl+laD7NFHIrQr54yo=
212214
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
213215
github.com/aws/aws-sdk-go v1.44.46 h1:BsKENvu24eXg7CWQ2wJAjKbDFkGP+hBtxKJIR3UdcB8=
214216
github.com/aws/aws-sdk-go v1.44.46/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=

sbom/lsp.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright © 2022 Docker, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package sbom
18+
19+
import (
20+
"github.com/docker/cli/cli/command"
21+
cliflags "github.com/docker/cli/cli/flags"
22+
"github.com/pkg/errors"
23+
)
24+
25+
func Send(image string, tx chan<- string) error {
26+
cmd, err := command.NewDockerCli()
27+
if err != nil {
28+
return errors.Wrap(err, "failed to create docker cli")
29+
}
30+
if err := cmd.Initialize(cliflags.NewClientOptions()); err != nil {
31+
return errors.Wrap(err, "failed to initialize docker cli")
32+
}
33+
sbom, err := IndexImage(image, cmd)
34+
if err != nil {
35+
return errors.Wrap(err, "failed to create sbom")
36+
}
37+
err = sendSbom(sbom, tx)
38+
if err != nil {
39+
return errors.Wrap(err, "failed to send sbom")
40+
}
41+
close(tx)
42+
return nil
43+
}

sbom/lsp_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright © 2022 Docker, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package sbom
18+
19+
import (
20+
"testing"
21+
)
22+
23+
func TestSend(t *testing.T) {
24+
tx := make(chan string, 10)
25+
transactions := make([]string, 0)
26+
27+
err := Send("alpine@sha256:c0d488a800e4127c334ad20d61d7bc21b4097540327217dfab52262adc02380c", tx)
28+
if err != nil {
29+
t.Fail()
30+
}
31+
for elem := range tx {
32+
transactions = append(transactions, elem)
33+
}
34+
if len(transactions) != 3 {
35+
t.Errorf("expected 3 transactions, instead got %d", len(transactions))
36+
}
37+
}

sbom/upload.go

Lines changed: 57 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,67 @@ import (
3333
"olympos.io/encoding/edn"
3434
)
3535

36+
type TransactionMaker = func() skill.Transaction
37+
3638
// UploadSbom transact an image and its data into the data plane
3739
func UploadSbom(sb *types.Sbom, workspace string, apikey string) error {
38-
host, name, err := parseReference(sb)
40+
correlationId := uuid.NewString()
41+
context := skill.RequestContext{
42+
Event: skill.EventIncoming{
43+
ExecutionId: correlationId,
44+
WorkspaceId: workspace,
45+
Token: apikey,
46+
},
47+
}
48+
49+
newTransaction := context.NewTransaction
50+
image, err := transactSbom(sb, newTransaction)
3951
if err != nil {
40-
return errors.Wrapf(err, "failed to obtain host and repository")
52+
return errors.Wrap(err, "failed to transact image")
4153
}
42-
config := (*sb).Source.Image.Config
43-
manifest := (*sb).Source.Image.Manifest
4454

45-
now := time.Now()
55+
imageName := ""
56+
if image.Repository.Host != "hub.docker.com" {
57+
imageName = image.Repository.Host + "/"
58+
}
59+
imageName += image.Repository.Name
60+
61+
skill.Log.Infof("Inspect image at https://dso.docker.com/%s/overview/images/%s/digests/%s", workspace, imageName, image.Digest)
62+
63+
return nil
64+
}
65+
66+
func sendSbom(sb *types.Sbom, entities chan<- string) error {
4667
correlationId := uuid.NewString()
4768
context := skill.RequestContext{
4869
Event: skill.EventIncoming{
4970
ExecutionId: correlationId,
50-
WorkspaceId: workspace,
51-
Token: apikey,
5271
},
5372
}
54-
transaction := context.NewTransaction().Ordered()
73+
74+
newTransaction := func() skill.Transaction {
75+
return context.NewTransactionWithTransactor(func(entitiesString string) {
76+
entities <- entitiesString
77+
})
78+
}
79+
_, err := transactSbom(sb, newTransaction)
80+
if err != nil {
81+
return errors.Wrap(err, "failed to transact image")
82+
}
83+
84+
return nil
85+
}
86+
87+
func transactSbom(sb *types.Sbom, newTransaction func() skill.Transaction) (*ImageEntity, error) {
88+
now := time.Now()
89+
host, name, err := parseReference(sb)
90+
if err != nil {
91+
return nil, errors.Wrap(err, "failed to obtain host and repository")
92+
}
93+
config := (*sb).Source.Image.Config
94+
manifest := (*sb).Source.Image.Manifest
95+
96+
transaction := newTransaction().Ordered()
5597
ports := parsePorts(config)
5698
env, envVars := parseEnvVars(config)
5799
sha := parseSha(config)
@@ -111,7 +153,7 @@ func UploadSbom(sb *types.Sbom, workspace string, apikey string) error {
111153
image.Sha = sha
112154
}
113155

114-
if len(*sb.Source.Image.Tags) > 0 {
156+
if sb.Source.Image.Tags != nil && len(*sb.Source.Image.Tags) > 0 {
115157
image.Tags = &skill.ManyRef{Add: *sb.Source.Image.Tags}
116158

117159
for _, t := range *sb.Source.Image.Tags {
@@ -136,13 +178,13 @@ func UploadSbom(sb *types.Sbom, workspace string, apikey string) error {
136178
// transact the image with all its metadata (repo, tags, layers, blobs, ports, env etc)
137179
err = transaction.AddEntities(image, platform).Transact()
138180
if err != nil {
139-
return errors.Wrapf(err, "failed to transact image")
181+
return nil, errors.Wrapf(err, "failed to transact image")
140182
}
141183

142184
// transact all packages in chunks
143185
packageChunks := internal.ChunkSlice(sb.Artifacts, 20)
144186
for _, packages := range packageChunks {
145-
transaction := context.NewTransaction().Ordered()
187+
transaction := newTransaction().Ordered()
146188

147189
image = ImageEntity{
148190
Digest: sb.Source.Image.Digest,
@@ -186,28 +228,19 @@ func UploadSbom(sb *types.Sbom, workspace string, apikey string) error {
186228
image.Dependencies = &skill.ManyRef{Add: transaction.EntityRefs("package/dependency")}
187229
err := transaction.AddEntities(image).Transact()
188230
if err != nil {
189-
return errors.Wrapf(err, "failed to transact packages")
231+
return nil, errors.Wrapf(err, "failed to transact packages")
190232
}
191233
}
192234

193235
image = ImageEntity{
194236
Digest: sb.Source.Image.Digest,
195237
SbomState: Indexed,
196238
}
197-
err = context.NewTransaction().Ordered().AddEntities(image).Transact()
239+
err = newTransaction().Ordered().AddEntities(image).Transact()
198240
if err != nil {
199-
return errors.Wrapf(err, "failed to transact packages")
241+
return nil, errors.Wrapf(err, "failed to transact packages")
200242
}
201-
202-
imageName := ""
203-
if host != "hub.docker.com" {
204-
imageName = host + "/"
205-
}
206-
imageName += name
207-
208-
skill.Log.Infof("Inspect image at https://dso.docker.com/%s/overview/images/%s/digests/%s", workspace, imageName, image.Digest)
209-
210-
return nil
243+
return &image, nil
211244
}
212245

213246
func digestChainIds(manifest *v1.Manifest) []digest.Digest {

0 commit comments

Comments
 (0)