From 2abbf34f5cd8360fe74c4177b214064de161c979 Mon Sep 17 00:00:00 2001 From: Suman Date: Thu, 24 Oct 2024 13:27:37 -0400 Subject: [PATCH 01/14] changes to create concert build manifest to create build sbom in concert format --- .../PackageBuildOutputs.groovy | 78 +++++++++-- .../concertBuildManifestGenerator.groovy | 128 ++++++++++++++++++ .../utilities/sbomGenerator.groovy | 17 ++- 3 files changed, 211 insertions(+), 12 deletions(-) create mode 100644 Pipeline/PackageBuildOutputs/utilities/concertBuildManifestGenerator.groovy diff --git a/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy b/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy index 597140e0..5b60c9e2 100644 --- a/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy +++ b/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy @@ -51,14 +51,23 @@ import com.ibm.jzos.ZFile; * Version 8 - 2024-07 * - Reworked error management and fixed few glitches * + * Version 9 - 2024-10 + * - Added the following + * a) Fields and code to generate concert manifest linking to + * concertBuildManifestGenerator.groovy + * b) Refactoring to generate SBOM details like SerialNumber from this script + * to be passed to sbomGenerator.groovy and concertBuildManifestGenerator.groovy ************************************************************************************/ // start create & publish package @Field Properties props = null def scriptDir = new File(getClass().protectionDomain.codeSource.location.path).parent @Field def wdManifestGeneratorUtilities = loadScript(new File("${scriptDir}/utilities/WaziDeployManifestGenerator.groovy")) +@Field def concertManifestGeneratorUtilities = loadScript(new File("${scriptDir}/utilities/concertBuildManifestGenerator.groovy")) @Field def sbomUtilities @Field def rc = 0 +@Field def sbomSerialNumber +@Field def sbomFileName def startTime = new Date() @@ -91,14 +100,15 @@ Map buildOutputsMap = new HashMap scmInfo = new HashMap() -if (props.generateSBOM && props.generateSBOM.toBoolean()) { - sbomUtilities = loadScript(new File("${scriptDir}/utilities/sbomGenerator.groovy")) - sbomUtilities.initializeSBOM(props.sbomAuthor) -} +// Object to store scm information for Wazi Deploy Application Manifest file +HashMap packageInfo = new HashMap() + // iterate over all build reports to obtain build output props.buildReportOrder.each { buildReportFile -> @@ -119,6 +129,7 @@ props.buildReportOrder.each { buildReportFile -> } if (buildInfo.size() != 0) { tarFileLabel = buildInfo[0].label + buildNumber = buildInfo[0].label } // retrieve the buildResultPropertiesRecord @@ -326,7 +337,9 @@ props.buildReportOrder.each { buildReportFile -> } // generate scmInfo for Wazi Deploy Application Manifest file - if (props.generateWaziDeployAppManifest && props.generateWaziDeployAppManifest.toBoolean()) { + if ((props.generateWaziDeployAppManifest && props.generateWaziDeployAppManifest.toBoolean()) || + (props.generateConcertBuildManifest && props.generateConcertBuildManifest.toBoolean() )) { + if (props.buildReportOrder.size() == 1) { scmInfo.put("type", "git") gitUrl = retrieveBuildResultProperty (buildResultPropertiesRecord, "giturl") @@ -348,13 +361,27 @@ if (rc == 0) { println("** There are no build outputs found in all provided build reports. Exiting.") rc = 0 } else { - + // generate SBOM only if build outputs exist + if (props.generateSBOM && props.generateSBOM.toBoolean()) { + sbomUtilities = loadScript(new File("${scriptDir}/utilities/sbomGenerator.groovy")) + sbomSerialNumber = "url:uuid:" + UUID.randomUUID().toString() + sbomFileName = "${buildNumber}_sbom.json" + sbomUtilities.initializeSBOM(props.sbomAuthor,sbomSerialNumber) + + } // Local variables // Initialize Wazi Deploy Manifest Generator if (props.generateWaziDeployAppManifest && props.generateWaziDeployAppManifest.toBoolean()) { wdManifestGeneratorUtilities.initWaziDeployManifestGenerator(props)// Wazi Deploy Application Manifest wdManifestGeneratorUtilities.setScmInfo(scmInfo) } + + // Initialize Concert Build Manifest Generator + if (props.generateConcertBuildManifest && props.generateConcertBuildManifest.toBoolean()) { + concertManifestGeneratorUtilities.initConcertBuildManifestGenerator(props,buildNumber)// Concert Build Manifest + concertManifestGeneratorUtilities.setScmInfo(scmInfo) + concertManifestGeneratorUtilities.setSBOMInfo(sbomFileName,sbomSerialNumber) + } def String tarFileName = (props.tarFileName) ? props.tarFileName : "${tarFileLabel}.tar" def tarFile = "$props.workDir/${tarFileName}" @@ -456,7 +483,7 @@ if (rc == 0) { } if (props.generateSBOM && props.generateSBOM.toBoolean() && rc == 0) { - sbomUtilities.writeSBOM("$tempLoadDir/sbom.json", props.fileEncoding) + sbomUtilities.writeSBOM("$tempLoadDir/$sbomFileName", props.fileEncoding) } @@ -465,6 +492,7 @@ if (rc == 0) { // wazideploy_manifest.yml is the default name of the manifest file wdManifestGeneratorUtilities.writeApplicationManifest(new File("$tempLoadDir/wazideploy_manifest.yml"), props.fileEncoding, props.verbose) } + if (rc == 0) { @@ -567,6 +595,23 @@ if (rc == 0) { println ("** Upload package to Artifact Repository '$url'.") artifactRepositoryHelpers.upload(url, tarFile as String, user, password, props.verbose.toBoolean(), httpClientVersion) + + // generate PackageInfo for Concert Manifest file + if (props.generateConcertBuildManifest && props.generateConcertBuildManifest.toBoolean() ) { + + packageInfo.put("type", "artifactory") + if (url) packageInfo.put("uri", url) + if (tarFileName) packageInfo.put("name",tarFileName) + // Set package info + concertManifestGeneratorUtilities.setPackageInfo(packageInfo) + + } + } + + if (concertManifestGeneratorUtilities && props.generateConcertBuildManifest && props.generateConcertBuildManifest.toBoolean() && rc == 0) { + // print concert deploy manifest + // concert_build_manifest.yml is the default name of the manifest file + concertManifestGeneratorUtilities.writeBuildManifest(new File("$tempLoadDir/concert_build_manifest.yml"), props.fileEncoding, props.verbose) } } } @@ -643,12 +688,15 @@ def parseInput(String[] cliArgs){ // Wazi Deploy Application Manifest generation cli.wd(longOpt:'generateWaziDeployAppManifest', 'Flag indicating to generate and add the Wazi Deploy Application Manifest file.') + // Concert Build Manifest generation + cli.ic(longOpt:'generateConcertBuildManifest', 'Flag indicating to generate and add the IBM Concert Build Manifest file.') + cli.b(longOpt:'branch', args:1, argName:'branch', 'The git branch processed by the pipeline') cli.a(longOpt:'application', args:1, argName:'application', 'The name of the application') // Artifact repository options :: cli.p(longOpt:'publish', 'Flag to indicate package upload to the provided Artifact Repository server. (Optional)') - cli.v(longOpt:'versionName', args:1, argName:'versionName', 'Name of the version/package on the Artifact repository server. (Optional)') + cli.v(longOpt:'versionName', args:1, argName:'versionName', 'Name of the version/package on the Artifact repository server. (Optional)') // Artifact repository info cli.au(longOpt:'artifactRepositoryUrl', args:1, argName:'url', 'URL to the Artifact repository server. (Optional)') @@ -705,6 +753,7 @@ def parseInput(String[] cliArgs){ // cli overrides defaults set in 'packageBuildOutputs.properties' props.generateWaziDeployAppManifest = (opts.wd) ? 'true' : props.generateWaziDeployAppManifest + props.generateConcertBuildManifest = (opts.ic) ? 'true' : props.generateConcertBuildManifest props.addExtension = (opts.ae) ? 'true' : props.addExtension props.publish = (opts.p) ? 'true' : props.publish props.generateSBOM = (opts.sbom) ? 'true' : props.generateSBOM @@ -819,6 +868,19 @@ def parseInput(String[] cliArgs){ rc = 2 } } + + // assess required options to generate Concert Build manifest + if (props.generateConcertBuildManifest && props.generateConcertBuildManifest.toBoolean()) { + if (!props.branch) { + println("*! [ERROR] Missing branch parameter ('--branch'). It is required for generating the Concert Build Manifest file.") + rc = 2 + } + if (!props.publish || !props.publish.toBoolean()) { + println("*! [ERROR] Missing package publish parameter. It is required for generating the Concert Build Manifest file.") + rc = 2 + } + } + return props } diff --git a/Pipeline/PackageBuildOutputs/utilities/concertBuildManifestGenerator.groovy b/Pipeline/PackageBuildOutputs/utilities/concertBuildManifestGenerator.groovy new file mode 100644 index 00000000..4c9fa580 --- /dev/null +++ b/Pipeline/PackageBuildOutputs/utilities/concertBuildManifestGenerator.groovy @@ -0,0 +1,128 @@ +import groovy.transform.* +import groovy.yaml.YamlBuilder +import com.ibm.dbb.build.report.records.* + +/* + * This is a utility method to generate the Wazi Deploy Application Manifest file + * See https://www.ibm.com/docs/en/developer-for-zos/16.0?topic=files-application-manifest-file + */ + +/** + * Initialize application manifest file + * Should be the constructor + */ + +@Field ConcertBuildManifest concertManifest = new ConcertBuildManifest() + +def initConcertBuildManifestGenerator(Properties props, String buildNumber) { + // Metadata + concertManifest.concert = new Concertdata() + concertManifest.concert.builds = new Builds() + concertManifest.concert.builds[0].repositories = new Repositories() + concertManifest.concert.builds[0].library = new Library() + + if (props.application) { + concertManifest.concert.builds[0].component_name = props.application + } else { + concertManifest.concert.builds[0].component_name = "UNDEFINED" + } + concertManifest.concert.builds[0].number = buildNumber + concertManifest.concert.builds[0].output_file = concertManifest.concert.builds[0].component_name + "_sbom.json" + + // Metadata information + concertManifest.concert.builds[0].version = (props.versionName) ? props.versionName : props.startTime + +} + +def setScmInfo(HashMap scmInfoMap) { + concertManifest.concert.builds[0].repositories[0].name = concertManifest.concert.builds[0].component_name + concertManifest.concert.builds[0].repositories[0].url = scmInfoMap.uri + concertManifest.concert.builds[0].repositories[0].branch = scmInfoMap.branch + concertManifest.concert.builds[0].repositories[0].commit_sha = scmInfoMap.shortCommit +} + +def setPackageInfo(HashMap packageInfoMap) { + concertManifest.concert.builds[0].library.scope = 'tar' + concertManifest.concert.builds[0].library.name = concertManifest.concert.builds[0].component_name + concertManifest.concert.builds[0].library.filename = packageInfoMap.name + concertManifest.concert.builds[0].library.version = concertManifest.concert.builds[0].version + concertManifest.concert.builds[0].library.url = packageInfoMap.uri +} + +def setSBOMInfo(String sbomFileName, String sbomSerialNumber) { + concertManifest.concert.builds[0].library.cyclonedx_bom_link = new SBOMInfo() + concertManifest.concert.builds[0].library.cyclonedx_bom_link.file = sbomFileName + concertManifest.concert.builds[0].library.cyclonedx_bom_link.data = new SBOMdata() + concertManifest.concert.builds[0].library.cyclonedx_bom_link.data.serial_number = sbomSerialNumber + concertManifest.concert.builds[0].library.cyclonedx_bom_link.data.version = 1 +} + +/** + * Write an Concert Build Manifest a YAML file + */ +def writeBuildManifest(File yamlFile, String fileEncoding, String verbose){ + println("** Generate Concert Build Manifest file to $yamlFile") + def yamlBuilder = new YamlBuilder() + + yamlBuilder { + specVersion concertManifest.specVersion + concert concertManifest.concert + } + + if (verbose && verbose.toBoolean()) { + println yamlBuilder.toString() + } + + // write file + yamlFile.withWriter(fileEncoding) { writer -> + writer.write(yamlBuilder.toString()) + } +} + +/** + * Concert Deploy Manifest Classes and Helpers + */ + +class ConcertBuildManifest { + String specVersion = "1.0.2" + Concertdata concert +} + +class Concertdata { + Builds[] builds +} + +class Builds { + String component_name + String output_file + String number + String version + Library library + Repositories[] repositories +} + +class Repositories { + String name + String url + String branch + String commit_sha +} + +class Library { + String scope + String name + String version + String filename + String url + SBOMInfo cyclonedx_bom_link +} + +class SBOMInfo { + String file + SBOMdata data +} + +class SBOMdata { + String serial_number + String version +} \ No newline at end of file diff --git a/Pipeline/PackageBuildOutputs/utilities/sbomGenerator.groovy b/Pipeline/PackageBuildOutputs/utilities/sbomGenerator.groovy index aa19b6b9..07ffde54 100644 --- a/Pipeline/PackageBuildOutputs/utilities/sbomGenerator.groovy +++ b/Pipeline/PackageBuildOutputs/utilities/sbomGenerator.groovy @@ -19,6 +19,9 @@ import org.cyclonedx.model.* * * Version 1 - 04/2024 * Initial implementation of SBOM Generation + * Version 2 - 10/2024 + * Changed to pass SerialNumber from the packaging script. Changed type "container" + * to "library" ************************************************************************************/ @@ -30,10 +33,8 @@ import org.cyclonedx.model.* @Field ArrayList sbomDependencies @Field Bom sbom -def initializeSBOM(String sbomAuthor) { +def initializeSBOM(String sbomAuthor, String serialNumber) { sbom = new Bom(); - sbom.setSerialNumber("url:uuid:" + UUID.randomUUID().toString()); - sbom.setVersion(1); LifecycleChoice sbomLifecycleChoice = new LifecycleChoice() sbomLifecycleChoice.setPhase(LifecycleChoice.Phase.POST_BUILD) Lifecycles sbomLifecycles = new Lifecycles() @@ -54,6 +55,14 @@ def initializeSBOM(String sbomAuthor) { } else { println("*! Warning: empty SBOM Author. It is recommend to specify a valid Author.") } + if (serialNumber) { + sbom.setSerialNumber(serialNumber) + } else { + println("*! Warning: Serial Number has been regenerated.") + sbom.setSerialNumber("url:uuid:" + UUID.randomUUID().toString()) + } + + sbom.setVersion(1) sbom.setMetadata(sbomMetadata) sbom.setDependencies(new ArrayList()) } @@ -95,7 +104,7 @@ def addEntryToSBOM(DeployableArtifact deployableArtifact, HashMap deployableArtifactComponentProperties = new ArrayList() Property deployableArtifactContainerComponentProperty = new Property() - deployableArtifactContainerComponentProperty.setName("container") + deployableArtifactContainerComponentProperty.setName("library") deployableArtifactContainerComponentProperty.setValue(container) deployableArtifactComponentProperties.add(deployableArtifactContainerComponentProperty) Property deployableArtifactDeployTypeComponentProperty = new Property() From d5a05bdf8d61f1724b3d785cbdd5a907e3494385 Mon Sep 17 00:00:00 2001 From: Mathieu Dalbin Date: Mon, 28 Oct 2024 17:43:51 +0100 Subject: [PATCH 02/14] Reworked the generation of IBM Concert build file Signed-off-by: Mathieu Dalbin --- .../PackageBuildOutputs.groovy | 42 ++++------ .../packageBuildOutputs.properties | 5 ++ .../concertBuildManifestGenerator.groovy | 83 +++++++++---------- 3 files changed, 61 insertions(+), 69 deletions(-) diff --git a/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy b/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy index 5b60c9e2..8210230e 100644 --- a/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy +++ b/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy @@ -68,6 +68,7 @@ def scriptDir = new File(getClass().protectionDomain.codeSource.location.path).p @Field def rc = 0 @Field def sbomSerialNumber @Field def sbomFileName +@Field def concertBuild def startTime = new Date() @@ -106,10 +107,6 @@ def String buildNumber = "UNKNOWN" // Object to store scm information for Wazi Deploy Application Manifest file HashMap scmInfo = new HashMap() -// Object to store scm information for Wazi Deploy Application Manifest file -HashMap packageInfo = new HashMap() - - // iterate over all build reports to obtain build output props.buildReportOrder.each { buildReportFile -> println("** Read build report data from '${buildReportFile}'.") @@ -366,7 +363,7 @@ if (rc == 0) { sbomUtilities = loadScript(new File("${scriptDir}/utilities/sbomGenerator.groovy")) sbomSerialNumber = "url:uuid:" + UUID.randomUUID().toString() sbomFileName = "${buildNumber}_sbom.json" - sbomUtilities.initializeSBOM(props.sbomAuthor,sbomSerialNumber) + sbomUtilities.initializeSBOM(props.sbomAuthor, sbomSerialNumber) } // Local variables @@ -378,9 +375,11 @@ if (rc == 0) { // Initialize Concert Build Manifest Generator if (props.generateConcertBuildManifest && props.generateConcertBuildManifest.toBoolean()) { - concertManifestGeneratorUtilities.initConcertBuildManifestGenerator(props,buildNumber)// Concert Build Manifest - concertManifestGeneratorUtilities.setScmInfo(scmInfo) - concertManifestGeneratorUtilities.setSBOMInfo(sbomFileName,sbomSerialNumber) + // Concert Build Manifest + concertManifestGeneratorUtilities.initConcertBuildManifestGenerator() + concertBuild = concertManifestGeneratorUtilities.addBuild(props.application, props.versionName, buildNumber) + + concertManifestGeneratorUtilities.addRepositoryToBuild(concertBuild, scmInfo.uri, scmInfo.branch, scmInfo.shortCommit) } def String tarFileName = (props.tarFileName) ? props.tarFileName : "${tarFileLabel}.tar" def tarFile = "$props.workDir/${tarFileName}" @@ -596,21 +595,18 @@ if (rc == 0) { println ("** Upload package to Artifact Repository '$url'.") artifactRepositoryHelpers.upload(url, tarFile as String, user, password, props.verbose.toBoolean(), httpClientVersion) - // generate PackageInfo for Concert Manifest file - if (props.generateConcertBuildManifest && props.generateConcertBuildManifest.toBoolean() ) { - - packageInfo.put("type", "artifactory") - if (url) packageInfo.put("uri", url) - if (tarFileName) packageInfo.put("name",tarFileName) - // Set package info - concertManifestGeneratorUtilities.setPackageInfo(packageInfo) - - } + // generate PackageInfo for Concert Manifest file + if (props.generateConcertBuildManifest && props.generateConcertBuildManifest.toBoolean()) { + concertManifestGeneratorUtilities.addLibraryInfoTobuild(concertBuild, tarFileName, url) + } } if (concertManifestGeneratorUtilities && props.generateConcertBuildManifest && props.generateConcertBuildManifest.toBoolean() && rc == 0) { - // print concert deploy manifest // concert_build_manifest.yml is the default name of the manifest file + + if (props.generateSBOM && props.generateSBOM.toBoolean() && rc == 0) { + concertManifestGeneratorUtilities.addSBOMInfoToBuild(concertBuild, sbomFileName, sbomSerialNumber) + } concertManifestGeneratorUtilities.writeBuildManifest(new File("$tempLoadDir/concert_build_manifest.yml"), props.fileEncoding, props.verbose) } } @@ -851,10 +847,6 @@ def parseInput(String[] cliArgs){ println("*! [ERROR] Missing Artifact Repository Password property. It is required when publishing the package via ArtifactRepositoryHelpers.") rc = 2 } - if (!props.'artifactRepository.directory') { - println("*! [ERROR] Missing Artifact Repository Directory property. It is required when publishing the package via ArtifactRepositoryHelpers.") - rc = 2 - } } // assess required options to generate Wazi Deploy application manifest @@ -875,8 +867,8 @@ def parseInput(String[] cliArgs){ println("*! [ERROR] Missing branch parameter ('--branch'). It is required for generating the Concert Build Manifest file.") rc = 2 } - if (!props.publish || !props.publish.toBoolean()) { - println("*! [ERROR] Missing package publish parameter. It is required for generating the Concert Build Manifest file.") + if (!props.publish) { + println("*! [ERROR] Missing publish parameter ('--publish'). It is required for generating the Concert Build Manifest file.") rc = 2 } } diff --git a/Pipeline/PackageBuildOutputs/packageBuildOutputs.properties b/Pipeline/PackageBuildOutputs/packageBuildOutputs.properties index 999eea13..426d391c 100644 --- a/Pipeline/PackageBuildOutputs/packageBuildOutputs.properties +++ b/Pipeline/PackageBuildOutputs/packageBuildOutputs.properties @@ -30,6 +30,11 @@ addExtension=false # Default: false generateWaziDeployAppManifest=false +# Boolean setting to define if the Wazi Deploy Application Manifest file should be generated +# Please note that the cli option `generateWaziDeployAppManifest` can override this setting and activate it. +# Default: false +generateConcertBuildManifest=false + # Boolean setting to define if SBOM based on cycloneDX should be generated # Please note that the cli option `generateSBOM` can override this setting and activate it. # Requires the classpath to contain the cycloneDX libs diff --git a/Pipeline/PackageBuildOutputs/utilities/concertBuildManifestGenerator.groovy b/Pipeline/PackageBuildOutputs/utilities/concertBuildManifestGenerator.groovy index 4c9fa580..5aba65cc 100644 --- a/Pipeline/PackageBuildOutputs/utilities/concertBuildManifestGenerator.groovy +++ b/Pipeline/PackageBuildOutputs/utilities/concertBuildManifestGenerator.groovy @@ -3,65 +3,60 @@ import groovy.yaml.YamlBuilder import com.ibm.dbb.build.report.records.* /* - * This is a utility method to generate the Wazi Deploy Application Manifest file - * See https://www.ibm.com/docs/en/developer-for-zos/16.0?topic=files-application-manifest-file - */ - -/** - * Initialize application manifest file - * Should be the constructor + * This is a utility method to generate IBM Concert build files */ @Field ConcertBuildManifest concertManifest = new ConcertBuildManifest() -def initConcertBuildManifestGenerator(Properties props, String buildNumber) { +def initConcertBuildManifestGenerator() { // Metadata concertManifest.concert = new Concertdata() - concertManifest.concert.builds = new Builds() - concertManifest.concert.builds[0].repositories = new Repositories() - concertManifest.concert.builds[0].library = new Library() - - if (props.application) { - concertManifest.concert.builds[0].component_name = props.application - } else { - concertManifest.concert.builds[0].component_name = "UNDEFINED" - } - concertManifest.concert.builds[0].number = buildNumber - concertManifest.concert.builds[0].output_file = concertManifest.concert.builds[0].component_name + "_sbom.json" + concertManifest.concert.builds = new ArrayList() +} +def addBuild(String application, String version, String buildNumber) { + Build build = new Build() + build.repositories = new ArrayList() + build.library = new Library() + build.component_name = application + build.number = buildNumber + build.output_file = application + "_sbom.json" // Metadata information - concertManifest.concert.builds[0].version = (props.versionName) ? props.versionName : props.startTime - + build.version = version + concertManifest.concert.builds.add(build) + return build } -def setScmInfo(HashMap scmInfoMap) { - concertManifest.concert.builds[0].repositories[0].name = concertManifest.concert.builds[0].component_name - concertManifest.concert.builds[0].repositories[0].url = scmInfoMap.uri - concertManifest.concert.builds[0].repositories[0].branch = scmInfoMap.branch - concertManifest.concert.builds[0].repositories[0].commit_sha = scmInfoMap.shortCommit +def addRepositoryToBuild(Build build, String url, String branch, String shortCommit) { + Repository repository = new Repository() + repository.name = build.component_name + repository.url = url + repository.branch = branch + repository.commit_sha = shortCommit + build.repositories.add(repository) } -def setPackageInfo(HashMap packageInfoMap) { - concertManifest.concert.builds[0].library.scope = 'tar' - concertManifest.concert.builds[0].library.name = concertManifest.concert.builds[0].component_name - concertManifest.concert.builds[0].library.filename = packageInfoMap.name - concertManifest.concert.builds[0].library.version = concertManifest.concert.builds[0].version - concertManifest.concert.builds[0].library.url = packageInfoMap.uri +def addLibraryInfoTobuild(Build build, String filename, String url) { + build.library.scope = 'tar' + build.library.name = build.component_name + build.library.filename = filename + build.library.version = build.version + build.library.url = url } -def setSBOMInfo(String sbomFileName, String sbomSerialNumber) { - concertManifest.concert.builds[0].library.cyclonedx_bom_link = new SBOMInfo() - concertManifest.concert.builds[0].library.cyclonedx_bom_link.file = sbomFileName - concertManifest.concert.builds[0].library.cyclonedx_bom_link.data = new SBOMdata() - concertManifest.concert.builds[0].library.cyclonedx_bom_link.data.serial_number = sbomSerialNumber - concertManifest.concert.builds[0].library.cyclonedx_bom_link.data.version = 1 +def addSBOMInfoToBuild(Build build, String sbomFileName, String sbomSerialNumber) { + build.library.cyclonedx_bom_link = new SBOMInfo() + build.library.cyclonedx_bom_link.file = sbomFileName + build.library.cyclonedx_bom_link.data = new SBOMdata() + build.library.cyclonedx_bom_link.data.serial_number = sbomSerialNumber + build.library.cyclonedx_bom_link.data.version = 1 } /** * Write an Concert Build Manifest a YAML file */ def writeBuildManifest(File yamlFile, String fileEncoding, String verbose){ - println("** Generate Concert Build Manifest file to $yamlFile") + println("** Generate IBM Concert Build Manifest file to '$yamlFile'") def yamlBuilder = new YamlBuilder() yamlBuilder { @@ -80,7 +75,7 @@ def writeBuildManifest(File yamlFile, String fileEncoding, String verbose){ } /** - * Concert Deploy Manifest Classes and Helpers + * IBM Concert Manifest Classes and Helpers */ class ConcertBuildManifest { @@ -89,19 +84,19 @@ class ConcertBuildManifest { } class Concertdata { - Builds[] builds + ArrayList builds } -class Builds { +class Build { String component_name String output_file String number String version Library library - Repositories[] repositories + ArrayList repositories } -class Repositories { +class Repository { String name String url String branch From eef5e0b933d4efe38e0293d14bf23e795f81076f Mon Sep 17 00:00:00 2001 From: Mathieu Dalbin Date: Mon, 28 Oct 2024 17:46:52 +0100 Subject: [PATCH 03/14] Added changes to SBOM processing Signed-off-by: Mathieu Dalbin --- Pipeline/PackageBuildOutputs/utilities/sbomGenerator.groovy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Pipeline/PackageBuildOutputs/utilities/sbomGenerator.groovy b/Pipeline/PackageBuildOutputs/utilities/sbomGenerator.groovy index 07ffde54..6bfd154e 100644 --- a/Pipeline/PackageBuildOutputs/utilities/sbomGenerator.groovy +++ b/Pipeline/PackageBuildOutputs/utilities/sbomGenerator.groovy @@ -50,15 +50,15 @@ def initializeSBOM(String sbomAuthor, String serialNumber) { author.setEmail(sbomAuthorFields[1].replaceAll(">", "").trim()) sbomMetadata.addAuthor(author) } else { - println("*! Warning: SBOM Author not correctly formed, expecting 'Name ' format. Skipping.") + println("*! [WARNING] SBOM Author not correctly formed, expecting 'Name ' format. Skipping.") } } else { - println("*! Warning: empty SBOM Author. It is recommend to specify a valid Author.") + println("*! [WARNING] empty SBOM Author. It is recommend to specify a valid Author.") } if (serialNumber) { sbom.setSerialNumber(serialNumber) } else { - println("*! Warning: Serial Number has been regenerated.") + println("*! [WARNING] Serial Number has been regenerated.") sbom.setSerialNumber("url:uuid:" + UUID.randomUUID().toString()) } From 7afa3ddb22ef1a86f9458ae2e82a08f0aa091e3b Mon Sep 17 00:00:00 2001 From: Suman Date: Mon, 4 Nov 2024 11:03:49 -0500 Subject: [PATCH 04/14] Addressed some of Dennis's comments. Changed concert file extension to 'yaml' and changed version to 1.0.3 --- .../PackageBuildOutputs.groovy | 9 +++++---- Pipeline/PackageBuildOutputs/README.md | 19 ++++++++++++++++++- .../concertBuildManifestGenerator.groovy | 2 +- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy b/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy index 8210230e..03ec96ef 100644 --- a/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy +++ b/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy @@ -63,8 +63,8 @@ import com.ibm.jzos.ZFile; @Field Properties props = null def scriptDir = new File(getClass().protectionDomain.codeSource.location.path).parent @Field def wdManifestGeneratorUtilities = loadScript(new File("${scriptDir}/utilities/WaziDeployManifestGenerator.groovy")) -@Field def concertManifestGeneratorUtilities = loadScript(new File("${scriptDir}/utilities/concertBuildManifestGenerator.groovy")) @Field def sbomUtilities +@Field def concertManifestGeneratorUtilities @Field def rc = 0 @Field def sbomSerialNumber @Field def sbomFileName @@ -376,9 +376,10 @@ if (rc == 0) { // Initialize Concert Build Manifest Generator if (props.generateConcertBuildManifest && props.generateConcertBuildManifest.toBoolean()) { // Concert Build Manifest + + concertManifestGeneratorUtilities = loadScript(new File("${scriptDir}/utilities/concertBuildManifestGenerator.groovy")) concertManifestGeneratorUtilities.initConcertBuildManifestGenerator() concertBuild = concertManifestGeneratorUtilities.addBuild(props.application, props.versionName, buildNumber) - concertManifestGeneratorUtilities.addRepositoryToBuild(concertBuild, scmInfo.uri, scmInfo.branch, scmInfo.shortCommit) } def String tarFileName = (props.tarFileName) ? props.tarFileName : "${tarFileLabel}.tar" @@ -602,12 +603,12 @@ if (rc == 0) { } if (concertManifestGeneratorUtilities && props.generateConcertBuildManifest && props.generateConcertBuildManifest.toBoolean() && rc == 0) { - // concert_build_manifest.yml is the default name of the manifest file + // concert_build_manifest.yaml is the default name of the manifest file if (props.generateSBOM && props.generateSBOM.toBoolean() && rc == 0) { concertManifestGeneratorUtilities.addSBOMInfoToBuild(concertBuild, sbomFileName, sbomSerialNumber) } - concertManifestGeneratorUtilities.writeBuildManifest(new File("$tempLoadDir/concert_build_manifest.yml"), props.fileEncoding, props.verbose) + concertManifestGeneratorUtilities.writeBuildManifest(new File("$tempLoadDir/concert_build_manifest.yaml"), props.fileEncoding, props.verbose) } } } diff --git a/Pipeline/PackageBuildOutputs/README.md b/Pipeline/PackageBuildOutputs/README.md index 412bedab..3b4fb7b9 100644 --- a/Pipeline/PackageBuildOutputs/README.md +++ b/Pipeline/PackageBuildOutputs/README.md @@ -46,6 +46,9 @@ This section provides a more detailed explanation of how the PackageBuildOutputs 6. **(Optional) Publish to Artifact Repository such as JFrog Artifactory or Sonartype Nexus** 1. Publishes the TAR file to the artifact repository based on the given configuration using the ArtifactRepositoryHelpers script. Consider a Nexus RAW, or a Artifactory Generic as the repository type. **Please note**: The ArtifactRepositoryHelpers script is updated for DBB 2.0 and requires to run on JAVA 11. The publishing can be configured to pass in the artifact repository information as well as the path within the repository `directory/[versionName|buildLabel]/tarFileName` via the cli. +7. **(Optional) Generate IBM Concert Build manifest** + 1. Based on the collected build outputs information, the IBM Concert Build Manifest file is generated and saved as concert_build_manifest.yaml. This is a feeder file to publish build information into IBM Concert. It will only be generated if both sbom and packaging options are in effect. + Notes: * The script doesn't manage the deletions of artifacts. Although they are reported in the DBB Build Reports, deletions are not handled by this script. @@ -566,9 +569,23 @@ As an example, you can invoke the SBOM generation with the following command: /usr/lpp/dbb/v2r0/bin/groovyz -cp /u/mdalbin/SBOM/cyclonedx-core-java-8.0.3.jar:/u/mdalbin/SBOM/jackson-annotations-2.16.1.jar:/u/mdalbin/SBOM/jackson-core-2.16.1.jar:/u/mdalbin/SBOM/jackson-databind-2.16.1.jar:/u/mdalbin/SBOM/jackson-dataformat-xml-2.16.1.jar:/u/mdalbin/SBOM/json-schema-validator-1.2.0.jar:/u/mdalbin/SBOM/packageurl-java-1.5.0.jar /u/mdalbin/SBOM/dbb/Pipeline/PackageBuildOutputs/PackageBuildOutputsWithSBOM.groovy --workDir /u/ado/workspace/MortgageApplication/feature/consumeRetirementCalculatorServiceImpacts/build-20240312.1/logs --tarFileName MortgageApplication.tar --addExtension -s -sa "David Gilmour " ~~~~ -By default, the SBOM file is generated in the `tempPackageDir` and named `sbom.json`. +By default, the SBOM file is generated in the `tempPackageDir` and named `_sbom.json`. This way, it is automatically packaged in the TAR file that is created by the script, ensuring the package and its content are not tampered and correctly documented. +## IBM Concert Build (SBOM) manifest generation + +This `PackageBuildOutputs.groovy` script is able to generate an IBM Concert SBOM file based on the information contained in the DBB Build Report and the published package information. The output is a yaml file that adheres to IBM Concert build configuration yaml format. The generation of the CycloneDX SBOM is a pre-requisite as the IBM Concert file will redirect to CycloneDX for detailed information about the build outputs. + +To enable the generation of the IBM Concert manifest/config file, the `-ic/--generateConcertBuildManifest` flag must be passed. + +As an example, you can invoke IBM Concert generation with the following command: + +~~~~ +/usr/lpp/dbb/v2r0/bin/groovyz -cp /u/mdalbin/SBOM/cyclonedx-core-java-8.0.3.jar:/u/mdalbin/SBOM/jackson-annotations-2.16.1.jar:/u/mdalbin/SBOM/jackson-core-2.16.1.jar:/u/mdalbin/SBOM/jackson-databind-2.16.1.jar:/u/mdalbin/SBOM/jackson-dataformat-xml-2.16.1.jar:/u/mdalbin/SBOM/json-schema-validator-1.2.0.jar:/u/mdalbin/SBOM/packageurl-java-1.5.0.jar /u/mdalbin/SBOM/dbb/Pipeline/PackageBuildOutputs/PackageBuildOutputsWithSBOM.groovy --workDir /u/ado/workspace/MortgageApplication/feature/consumeRetirementCalculatorServiceImpacts/build-20240312.1/logs --tarFileName MortgageApplication.tar --addExtension -s -sa "David Gilmour " -ic +~~~~ + +By default, the concert build manifest file is generated in the `tempPackageDir` and named `concert_build_manifest.yaml`. + ## Useful reference material diff --git a/Pipeline/PackageBuildOutputs/utilities/concertBuildManifestGenerator.groovy b/Pipeline/PackageBuildOutputs/utilities/concertBuildManifestGenerator.groovy index 5aba65cc..1ab3fd3f 100644 --- a/Pipeline/PackageBuildOutputs/utilities/concertBuildManifestGenerator.groovy +++ b/Pipeline/PackageBuildOutputs/utilities/concertBuildManifestGenerator.groovy @@ -79,7 +79,7 @@ def writeBuildManifest(File yamlFile, String fileEncoding, String verbose){ */ class ConcertBuildManifest { - String specVersion = "1.0.2" + String specVersion = "1.0.3" Concertdata concert } From 94a4e1126a6fdd006e33786300339b98faeff8b5 Mon Sep 17 00:00:00 2001 From: Suman Date: Mon, 4 Nov 2024 11:17:13 -0500 Subject: [PATCH 05/14] Addressing comments to correct typo in properties file --- Pipeline/PackageBuildOutputs/packageBuildOutputs.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Pipeline/PackageBuildOutputs/packageBuildOutputs.properties b/Pipeline/PackageBuildOutputs/packageBuildOutputs.properties index 426d391c..094467b6 100644 --- a/Pipeline/PackageBuildOutputs/packageBuildOutputs.properties +++ b/Pipeline/PackageBuildOutputs/packageBuildOutputs.properties @@ -30,8 +30,8 @@ addExtension=false # Default: false generateWaziDeployAppManifest=false -# Boolean setting to define if the Wazi Deploy Application Manifest file should be generated -# Please note that the cli option `generateWaziDeployAppManifest` can override this setting and activate it. +# Boolean setting to define if the IBM Concert Build Manifest file should be generated +# Please note that the cli option `generateConcertBuildManifest` can override this setting and activate it. # Default: false generateConcertBuildManifest=false From 93c8e5e4f6436dd667d3c52567607dace81e150e Mon Sep 17 00:00:00 2001 From: Suman Date: Mon, 4 Nov 2024 12:26:37 -0500 Subject: [PATCH 06/14] added concert build manifest to the package tar file --- .../PackageBuildOutputs.groovy | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy b/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy index 03ec96ef..6a8a9c7c 100644 --- a/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy +++ b/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy @@ -609,6 +609,22 @@ if (rc == 0) { concertManifestGeneratorUtilities.addSBOMInfoToBuild(concertBuild, sbomFileName, sbomSerialNumber) } concertManifestGeneratorUtilities.writeBuildManifest(new File("$tempLoadDir/concert_build_manifest.yaml"), props.fileEncoding, props.verbose) + println("** Add concert build config yaml to tar file at ${tarFile}") + // Note: https://www.ibm.com/docs/en/zos/2.4.0?topic=scd-tar-manipulate-tar-archive-files-copy-back-up-file + // To save all attributes to be restored on z/OS and non-z/OS systems : tar -UX + def processCmd = [ + "sh", + "-c", + "tar rvf $tarFile concert_build_manifest.yaml" + ] + + def processRC = runProcess(processCmd, tempLoadDir) + rc = Math.max(rc, processRC) + if (rc == 0) { + println("** Package '${tarFile}' successfully appended with concert manifest yaml.") + } else { + println("*! [ERROR] Error appending '${tarFile}' with concert manifest yaml rc=$rc.") + } } } } From 11afdd8de7f743152e8ec2fa5e8fed40dfef2d32 Mon Sep 17 00:00:00 2001 From: Suman Date: Mon, 4 Nov 2024 14:29:03 -0500 Subject: [PATCH 07/14] corrected error in tar parms --- Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy b/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy index 6a8a9c7c..1f166d10 100644 --- a/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy +++ b/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy @@ -615,7 +615,7 @@ if (rc == 0) { def processCmd = [ "sh", "-c", - "tar rvf $tarFile concert_build_manifest.yaml" + "tar rUXf $tarFile concert_build_manifest.yaml" ] def processRC = runProcess(processCmd, tempLoadDir) From e83fb34a21455f2bf4f85cfb014e66aadde43149 Mon Sep 17 00:00:00 2001 From: Suman Date: Mon, 4 Nov 2024 15:25:43 -0500 Subject: [PATCH 08/14] Check to ensure single build reports are a pre-req for concert. --- Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy b/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy index 1f166d10..222bda3a 100644 --- a/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy +++ b/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy @@ -888,6 +888,10 @@ def parseInput(String[] cliArgs){ println("*! [ERROR] Missing publish parameter ('--publish'). It is required for generating the Concert Build Manifest file.") rc = 2 } + if (props.bO || props.boFile) { + println("*! [ERROR] conflicting parameter ('-bO or -boFile'). IBM Concert Build Manifest file is creating with single builds only.") + rc = 2 + } } return props From c007293bdc82bb36a0e2d2a8d9308ca56a83a946 Mon Sep 17 00:00:00 2001 From: Suman Date: Mon, 4 Nov 2024 16:41:07 -0500 Subject: [PATCH 09/14] corrected bug in error handling for multiple build reports and concert manifest generation --- Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy b/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy index 222bda3a..5fbf2099 100644 --- a/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy +++ b/Pipeline/PackageBuildOutputs/PackageBuildOutputs.groovy @@ -888,8 +888,8 @@ def parseInput(String[] cliArgs){ println("*! [ERROR] Missing publish parameter ('--publish'). It is required for generating the Concert Build Manifest file.") rc = 2 } - if (props.bO || props.boFile) { - println("*! [ERROR] conflicting parameter ('-bO or -boFile'). IBM Concert Build Manifest file is creating with single builds only.") + if (opts.bO || opts.boFile) { + println("*! [ERROR] conflicting parameter ('-bO or -boFile'). IBM Concert Build Manifest file is created with single builds only.") rc = 2 } } From f155e0b6bad2fbf15133e5b4692904d445e27cb1 Mon Sep 17 00:00:00 2001 From: suman-gopinath <69168800+suman-gopinath@users.noreply.github.com> Date: Wed, 6 Nov 2024 10:44:12 -0500 Subject: [PATCH 10/14] Update Pipeline/PackageBuildOutputs/README.md Co-authored-by: Mathieu Dalbin --- Pipeline/PackageBuildOutputs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pipeline/PackageBuildOutputs/README.md b/Pipeline/PackageBuildOutputs/README.md index 3b4fb7b9..9824b750 100644 --- a/Pipeline/PackageBuildOutputs/README.md +++ b/Pipeline/PackageBuildOutputs/README.md @@ -572,7 +572,7 @@ As an example, you can invoke the SBOM generation with the following command: By default, the SBOM file is generated in the `tempPackageDir` and named `_sbom.json`. This way, it is automatically packaged in the TAR file that is created by the script, ensuring the package and its content are not tampered and correctly documented. -## IBM Concert Build (SBOM) manifest generation +## IBM Concert Build manifest generation This `PackageBuildOutputs.groovy` script is able to generate an IBM Concert SBOM file based on the information contained in the DBB Build Report and the published package information. The output is a yaml file that adheres to IBM Concert build configuration yaml format. The generation of the CycloneDX SBOM is a pre-requisite as the IBM Concert file will redirect to CycloneDX for detailed information about the build outputs. From ec10f44e23759426b631fdcb54e29485aff8f675 Mon Sep 17 00:00:00 2001 From: suman-gopinath <69168800+suman-gopinath@users.noreply.github.com> Date: Wed, 6 Nov 2024 10:45:00 -0500 Subject: [PATCH 11/14] Update Pipeline/PackageBuildOutputs/README.md Co-authored-by: Mathieu Dalbin --- Pipeline/PackageBuildOutputs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pipeline/PackageBuildOutputs/README.md b/Pipeline/PackageBuildOutputs/README.md index 9824b750..ae4e45da 100644 --- a/Pipeline/PackageBuildOutputs/README.md +++ b/Pipeline/PackageBuildOutputs/README.md @@ -574,7 +574,7 @@ This way, it is automatically packaged in the TAR file that is created by the sc ## IBM Concert Build manifest generation -This `PackageBuildOutputs.groovy` script is able to generate an IBM Concert SBOM file based on the information contained in the DBB Build Report and the published package information. The output is a yaml file that adheres to IBM Concert build configuration yaml format. The generation of the CycloneDX SBOM is a pre-requisite as the IBM Concert file will redirect to CycloneDX for detailed information about the build outputs. +This `PackageBuildOutputs.groovy` script is able to generate an IBM Concert Build manifest based on the information contained in the DBB Build Report and the published package information. The output is a YAML file that adheres to IBM Concert Build specification YAML format. The generation of the CycloneDX SBOM is a pre-requisite as the IBM Concert Build manifest will reference the CycloneDX SBOM file for detailed information about the build outputs. To enable the generation of the IBM Concert manifest/config file, the `-ic/--generateConcertBuildManifest` flag must be passed. From c46bd2e56bcab825afd701e4d327f0e98051a535 Mon Sep 17 00:00:00 2001 From: suman-gopinath <69168800+suman-gopinath@users.noreply.github.com> Date: Wed, 6 Nov 2024 10:46:20 -0500 Subject: [PATCH 12/14] Update Pipeline/PackageBuildOutputs/README.md Co-authored-by: Mathieu Dalbin --- Pipeline/PackageBuildOutputs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pipeline/PackageBuildOutputs/README.md b/Pipeline/PackageBuildOutputs/README.md index ae4e45da..83ed1608 100644 --- a/Pipeline/PackageBuildOutputs/README.md +++ b/Pipeline/PackageBuildOutputs/README.md @@ -584,7 +584,7 @@ As an example, you can invoke IBM Concert generation with the following command: /usr/lpp/dbb/v2r0/bin/groovyz -cp /u/mdalbin/SBOM/cyclonedx-core-java-8.0.3.jar:/u/mdalbin/SBOM/jackson-annotations-2.16.1.jar:/u/mdalbin/SBOM/jackson-core-2.16.1.jar:/u/mdalbin/SBOM/jackson-databind-2.16.1.jar:/u/mdalbin/SBOM/jackson-dataformat-xml-2.16.1.jar:/u/mdalbin/SBOM/json-schema-validator-1.2.0.jar:/u/mdalbin/SBOM/packageurl-java-1.5.0.jar /u/mdalbin/SBOM/dbb/Pipeline/PackageBuildOutputs/PackageBuildOutputsWithSBOM.groovy --workDir /u/ado/workspace/MortgageApplication/feature/consumeRetirementCalculatorServiceImpacts/build-20240312.1/logs --tarFileName MortgageApplication.tar --addExtension -s -sa "David Gilmour " -ic ~~~~ -By default, the concert build manifest file is generated in the `tempPackageDir` and named `concert_build_manifest.yaml`. +By default, the IBM Concert Build manifest file is generated in the `tempPackageDir` and named `concert_build_manifest.yaml`. ## Useful reference material From 83120935e8c8d488de7528494eab76d9ef9c5c0a Mon Sep 17 00:00:00 2001 From: suman-gopinath <69168800+suman-gopinath@users.noreply.github.com> Date: Wed, 6 Nov 2024 10:46:38 -0500 Subject: [PATCH 13/14] Update Pipeline/PackageBuildOutputs/README.md Co-authored-by: Mathieu Dalbin --- Pipeline/PackageBuildOutputs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pipeline/PackageBuildOutputs/README.md b/Pipeline/PackageBuildOutputs/README.md index 83ed1608..87b5b90b 100644 --- a/Pipeline/PackageBuildOutputs/README.md +++ b/Pipeline/PackageBuildOutputs/README.md @@ -576,7 +576,7 @@ This way, it is automatically packaged in the TAR file that is created by the sc This `PackageBuildOutputs.groovy` script is able to generate an IBM Concert Build manifest based on the information contained in the DBB Build Report and the published package information. The output is a YAML file that adheres to IBM Concert Build specification YAML format. The generation of the CycloneDX SBOM is a pre-requisite as the IBM Concert Build manifest will reference the CycloneDX SBOM file for detailed information about the build outputs. -To enable the generation of the IBM Concert manifest/config file, the `-ic/--generateConcertBuildManifest` flag must be passed. +To enable the generation of the IBM Concert Build manifest, the `-ic/--generateConcertBuildManifest` flag must be passed. As an example, you can invoke IBM Concert generation with the following command: From e66e03b7d45326472d760a13f60aa90ddecda000 Mon Sep 17 00:00:00 2001 From: suman-gopinath <69168800+suman-gopinath@users.noreply.github.com> Date: Wed, 6 Nov 2024 10:46:48 -0500 Subject: [PATCH 14/14] Update Pipeline/PackageBuildOutputs/README.md Co-authored-by: Mathieu Dalbin --- Pipeline/PackageBuildOutputs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pipeline/PackageBuildOutputs/README.md b/Pipeline/PackageBuildOutputs/README.md index 87b5b90b..2cc2a686 100644 --- a/Pipeline/PackageBuildOutputs/README.md +++ b/Pipeline/PackageBuildOutputs/README.md @@ -578,7 +578,7 @@ This `PackageBuildOutputs.groovy` script is able to generate an IBM Concert Buil To enable the generation of the IBM Concert Build manifest, the `-ic/--generateConcertBuildManifest` flag must be passed. -As an example, you can invoke IBM Concert generation with the following command: +As an example, you can invoke the generation of an IBM Concert Build manifest with the following command: ~~~~ /usr/lpp/dbb/v2r0/bin/groovyz -cp /u/mdalbin/SBOM/cyclonedx-core-java-8.0.3.jar:/u/mdalbin/SBOM/jackson-annotations-2.16.1.jar:/u/mdalbin/SBOM/jackson-core-2.16.1.jar:/u/mdalbin/SBOM/jackson-databind-2.16.1.jar:/u/mdalbin/SBOM/jackson-dataformat-xml-2.16.1.jar:/u/mdalbin/SBOM/json-schema-validator-1.2.0.jar:/u/mdalbin/SBOM/packageurl-java-1.5.0.jar /u/mdalbin/SBOM/dbb/Pipeline/PackageBuildOutputs/PackageBuildOutputsWithSBOM.groovy --workDir /u/ado/workspace/MortgageApplication/feature/consumeRetirementCalculatorServiceImpacts/build-20240312.1/logs --tarFileName MortgageApplication.tar --addExtension -s -sa "David Gilmour " -ic