Skip to content

Commit

Permalink
feat: add parlay as tool during enrichments
Browse files Browse the repository at this point in the history
Closes #82.
  • Loading branch information
mcombuechen committed Dec 12, 2024
1 parent 2f3d685 commit 796528b
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ builds:
ldflags:
- "-s"
- "-w"
- "-X github.com/snyk/parlay/internal/commands.version={{.Version}}"
- "-X github.com/snyk/parlay/internal/utils.version={{.Version}}"

archives:
- format: tar.gz
Expand Down
12 changes: 2 additions & 10 deletions internal/commands/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ import (
"github.com/snyk/parlay/internal/commands/ecosystems"
"github.com/snyk/parlay/internal/commands/scorecard"
"github.com/snyk/parlay/internal/commands/snyk"
)

// These values are set at build time
var (
version = ""
"github.com/snyk/parlay/internal/utils"
)

func NewDefaultCommand() *cobra.Command {
Expand All @@ -26,7 +22,7 @@ func NewDefaultCommand() *cobra.Command {
Use: "parlay",
Short: "Enrich an SBOM with context from third party services",
SilenceUsage: true,
Version: GetVersion(),
Version: utils.GetVersion(),
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
if err := cmd.Help(); err != nil {
Expand Down Expand Up @@ -55,7 +51,3 @@ func NewDefaultCommand() *cobra.Command {

return &cmd
}

func GetVersion() string {
return version
}
16 changes: 13 additions & 3 deletions internal/commands/ecosystems/enrich.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ import (
)

func NewEnrichCommand(logger *zerolog.Logger) *cobra.Command {
var omitWatermark bool

cmd := cobra.Command{
Use: "enrich <sbom>",
Short: "Enrich an SBOM with ecosyste.ms data",
Args: cobra.ExactArgs(1),
Use: "enrich <sbom>",
Short: "Enrich an SBOM with ecosyste.ms data",
Args: cobra.ExactArgs(1),
Version: utils.GetVersion(),
Run: func(cmd *cobra.Command, args []string) {
b, err := utils.GetUserInput(args[0], os.Stdin)
if err != nil {
Expand All @@ -29,10 +32,17 @@ func NewEnrichCommand(logger *zerolog.Logger) *cobra.Command {

ecosystems.EnrichSBOM(doc, logger)

if !omitWatermark {
sbom.AddParlayWatermark(doc, cmd.Version)
}

if err := doc.Encode(os.Stdout); err != nil {
logger.Fatal().Err(err).Msg("Failed to encode new SBOM")
}
},
}

cmd.Flags().BoolVar(&omitWatermark, "omit-watermark", false, "omit parlay watermark")

return &cmd
}
16 changes: 13 additions & 3 deletions internal/commands/scorecard/enrich.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ import (
)

func NewEnrichCommand(logger *zerolog.Logger) *cobra.Command {
var omitWatermark bool

cmd := cobra.Command{
Use: "enrich <sbom>",
Short: "Enrich an SBOM with OpenSSF Scorecard data",
Args: cobra.ExactArgs(1),
Use: "enrich <sbom>",
Short: "Enrich an SBOM with OpenSSF Scorecard data",
Args: cobra.ExactArgs(1),
Version: utils.GetVersion(),
Run: func(cmd *cobra.Command, args []string) {
b, err := utils.GetUserInput(args[0], os.Stdin)
if err != nil {
Expand All @@ -29,10 +32,17 @@ func NewEnrichCommand(logger *zerolog.Logger) *cobra.Command {

scorecard.EnrichSBOM(doc)

if !omitWatermark {
sbom.AddParlayWatermark(doc, cmd.Version)
}

if err := doc.Encode(os.Stdout); err != nil {
logger.Fatal().Err(err).Msg("Failed to encode new SBOM")
}
},
}

cmd.Flags().BoolVar(&omitWatermark, "omit-watermark", false, "omit parlay watermark")

return &cmd
}
16 changes: 13 additions & 3 deletions internal/commands/snyk/enrich.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ import (
)

func NewEnrichCommand(logger *zerolog.Logger) *cobra.Command {
var omitWatermark bool

cmd := cobra.Command{
Use: "enrich <sbom>",
Short: "Enrich an SBOM with Snyk data",
Args: cobra.ExactArgs(1),
Use: "enrich <sbom>",
Short: "Enrich an SBOM with Snyk data",
Args: cobra.ExactArgs(1),
Version: utils.GetVersion(),
Run: func(cmd *cobra.Command, args []string) {
cfg := config()
svc := snyk.NewService(cfg, logger)
Expand All @@ -32,10 +35,17 @@ func NewEnrichCommand(logger *zerolog.Logger) *cobra.Command {

svc.EnrichSBOM(doc)

if !omitWatermark {
sbom.AddParlayWatermark(doc, cmd.Version)
}

if err := doc.Encode(os.Stdout); err != nil {
logger.Fatal().Err(err).Msg("Failed to encode new SBOM")
}
},
}

cmd.Flags().BoolVar(&omitWatermark, "omit-watermark", false, "omit parlay watermark")

return &cmd
}
8 changes: 8 additions & 0 deletions internal/utils/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package utils

// This value gets set at build time
var version string

func GetVersion() string {
return version
}
32 changes: 32 additions & 0 deletions lib/sbom/cyclonedx.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,35 @@ func encodeCycloneDX(bom *cdx.BOM, f cdx.BOMFileFormat) encoderFn {
return cdx.NewBOMEncoder(w, f).Encode(bom)
}
}

func addCDXTool(bom *cdx.BOM, name, version string) {
if bom.Metadata == nil {
bom.Metadata = &cdx.Metadata{}
}

if bom.Metadata.Tools == nil {
bom.Metadata.Tools = &cdx.ToolsChoice{}
}

// Handle possibly existing, legacy "Tools" entry
if bom.Metadata.Tools.Tools != nil {
*bom.Metadata.Tools.Tools = append(*bom.Metadata.Tools.Tools, cdx.Tool{

Check failure on line 68 in lib/sbom/cyclonedx.go

View workflow job for this annotation

GitHub Actions / build

SA1019: cdx.Tool is deprecated: Use Component or Service instead. (staticcheck)

Check failure on line 68 in lib/sbom/cyclonedx.go

View workflow job for this annotation

GitHub Actions / build

SA1019: cdx.Tool is deprecated: Use Component or Service instead. (staticcheck)
Vendor: "Snyk",
Name: name,
})
return
}

if bom.Metadata.Tools.Components == nil {
bom.Metadata.Tools.Components = &[]cdx.Component{}
}

*bom.Metadata.Tools.Components = append(
*bom.Metadata.Tools.Components,
cdx.Component{
Type: cdx.ComponentTypeApplication,
Name: name,
Version: version,
Publisher: "Snyk",
PackageURL: "pkg:github/snyk/parlay"})
}
10 changes: 10 additions & 0 deletions lib/sbom/spdx.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,13 @@ func encodeSPDX2_3JSON(bom *spdx.Document) encoderFn {
return spdx_json.Write(bom, w)
}
}

func addSPDXTool(bom *spdx.Document, name, _ string) {
if bom.CreationInfo == nil {
bom.CreationInfo = &spdx.CreationInfo{}
}

bom.CreationInfo.Creators = append(
bom.CreationInfo.Creators,
spdx.Creator{Creator: name, CreatorType: "Tool"})
}
31 changes: 31 additions & 0 deletions lib/sbom/watermark.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* © 2024 Snyk Limited All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package sbom

import (
cdx "github.com/CycloneDX/cyclonedx-go"
"github.com/spdx/tools-golang/spdx"
)

func AddParlayWatermark(doc *SBOMDocument, version string) {
switch bom := doc.BOM.(type) {
case *cdx.BOM:
addCDXTool(bom, "parlay", version)
case *spdx.Document:
addSPDXTool(bom, "parlay", version)
}
}
62 changes: 62 additions & 0 deletions lib/sbom/watermark_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* © 2024 Snyk Limited All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package sbom

import (
"testing"

cdx "github.com/CycloneDX/cyclonedx-go"
"github.com/spdx/tools-golang/spdx"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestAddParlayWatermark_CycloneDX(t *testing.T) {
doc, err := DecodeSBOMDocument([]byte(`{
"bomFormat": "CycloneDX",
"specVersion": "1.6"
}`))
require.NoError(t, err)

AddParlayWatermark(doc, "0.0.0")

bom, ok := doc.BOM.(*cdx.BOM)
require.True(t, ok)

require.NotNil(t, bom.Metadata.Tools.Components)
require.Len(t, *bom.Metadata.Tools.Components, 1)
tool := (*bom.Metadata.Tools.Components)[0]
assert.Equal(t, "application", string(tool.Type))
assert.Equal(t, "parlay", tool.Name)
assert.Equal(t, "0.0.0", tool.Version)
assert.Equal(t, "Snyk", tool.Publisher)
}

func TestAddParlayWatermark_SPDX(t *testing.T) {
doc, err := DecodeSBOMDocument([]byte(`{
"spdxVersion": "SPDX-2.3",
"SPDXID": "SPDXRef-DOCUMENT"
}`))
require.NoError(t, err)

AddParlayWatermark(doc, "0.0.0")

bom, ok := doc.BOM.(*spdx.Document)
require.True(t, ok)

assert.Contains(t, bom.CreationInfo.Creators, spdx.Creator{Creator: "parlay", CreatorType: "Tool"})
}

0 comments on commit 796528b

Please sign in to comment.