Skip to content

Commit

Permalink
Include purl info in the event (#5092)
Browse files Browse the repository at this point in the history
  • Loading branch information
D074360 authored Oct 2, 2024
1 parent 2175d38 commit 5230c3d
Show file tree
Hide file tree
Showing 7 changed files with 378 additions and 2 deletions.
40 changes: 38 additions & 2 deletions cmd/mavenBuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ const (

func mavenBuild(config mavenBuildOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *mavenBuildCommonPipelineEnvironment) {
utils := maven.NewUtilsBundle()

// enables url-log.json creation
cmd := reflect.ValueOf(utils).Elem().FieldByName("Command")
if cmd.IsValid() {
Expand Down Expand Up @@ -62,7 +61,7 @@ func runMavenBuild(config *mavenBuildOptions, telemetryData *telemetry.CustomDat
}

if config.CreateBOM {
goals = append(goals, "org.cyclonedx:cyclonedx-maven-plugin:2.7.8:makeAggregateBom")
goals = append(goals, "org.cyclonedx:cyclonedx-maven-plugin:2.7.8:makeBom", "org.cyclonedx:cyclonedx-maven-plugin:2.7.8:makeAggregateBom")
createBOMConfig := []string{
"-DschemaVersion=1.4",
"-DincludeBomSerialNumber=true",
Expand Down Expand Up @@ -183,6 +182,7 @@ func runMavenBuild(config *mavenBuildOptions, telemetryData *telemetry.CustomDat
} else {
coordinate.BuildPath = filepath.Dir(match)
coordinate.URL = config.AltDeploymentRepositoryURL
coordinate.PURL = getPurlForThePomAndDeleteIndividualBom(match)
buildCoordinates = append(buildCoordinates, coordinate)
}
}
Expand All @@ -209,6 +209,42 @@ func runMavenBuild(config *mavenBuildOptions, telemetryData *telemetry.CustomDat
return err
}

func getPurlForThePomAndDeleteIndividualBom(pomFilePath string) string {
bomPath := filepath.Join(filepath.Dir(pomFilePath) + "/target/" + mvnBomFilename + ".xml")
exists, _ := piperutils.FileExists(bomPath)
if !exists {
log.Entry().Debugf("bom file doesn't exist and hence no pURL info: %v", bomPath)
return ""
}
bom, err := piperutils.GetBom(bomPath)
if err != nil {
log.Entry().Warnf("failed to get bom file %s: %v", bomPath, err)
return ""
}

log.Entry().Debugf("Found purl: %s for the bomPath: %s", bom.Metadata.Component.Purl, bomPath)
purl := bom.Metadata.Component.Purl

// Check if the BOM is an aggregated BOM
if !isAggregatedBOM(bom) {
// Delete the individual BOM file
err = os.Remove(bomPath)
if err != nil {
log.Entry().Warnf("failed to delete bom file %s: %v", bomPath, err)
}
}
return purl
}

func isAggregatedBOM(bom piperutils.Bom) bool {
for _, property := range bom.Metadata.Properties {
if property.Name == "maven.goal" && property.Value == "makeAggregateBom" {
return true
}
}
return false
}

func createOrUpdateProjectSettingsXML(projectSettingsFile string, altDeploymentRepositoryID string, altDeploymentRepositoryUser string, altDeploymentRepositoryPassword string, utils maven.Utils) (string, error) {
if len(projectSettingsFile) > 0 {
projectSettingsFilePath, err := maven.UpdateProjectSettingsXML(projectSettingsFile, altDeploymentRepositoryID, altDeploymentRepositoryUser, altDeploymentRepositoryPassword, utils)
Expand Down
105 changes: 105 additions & 0 deletions cmd/mavenBuild_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
package cmd

import (
"os"
"path/filepath"
"testing"

"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -157,3 +160,105 @@ func TestMavenBuild(t *testing.T) {
})

}

func TestIsAggregatedBOM(t *testing.T) {
t.Run("is aggregated BOM", func(t *testing.T) {
bom := piperutils.Bom{
Metadata: piperutils.Metadata{
Properties: []piperutils.BomProperty{
{Name: "maven.goal", Value: "makeAggregateBom"},
},
},
}
assert.True(t, isAggregatedBOM(bom))
})

t.Run("is not aggregated BOM", func(t *testing.T) {
bom := piperutils.Bom{
Metadata: piperutils.Metadata{
Properties: []piperutils.BomProperty{
{Name: "some.property", Value: "someValue"},
},
},
}
assert.False(t, isAggregatedBOM(bom))
})
}

func createTempFile(t *testing.T, dir string, filename string, content string) string {
filePath := filepath.Join(dir, filename)
err := os.WriteFile(filePath, []byte(content), 0666)
if err != nil {
t.Fatalf("Failed to create temp file: %s", err)
}
return filePath
}

func TestGetPurlForThePomAndDeleteIndividualBom(t *testing.T) {
t.Run("valid BOM file, non-aggregated", func(t *testing.T) {
tempDir, err := piperutils.Files{}.TempDir("", "test")
if err != nil {
t.Fatalf("Failed to create temp directory: %s", err)
}

bomContent := `<bom>
<metadata>
<component>
<purl>pkg:maven/com.example/[email protected]</purl>
</component>
<properties>
<property name="name1" value="value1" />
</properties>
</metadata>
</bom>`
pomFilePath := createTempFile(t, tempDir, "pom.xml", "")
bomDir := filepath.Join(tempDir, "target")
if err := os.MkdirAll(bomDir, 0777); err != nil {
t.Fatalf("Failed to create temp directory: %s", err)
}
bomFilePath := createTempFile(t, bomDir, mvnBomFilename+".xml", bomContent)
defer os.Remove(bomFilePath)

purl := getPurlForThePomAndDeleteIndividualBom(pomFilePath)
assert.Equal(t, "pkg:maven/com.example/[email protected]", purl)
_, err = os.Stat(bomFilePath)
assert.True(t, os.IsNotExist(err))
})

t.Run("valid BOM file, aggregated BOM", func(t *testing.T) {
tempDir, err := piperutils.Files{}.TempDir("", "test")
if err != nil {
t.Fatalf("Failed to create temp directory: %s", err)
}

bomContent := `<bom>
<metadata>
<component>
<purl>pkg:maven/com.example/[email protected]</purl>
</component>
<properties>
<property name="maven.goal" value="makeAggregateBom" />
</properties>
</metadata>
</bom>`
pomFilePath := createTempFile(t, tempDir, "pom.xml", "")
bomDir := filepath.Join(tempDir, "target")
if err := os.MkdirAll(bomDir, 0777); err != nil {
t.Fatalf("Failed to create temp directory: %s", err)
}
bomFilePath := createTempFile(t, bomDir, mvnBomFilename+".xml", bomContent)

purl := getPurlForThePomAndDeleteIndividualBom(pomFilePath)
assert.Equal(t, "pkg:maven/com.example/[email protected]", purl)
_, err = os.Stat(bomFilePath)
assert.False(t, os.IsNotExist(err)) // File should not be deleted
})

t.Run("BOM file does not exist", func(t *testing.T) {
tempDir := t.TempDir()
pomFilePath := createTempFile(t, tempDir, "pom.xml", "") // Create a temp pom file

purl := getPurlForThePomAndDeleteIndividualBom(pomFilePath)
assert.Equal(t, "", purl)
})
}
16 changes: 16 additions & 0 deletions pkg/npm/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p
coordinate.BuildPath = filepath.Dir(packageJSON)
coordinate.URL = registry
coordinate.Packaging = "tgz"
coordinate.PURL = getPurl(packageJSON)

*buildCoordinates = append(*buildCoordinates, coordinate)
}
Expand All @@ -225,6 +226,21 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p
return nil
}

func getPurl(packageJSON string) string {
expectedBomFilePath := filepath.Join(filepath.Dir(packageJSON) + "/" + npmBomFilename)
exists, _ := CredentialUtils.FileExists(expectedBomFilePath)
if !exists {
log.Entry().Debugf("bom file doesn't exist and hence no pURL info: %v", expectedBomFilePath)
return ""
}
bom, err := CredentialUtils.GetBom(expectedBomFilePath)
if err != nil {
log.Entry().Warnf("unable to get bom metdata : %v", err)
return ""
}
return bom.Metadata.Component.Purl
}

func (exec *Execute) readPackageScope(packageJSON string) (string, error) {
b, err := exec.Utils.FileRead(packageJSON)
if err != nil {
Expand Down
44 changes: 44 additions & 0 deletions pkg/npm/publish_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/SAP/jenkins-library/pkg/versioning"
"github.com/stretchr/testify/assert"
"os"
)

type npmMockUtilsBundleRelativeGlob struct {
Expand Down Expand Up @@ -573,3 +574,46 @@ func TestNpmPublish(t *testing.T) {
})
}
}

func createTempFile(t *testing.T, dir string, filename string, content string) string {
filePath := filepath.Join(dir, filename)
err := os.WriteFile(filePath, []byte(content), 0666)
if err != nil {
t.Fatalf("Failed to create temp file: %s", err)
}
return filePath
}

func TestGetPurl(t *testing.T) {
t.Run("valid BOM file", func(t *testing.T) {
tempDir, err := piperutils.Files{}.TempDir("", "test")
if err != nil {
t.Fatalf("Failed to create temp directory: %s", err)
}

bomContent := `<bom>
<metadata>
<component>
<purl>pkg:npm/com.example/[email protected]</purl>
</component>
<properties>
<property name="name1" value="value1" />
</properties>
</metadata>
</bom>`
packageJsonFilePath := createTempFile(t, tempDir, "package.json", "")
bomFilePath := createTempFile(t, tempDir, npmBomFilename, bomContent)
defer os.Remove(bomFilePath)

purl := getPurl(packageJsonFilePath)
assert.Equal(t, "pkg:npm/com.example/[email protected]", purl)
})

t.Run("BOM file does not exist", func(t *testing.T) {
tempDir := t.TempDir()
packageJsonFilePath := createTempFile(t, tempDir, "pom.xml", "") // Create a temp pom file

purl := getPurl(packageJsonFilePath)
assert.Equal(t, "", purl)
})
}
48 changes: 48 additions & 0 deletions pkg/piperutils/cyclonedxBom.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package piperutils

import (
"encoding/xml"
"github.com/SAP/jenkins-library/pkg/log"
"io"
"os"
)

// To serialize the cyclonedx BOM file
type Bom struct {
Metadata Metadata `xml:"metadata"`
}

type Metadata struct {
Component BomComponent `xml:"component"`
Properties []BomProperty `xml:"properties>property"`
}

type BomProperty struct {
Name string `xml:"name,attr"`
Value string `xml:"value,attr"`
}

type BomComponent struct {
Purl string `xml:"purl"`
}

func GetBom(absoluteBomPath string) (Bom, error) {
xmlFile, err := os.Open(absoluteBomPath)
if err != nil {
log.Entry().Debugf("failed to open bom file %s", absoluteBomPath)
return Bom{}, err
}
defer xmlFile.Close()
byteValue, err := io.ReadAll(xmlFile)
if err != nil {
log.Entry().Debugf("failed to read bom file %s", absoluteBomPath)
return Bom{}, err
}
var bom Bom
err = xml.Unmarshal(byteValue, &bom)
if err != nil {
log.Entry().Debugf("failed to unmarshal bom file %s", absoluteBomPath)
return Bom{}, err
}
return bom, nil
}
Loading

0 comments on commit 5230c3d

Please sign in to comment.