You've already forked sap-jenkins-library
mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-07-15 01:34:38 +02:00
feat: allow uploading multiple boms (#3900)
* WIP: Adapt bom names * + WIP: Adapt bom filenames * Upgrade cyclonedx gradle plugin and use cyclonedxBom config parameters * Fix unit tests - use correct name in bom creation * Fix pythonBuild bom name * introduce and use npmBomFilename const * Introduce and use mvnBomFilename const * Introduce and use gradleBomFilename const * Use build-tool names for bom suffix * + Adapt tests (build tool suffix) * Use BOM schema version 1.2 in gradleExecuteBuild * Pin version of cyclonedx-maven-plugin to 2.7.1 * Adapt generated files * Fix integration tests * Fix integration tests * Fix gradle build integration tests Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
This commit is contained in:
@ -34,7 +34,7 @@ const (
|
||||
golangCoberturaPackage = "github.com/boumenot/gocover-cobertura@latest"
|
||||
golangTestsumPackage = "gotest.tools/gotestsum@latest"
|
||||
golangCycloneDXPackage = "github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@latest"
|
||||
sbomFilename = "bom.xml"
|
||||
sbomFilename = "bom-golang.xml"
|
||||
golangciLintURL = "https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh"
|
||||
golangciLintVersion = "v1.46.2"
|
||||
)
|
||||
|
@ -88,7 +88,7 @@ func (p *golangBuildReports) persist(stepConfig golangBuildOptions, gcpJsonKeyFi
|
||||
}
|
||||
log.Entry().Info("Uploading reports to Google Cloud Storage...")
|
||||
content := []gcs.ReportOutputParam{
|
||||
{FilePattern: "**/bom.xml", ParamRef: "", StepResultType: "sbom"},
|
||||
{FilePattern: "**/bom-golang.xml", ParamRef: "", StepResultType: "sbom"},
|
||||
{FilePattern: "**/TEST-*.xml", ParamRef: "", StepResultType: "junit"},
|
||||
{FilePattern: "**/cobertura-coverage.xml", ParamRef: "", StepResultType: "cobertura-coverage"},
|
||||
}
|
||||
@ -550,7 +550,7 @@ func golangBuildMetadata() config.StepData {
|
||||
Name: "reports",
|
||||
Type: "reports",
|
||||
Parameters: []map[string]interface{}{
|
||||
{"filePattern": "**/bom.xml", "type": "sbom"},
|
||||
{"filePattern": "**/bom-golang.xml", "type": "sbom"},
|
||||
{"filePattern": "**/TEST-*.xml", "type": "junit"},
|
||||
{"filePattern": "**/cobertura-coverage.xml", "type": "cobertura-coverage"},
|
||||
},
|
||||
|
@ -250,7 +250,7 @@ go 1.17`
|
||||
assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
|
||||
assert.Equal(t, []string{"install", "github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@latest"}, utils.ExecMockRunner.Calls[0].Params)
|
||||
assert.Equal(t, "cyclonedx-gomod", utils.ExecMockRunner.Calls[1].Exec)
|
||||
assert.Equal(t, []string{"mod", "-licenses", "-test", "-output", "bom.xml"}, utils.ExecMockRunner.Calls[1].Params)
|
||||
assert.Equal(t, []string{"mod", "-licenses", "-test", "-output", "bom-golang.xml"}, 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)
|
||||
})
|
||||
@ -447,7 +447,7 @@ go 1.17`
|
||||
TargetArchitectures: []string{"linux,amd64"},
|
||||
}
|
||||
utils := newGolangBuildTestsUtils()
|
||||
utils.ShouldFailOnCommand = map[string]error{"cyclonedx-gomod mod -licenses -test -output bom.xml": fmt.Errorf("BOM creation failure")}
|
||||
utils.ShouldFailOnCommand = map[string]error{"cyclonedx-gomod mod -licenses -test -output bom-golang.xml": fmt.Errorf("BOM creation failure")}
|
||||
telemetryData := telemetry.CustomData{}
|
||||
|
||||
err := runGolangBuild(&config, &telemetryData, utils, &cpe)
|
||||
|
@ -12,6 +12,10 @@ import (
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
)
|
||||
|
||||
const (
|
||||
gradleBomFilename = "bom-gradle"
|
||||
)
|
||||
|
||||
var (
|
||||
bomGradleTaskName = "cyclonedxBom"
|
||||
publishTaskName = "publish"
|
||||
@ -67,7 +71,7 @@ initscript {
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath "com.cyclonedx:cyclonedx-gradle-plugin:1.5.0"
|
||||
classpath "org.cyclonedx:cyclonedx-gradle-plugin:1.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,6 +79,12 @@ rootProject {
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'maven'
|
||||
apply plugin: org.cyclonedx.gradle.CycloneDxPlugin
|
||||
|
||||
cyclonedxBom {
|
||||
outputName = "` + gradleBomFilename + `"
|
||||
outputFormat = "xml"
|
||||
schemaVersion = "1.2"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
|
@ -43,7 +43,7 @@ func (p *gradleExecuteBuildReports) persist(stepConfig gradleExecuteBuildOptions
|
||||
}
|
||||
log.Entry().Info("Uploading reports to Google Cloud Storage...")
|
||||
content := []gcs.ReportOutputParam{
|
||||
{FilePattern: "**/bom.xml", ParamRef: "", StepResultType: "sbom"},
|
||||
{FilePattern: "**/bom-gradle.xml", ParamRef: "", StepResultType: "sbom"},
|
||||
}
|
||||
envVars := []gcs.EnvVar{
|
||||
{Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: gcpJsonKeyFilePath, Modified: false},
|
||||
@ -331,7 +331,7 @@ func gradleExecuteBuildMetadata() config.StepData {
|
||||
Name: "reports",
|
||||
Type: "reports",
|
||||
Parameters: []map[string]interface{}{
|
||||
{"filePattern": "**/bom.xml", "type": "sbom"},
|
||||
{"filePattern": "**/bom-gradle.xml", "type": "sbom"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -18,6 +18,10 @@ import (
|
||||
piperhttp "github.com/SAP/jenkins-library/pkg/http"
|
||||
)
|
||||
|
||||
const (
|
||||
mvnBomFilename = "bom-maven"
|
||||
)
|
||||
|
||||
func mavenBuild(config mavenBuildOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *mavenBuildCommonPipelineEnvironment) {
|
||||
utils := maven.NewUtilsBundle()
|
||||
|
||||
@ -49,7 +53,7 @@ func runMavenBuild(config *mavenBuildOptions, telemetryData *telemetry.CustomDat
|
||||
}
|
||||
|
||||
if config.CreateBOM {
|
||||
goals = append(goals, "org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom")
|
||||
goals = append(goals, "org.cyclonedx:cyclonedx-maven-plugin:2.7.1:makeAggregateBom")
|
||||
createBOMConfig := []string{
|
||||
"-DschemaVersion=1.2",
|
||||
"-DincludeBomSerialNumber=true",
|
||||
@ -60,6 +64,7 @@ func runMavenBuild(config *mavenBuildOptions, telemetryData *telemetry.CustomDat
|
||||
"-DincludeTestScope=false",
|
||||
"-DincludeLicenseText=false",
|
||||
"-DoutputFormat=xml",
|
||||
"-DoutputName=" + mvnBomFilename,
|
||||
}
|
||||
defines = append(defines, createBOMConfig...)
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ func (p *mavenBuildReports) persist(stepConfig mavenBuildOptions, gcpJsonKeyFile
|
||||
}
|
||||
log.Entry().Info("Uploading reports to Google Cloud Storage...")
|
||||
content := []gcs.ReportOutputParam{
|
||||
{FilePattern: "**/bom.xml", ParamRef: "", StepResultType: "sbom"},
|
||||
{FilePattern: "**/bom-maven.xml", ParamRef: "", StepResultType: "sbom"},
|
||||
{FilePattern: "**/TEST-*.xml", ParamRef: "", StepResultType: "junit"},
|
||||
{FilePattern: "**/jacoco.xml", ParamRef: "", StepResultType: "jacoco-coverage"},
|
||||
}
|
||||
@ -505,7 +505,7 @@ func mavenBuildMetadata() config.StepData {
|
||||
Name: "reports",
|
||||
Type: "reports",
|
||||
Parameters: []map[string]interface{}{
|
||||
{"filePattern": "**/bom.xml", "type": "sbom"},
|
||||
{"filePattern": "**/bom-maven.xml", "type": "sbom"},
|
||||
{"filePattern": "**/TEST-*.xml", "type": "junit"},
|
||||
{"filePattern": "**/jacoco.xml", "type": "jacoco-coverage"},
|
||||
},
|
||||
|
@ -68,7 +68,7 @@ func TestMavenBuild(t *testing.T) {
|
||||
err := runMavenBuild(&config, nil, &mockedUtils, &cpe)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Contains(t, mockedUtils.Calls[0].Params, "org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom")
|
||||
assert.Contains(t, mockedUtils.Calls[0].Params, "org.cyclonedx:cyclonedx-maven-plugin:2.7.1:makeAggregateBom")
|
||||
assert.Contains(t, mockedUtils.Calls[0].Params, "-DschemaVersion=1.2")
|
||||
assert.Contains(t, mockedUtils.Calls[0].Params, "-DincludeBomSerialNumber=true")
|
||||
assert.Contains(t, mockedUtils.Calls[0].Params, "-DincludeCompileScope=true")
|
||||
@ -78,6 +78,7 @@ func TestMavenBuild(t *testing.T) {
|
||||
assert.Contains(t, mockedUtils.Calls[0].Params, "-DincludeTestScope=false")
|
||||
assert.Contains(t, mockedUtils.Calls[0].Params, "-DincludeLicenseText=false")
|
||||
assert.Contains(t, mockedUtils.Calls[0].Params, "-DoutputFormat=xml")
|
||||
assert.Contains(t, mockedUtils.Calls[0].Params, "-DoutputName=bom-maven")
|
||||
})
|
||||
|
||||
t.Run("mavenBuild include install and deploy when publish is true", func(t *testing.T) {
|
||||
|
@ -76,7 +76,7 @@ func (p *npmExecuteScriptsReports) persist(stepConfig npmExecuteScriptsOptions,
|
||||
}
|
||||
log.Entry().Info("Uploading reports to Google Cloud Storage...")
|
||||
content := []gcs.ReportOutputParam{
|
||||
{FilePattern: "**/bom.xml", ParamRef: "", StepResultType: "sbom"},
|
||||
{FilePattern: "**/bom-npm.xml", ParamRef: "", StepResultType: "sbom"},
|
||||
{FilePattern: "**/TEST-*.xml", ParamRef: "", StepResultType: "junit"},
|
||||
{FilePattern: "**/cobertura-coverage.xml", ParamRef: "", StepResultType: "cobertura-coverage"},
|
||||
{FilePattern: "**/e2e/*.json", ParamRef: "", StepResultType: "cucumber"},
|
||||
@ -429,7 +429,7 @@ func npmExecuteScriptsMetadata() config.StepData {
|
||||
Name: "reports",
|
||||
Type: "reports",
|
||||
Parameters: []map[string]interface{}{
|
||||
{"filePattern": "**/bom.xml", "type": "sbom"},
|
||||
{"filePattern": "**/bom-npm.xml", "type": "sbom"},
|
||||
{"filePattern": "**/TEST-*.xml", "type": "junit"},
|
||||
{"filePattern": "**/cobertura-coverage.xml", "type": "cobertura-coverage"},
|
||||
{"filePattern": "**/e2e/*.json", "type": "cucumber"},
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
PyBomFilename = "bom.xml"
|
||||
PyBomFilename = "bom-pip.xml"
|
||||
stepName = "pythonBuild"
|
||||
)
|
||||
|
||||
|
@ -99,6 +99,6 @@ func TestRunPythonBuild(t *testing.T) {
|
||||
assert.Equal(t, filepath.Join("dummy", "bin", "pip"), utils.ExecMockRunner.Calls[3].Exec)
|
||||
assert.Equal(t, []string{"install", "--upgrade", "cyclonedx-bom"}, utils.ExecMockRunner.Calls[3].Params)
|
||||
assert.Equal(t, filepath.Join("dummy", "bin", "cyclonedx-bom"), utils.ExecMockRunner.Calls[4].Exec)
|
||||
assert.Equal(t, []string{"--e", "--output", "bom.xml"}, utils.ExecMockRunner.Calls[4].Params)
|
||||
assert.Equal(t, []string{"--e", "--output", "bom-pip.xml"}, utils.ExecMockRunner.Calls[4].Params)
|
||||
})
|
||||
}
|
||||
|
@ -30,13 +30,13 @@ func TestGolangBuild_Project1(t *testing.T) {
|
||||
container.assertHasOutput(t, "info golangBuild - DONE 8 tests")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: go tool cover -html cover.out -o coverage.html")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: gotestsum --junitfile TEST-integration.xml -- -tags=integration ./...")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: cyclonedx-gomod mod -licenses -test -output bom.xml")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: cyclonedx-gomod mod -licenses -test -output bom-golang.xml")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: go build -trimpath -o golang-app-linux.amd64 cmd/server/server.go")
|
||||
container.assertHasOutput(t, "info golangBuild - SUCCESS")
|
||||
|
||||
container.assertHasFile(t, "/project/TEST-go.xml")
|
||||
container.assertHasFile(t, "/project/TEST-integration.xml")
|
||||
container.assertHasFile(t, "/project/bom.xml")
|
||||
container.assertHasFile(t, "/project/bom-golang.xml")
|
||||
container.assertHasFile(t, "/project/cover.out")
|
||||
container.assertHasFile(t, "/project/coverage.html")
|
||||
container.assertHasFile(t, "/project/golang-app-linux.amd64")
|
||||
@ -60,13 +60,13 @@ func TestGolangBuild_Project1_Multipackage(t *testing.T) {
|
||||
container.assertHasOutput(t, "info golangBuild - DONE 8 tests")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: go tool cover -html cover.out -o coverage.html")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: gotestsum --junitfile TEST-integration.xml -- -tags=integration ./...")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: cyclonedx-gomod mod -licenses -test -output bom.xml")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: cyclonedx-gomod mod -licenses -test -output bom-golang.xml")
|
||||
container.assertHasOutput(t, "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")
|
||||
container.assertHasOutput(t, "info golangBuild - SUCCESS")
|
||||
|
||||
container.assertHasFile(t, "/project/TEST-go.xml")
|
||||
container.assertHasFile(t, "/project/TEST-integration.xml")
|
||||
container.assertHasFile(t, "/project/bom.xml")
|
||||
container.assertHasFile(t, "/project/bom-golang.xml")
|
||||
container.assertHasFile(t, "/project/cover.out")
|
||||
container.assertHasFile(t, "/project/coverage.html")
|
||||
container.assertHasFile(t, "/project/golang-app-linux-amd64/server")
|
||||
@ -91,7 +91,7 @@ func TestGolangBuild_Project2(t *testing.T) {
|
||||
container.assertHasNoOutput(t, "info golangBuild - running command: gotestsum --junitfile TEST-go.xml -- -coverprofile=cover.out ./...")
|
||||
container.assertHasNoOutput(t, "info golangBuild - running command: go tool cover -html cover.out -o coverage.html")
|
||||
container.assertHasNoOutput(t, "info golangBuild - running command: gotestsum --junitfile TEST-integration.xml -- -tags=integration ./...")
|
||||
container.assertHasNoOutput(t, "info golangBuild - running command: cyclonedx-gomod mod -licenses -test -output bom.xml")
|
||||
container.assertHasNoOutput(t, "info golangBuild - running command: cyclonedx-gomod mod -licenses -test -output bom-golang.xml")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: go build -trimpath -o golang-app-linux.amd64")
|
||||
container.assertHasOutput(t, "info golangBuild - SUCCESS")
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ ls -l ./build/reports/ >files-list.txt 2>&1
|
||||
t.Fatal("Could not read files-list.txt.", err)
|
||||
}
|
||||
output = string(content)
|
||||
assert.Contains(t, output, "bom.xml")
|
||||
assert.Contains(t, output, "bom-gradle.xml")
|
||||
}
|
||||
|
||||
func TestGradleExecuteBuild_JavaProjectWithBomPlugin(t *testing.T) {
|
||||
@ -158,5 +158,5 @@ ls -l ./build/reports/ >files-list.txt 2>&1
|
||||
t.Fatal("Could not read files-list.txt.", err)
|
||||
}
|
||||
output = string(content)
|
||||
assert.Contains(t, output, "bom.xml")
|
||||
assert.Contains(t, output, "bom-gradle.xml")
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ func TestBuildPythonProject(t *testing.T) {
|
||||
|
||||
assert.Contains(t, output, "info pythonBuild - running command: python setup.py sdist bdist_wheel")
|
||||
assert.Contains(t, output, "info pythonBuild - running command: piperBuild-env/bin/pip install --upgrade cyclonedx-bom")
|
||||
assert.Contains(t, output, "info pythonBuild - running command: piperBuild-env/bin/cyclonedx-bom --e --output bom.xml")
|
||||
assert.Contains(t, output, "info pythonBuild - running command: piperBuild-env/bin/cyclonedx-bom --e --output bom-pip.xml")
|
||||
assert.Contains(t, output, "info pythonBuild - SUCCESS")
|
||||
|
||||
//workaround to use test script util it is possible to set workdir for Exec call
|
||||
@ -82,7 +82,7 @@ func TestBuildPythonProject(t *testing.T) {
|
||||
t.Fatal("Could not read files-list.txt.", err)
|
||||
}
|
||||
output = string(content)
|
||||
assert.Contains(t, output, "bom.xml")
|
||||
assert.Contains(t, output, "bom-pip.xml")
|
||||
assert.Contains(t, output, "example-pkg-0.0.1.tar.gz")
|
||||
assert.Contains(t, output, "example_pkg-0.0.1-py3-none-any.whl")
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ plugins {
|
||||
id 'org.springframework.boot' version '2.6.5-SNAPSHOT'
|
||||
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
|
||||
id 'java'
|
||||
id "org.cyclonedx.bom" version "1.5.0"
|
||||
id "org.cyclonedx.bom" version "1.7.0"
|
||||
}
|
||||
|
||||
group = 'com.example'
|
||||
@ -25,3 +25,9 @@ dependencies {
|
||||
tasks.named('test') {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
cyclonedxBom {
|
||||
outputName = "bom-gradle"
|
||||
outputFormat = "xml"
|
||||
schemaVersion = "1.2"
|
||||
}
|
||||
|
@ -13,6 +13,10 @@ import (
|
||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
)
|
||||
|
||||
const (
|
||||
npmBomFilename = "bom-npm.xml"
|
||||
)
|
||||
|
||||
// Execute struct holds utils to enable mocking and common parameters
|
||||
type Execute struct {
|
||||
Utils Utils
|
||||
@ -353,13 +357,14 @@ func (exec *Execute) CreateBOM(packageJSONFiles []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(packageJSONFiles) > 0 {
|
||||
for _, packageJSONFile := range packageJSONFiles {
|
||||
path := filepath.Dir(packageJSONFile)
|
||||
params := []string{
|
||||
"cyclonedx-bom",
|
||||
path,
|
||||
"--output", filepath.Join(path, "bom.xml"),
|
||||
"--output", filepath.Join(path, npmBomFilename),
|
||||
}
|
||||
err := execRunner.RunExecutable("npx", params...)
|
||||
if err != nil {
|
||||
|
@ -359,9 +359,9 @@ func TestNpm(t *testing.T) {
|
||||
if assert.Equal(t, 3, len(utils.execRunner.Calls)) {
|
||||
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"install", "@cyclonedx/bom", "--no-save"}}, utils.execRunner.Calls[0])
|
||||
assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{"cyclonedx-bom", ".",
|
||||
"--output", "bom.xml"}}, utils.execRunner.Calls[1])
|
||||
"--output", "bom-npm.xml"}}, utils.execRunner.Calls[1])
|
||||
assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{"cyclonedx-bom", "src",
|
||||
"--output", filepath.Join("src", "bom.xml")}}, utils.execRunner.Calls[2])
|
||||
"--output", filepath.Join("src", "bom-npm.xml")}}, utils.execRunner.Calls[2])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -252,7 +252,7 @@ spec:
|
||||
- name: reports
|
||||
type: reports
|
||||
params:
|
||||
- filePattern: "**/bom.xml"
|
||||
- filePattern: "**/bom-golang.xml"
|
||||
type: sbom
|
||||
- filePattern: "**/TEST-*.xml"
|
||||
type: junit
|
||||
|
@ -120,7 +120,7 @@ spec:
|
||||
- name: reports
|
||||
type: reports
|
||||
params:
|
||||
- filePattern: "**/bom.xml"
|
||||
- filePattern: "**/bom-gradle.xml"
|
||||
type: sbom
|
||||
containers:
|
||||
- name: gradle
|
||||
|
@ -239,7 +239,7 @@ spec:
|
||||
- name: reports
|
||||
type: reports
|
||||
params:
|
||||
- filePattern: "**/bom.xml"
|
||||
- filePattern: "**/bom-maven.xml"
|
||||
type: sbom
|
||||
- filePattern: "**/TEST-*.xml"
|
||||
type: junit
|
||||
|
@ -164,7 +164,7 @@ spec:
|
||||
- name: reports
|
||||
type: reports
|
||||
params:
|
||||
- filePattern: "**/bom.xml"
|
||||
- filePattern: "**/bom-npm.xml"
|
||||
type: sbom
|
||||
- filePattern: "**/TEST-*.xml"
|
||||
type: junit
|
||||
|
Reference in New Issue
Block a user