Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(golangBuild): allow SBOM creation for app only #4771

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions cmd/golangBuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ func runGolangBuild(config *golangBuildOptions, telemetryData *telemetry.CustomD
}

if config.CreateBOM {
if err := runBOMCreation(utils, sbomFilename); err != nil {
if err := runBOMCreation(config, utils, sbomFilename); err != nil {
return err
}
}
Expand All @@ -213,14 +213,12 @@ func runGolangBuild(config *golangBuildOptions, telemetryData *telemetry.CustomD

var binaries []string
platforms, err := multiarch.ParsePlatformStrings(config.TargetArchitectures)

if err != nil {
return err
}

for _, platform := range platforms {
binaryNames, err := runGolangBuildPerArchitecture(config, goModFile, utils, ldflags, platform)

if err != nil {
return err
}
Expand Down Expand Up @@ -262,7 +260,6 @@ func runGolangBuild(config *golangBuildOptions, telemetryData *telemetry.CustomD
}

artifact, err := versioning.GetArtifact("golang", "", &artifactOpts, utils)

if err != nil {
return err
}
Expand Down Expand Up @@ -304,7 +301,6 @@ func runGolangBuild(config *golangBuildOptions, telemetryData *telemetry.CustomD
log.Entry().Infof("publishing artifact: %s", targetURL)

response, err := utils.UploadRequest(http.MethodPut, targetURL, binary, "", nil, nil, "binary")

if err != nil {
return fmt.Errorf("couldn't upload artifact: %w", err)
}
Expand Down Expand Up @@ -407,7 +403,7 @@ func reportGolangTestCoverage(config *golangBuildOptions, utils golangBuildUtils
}
utils.Stdout(log.Writer())

err = utils.FileWrite("cobertura-coverage.xml", coverageOutput.Bytes(), 0666)
err = utils.FileWrite("cobertura-coverage.xml", coverageOutput.Bytes(), 0o666)
if err != nil {
return fmt.Errorf("failed to create cobertura coverage file: %w", err)
}
Expand Down Expand Up @@ -448,7 +444,7 @@ func runGolangciLint(utils golangBuildUtils, golangciLintDir string, lintSetting

log.Entry().Infof("lint report: \n" + outputBuffer.String())
log.Entry().Infof("writing lint report to %s", lintSettings["reportOutputPath"])
err = utils.FileWrite(lintSettings["reportOutputPath"], outputBuffer.Bytes(), 0644)
err = utils.FileWrite(lintSettings["reportOutputPath"], outputBuffer.Bytes(), 0o644)
if err != nil {
return fmt.Errorf("writing golangci-lint report failed: %w", err)
}
Expand Down Expand Up @@ -522,8 +518,18 @@ func runGolangBuildPerArchitecture(config *golangBuildOptions, goModFile *modfil
return binaryNames, nil
}

func runBOMCreation(utils golangBuildUtils, outputFilename string) error {
if err := utils.RunExecutable("cyclonedx-gomod", "mod", "-licenses", fmt.Sprintf("-verbose=%t", GeneralConfig.Verbose), "-test", "-output", outputFilename, "-output-version", "1.4"); err != nil {
func runBOMCreation(config *golangBuildOptions, utils golangBuildUtils, outputFilename string) error {
params := []string{}
// differentiate creation of SBOM for app only "app" vs. all packages "mod"
// see https://github.com/CycloneDX/cyclonedx-gomod?tab=readme-ov-file#subcommands
if len(config.CreateBOMMainPath) > 0 {
params = append(params, "app", fmt.Sprintf("-main=%v", config.CreateBOMMainPath))
} else {
params = append(params, "mod")
}
params = append(params, "-licenses", fmt.Sprintf("-verbose=%t", GeneralConfig.Verbose), "-output", outputFilename, "-output-version", "1.4")

if err := utils.RunExecutable("cyclonedx-gomod", params...); err != nil {
return fmt.Errorf("BOM creation failed: %w", err)
}
return nil
Expand Down
13 changes: 12 additions & 1 deletion cmd/golangBuild_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 25 additions & 5 deletions cmd/golangBuild_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,28 @@ go 1.17`
assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
assert.Equal(t, []string{"install", "github.com/CycloneDX/cyclonedx-gomod/cmd/[email protected]"}, utils.ExecMockRunner.Calls[0].Params)
assert.Equal(t, "cyclonedx-gomod", utils.ExecMockRunner.Calls[1].Exec)
assert.Equal(t, []string{"mod", "-licenses", "-verbose=false", "-test", "-output", "bom-golang.xml", "-output-version", "1.4"}, utils.ExecMockRunner.Calls[1].Params)
assert.Equal(t, []string{"mod", "-licenses", "-verbose=false", "-output", "bom-golang.xml", "-output-version", "1.4"}, utils.ExecMockRunner.Calls[1].Params)
assert.Equal(t, "go", utils.ExecMockRunner.Calls[2].Exec)
assert.Equal(t, []string{"build", "-trimpath"}, utils.ExecMockRunner.Calls[2].Params)
})

t.Run("success - create BOM - app only", func(t *testing.T) {
config := golangBuildOptions{
CreateBOM: true,
CreateBOMMainPath: ".",
TargetArchitectures: []string{"linux,amd64"},
}
utils := newGolangBuildTestsUtils()
utils.FilesMock.AddFile("go.mod", []byte(modTestFile))
telemetryData := telemetry.CustomData{}

err := runGolangBuild(&config, &telemetryData, utils, &cpe)
assert.NoError(t, err)
assert.Equal(t, 3, len(utils.ExecMockRunner.Calls))
assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
assert.Equal(t, []string{"install", "github.com/CycloneDX/cyclonedx-gomod/cmd/[email protected]"}, utils.ExecMockRunner.Calls[0].Params)
assert.Equal(t, "cyclonedx-gomod", utils.ExecMockRunner.Calls[1].Exec)
assert.Equal(t, []string{"app", "-main=.", "-licenses", "-verbose=false", "-output", "bom-golang.xml", "-output-version", "1.4"}, utils.ExecMockRunner.Calls[1].Params)
assert.Equal(t, "go", utils.ExecMockRunner.Calls[2].Exec)
assert.Equal(t, []string{"build", "-trimpath"}, utils.ExecMockRunner.Calls[2].Params)
})
Expand Down Expand Up @@ -480,7 +501,7 @@ go 1.17`
}
GeneralConfig.Verbose = false
utils := newGolangBuildTestsUtils()
utils.ShouldFailOnCommand = map[string]error{"cyclonedx-gomod mod -licenses -verbose=false -test -output bom-golang.xml -output-version 1.4": fmt.Errorf("BOM creation failure")}
utils.ShouldFailOnCommand = map[string]error{"cyclonedx-gomod mod -licenses -verbose=false -output bom-golang.xml -output-version 1.4": fmt.Errorf("BOM creation failure")}
telemetryData := telemetry.CustomData{}

err := runGolangBuild(&config, &telemetryData, utils, &cpe)
Expand Down Expand Up @@ -707,10 +728,10 @@ func TestPrepareLdflags(t *testing.T) {
t.Parallel()
dir := t.TempDir()

err := os.Mkdir(filepath.Join(dir, "commonPipelineEnvironment"), 0777)
err := os.Mkdir(filepath.Join(dir, "commonPipelineEnvironment"), 0o777)
assert.NoError(t, err, "Error when creating folder structure")

err = os.WriteFile(filepath.Join(dir, "commonPipelineEnvironment", "artifactVersion"), []byte("1.2.3"), 0666)
err = os.WriteFile(filepath.Join(dir, "commonPipelineEnvironment", "artifactVersion"), []byte("1.2.3"), 0o666)
assert.NoError(t, err, "Error when creating cpe file")

t.Run("success - default", func(t *testing.T) {
Expand Down Expand Up @@ -869,7 +890,6 @@ func TestRunGolangBuildPerArchitecture(t *testing.T) {
_, err := runGolangBuildPerArchitecture(&config, &goModFile, utils, ldflags, architecture)
assert.EqualError(t, err, "failed to run build for linux.amd64: execution error")
})

}

func TestPrepareGolangEnvironment(t *testing.T) {
Expand Down
6 changes: 3 additions & 3 deletions integration/integration_golang_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func TestGolangIntegrationBuildProject1(t *testing.T) {
"info golangBuild - DONE 8 tests",
"info golangBuild - running command: go tool cover -html cover.out -o coverage.html",
"info golangBuild - running command: gotestsum --junitfile TEST-integration.xml --jsonfile integration-report.out -- -tags=integration ./...",
"info golangBuild - running command: cyclonedx-gomod mod -licenses -verbose=false -test -output bom-golang.xml",
"info golangBuild - running command: cyclonedx-gomod mod -licenses -verbose=false -output bom-golang.xml",
"info golangBuild - running command: go build -trimpath -o golang-app-linux.amd64 cmd/server/server.go",
"info golangBuild - SUCCESS",
)
Expand Down Expand Up @@ -69,7 +69,7 @@ func TestGolangIntegrationBuildProject1MultiPackage(t *testing.T) {
"info golangBuild - DONE 8 tests",
"info golangBuild - running command: go tool cover -html cover.out -o coverage.html",
"info golangBuild - running command: gotestsum --junitfile TEST-integration.xml --jsonfile integration-report.out -- -tags=integration ./...",
"info golangBuild - running command: cyclonedx-gomod mod -licenses -verbose=false -test -output bom-golang.xml",
"info golangBuild - running command: cyclonedx-gomod mod -licenses -verbose=false -output bom-golang.xml",
"info golangBuild - running command: go build -trimpath -o golang-app-linux-amd64/ github.com/example/golang-app/cmd/server github.com/example/golang-app/cmd/helper",
"info golangBuild - SUCCESS",
)
Expand Down Expand Up @@ -106,7 +106,7 @@ func TestGolangIntegrationBuildProject2(t *testing.T) {
"info golangBuild - running command: gotestsum --junitfile TEST-go.xml --jsonfile unit-report.out -- -coverprofile=cover.out -tags=unit ./...",
"info golangBuild - running command: go tool cover -html cover.out -o coverage.html",
"info golangBuild - running command: gotestsum --junitfile TEST-integration.xml --jsonfile integration-report.out -- -tags=integration ./...",
"info golangBuild - running command: cyclonedx-gomod mod -licenses -verbose=false -test -output bom-golang.xml",
"info golangBuild - running command: cyclonedx-gomod mod -licenses -verbose=false -output bom-golang.xml",
)

container.assertHasOutput(t,
Expand Down
10 changes: 9 additions & 1 deletion resources/metadata/golangBuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,15 @@ spec:
default: html
- name: createBOM
type: bool
description: Creates the bill of materials (BOM) using CycloneDX plugin. It requires Go 1.17 or newer.
description: Creates the bill of materials (BOM) using CycloneDX plugin. By default it will create the SBOM for all packages contained in the repository unless [createBOMMainPath](#createbommainpath) is specified. It requires Go 1.17 or newer.
scope:
- GENERAL
- STEPS
- STAGES
- PARAMETERS
- name: createBOMMainPath
type: string
description: In case this parameter is defined, the SBOM will only be created for the application and not for all packages contained. The parameter specifies the path to the application's main package, relative to MODULE_PATH.
scope:
- GENERAL
- STEPS
Expand Down
Loading