Skip to content
Merged
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
4 changes: 3 additions & 1 deletion cli/docs/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ const (
IncludeCachedPackages = "include-cached-packages"
LegacyPeerDeps = "legacy-peer-deps"
RunNative = "run-native"
MvnIncludePluginDeps = "mvn-include-plugin-deps"

// Unique git flags
gitPrefix = "git-"
Expand Down Expand Up @@ -227,7 +228,7 @@ var commandFlags = map[string][]string{
StaticSca, XrayLibPluginBinaryCustomPath, AnalyzerManagerCustomPath, AddSastRules,
},
CurationAudit: {
CurationOutput, WorkingDirs, Threads, RequirementsFile, InsecureTls, useWrapperAudit, UseIncludedBuilds, SolutionPath, DockerImageName, IncludeCachedPackages, LegacyPeerDeps, RunNative,
CurationOutput, WorkingDirs, Threads, RequirementsFile, InsecureTls, useWrapperAudit, UseIncludedBuilds, SolutionPath, DockerImageName, IncludeCachedPackages, MvnIncludePluginDeps, LegacyPeerDeps, RunNative,
},
GitCountContributors: {
InputFile, ScmType, ScmApiUrl, Token, Owner, RepoName, Months, DetailedSummary, InsecureTls, GitThreads, CacheValidity,
Expand Down Expand Up @@ -350,6 +351,7 @@ var flagsMap = map[string]components.Flag{
CurationOutput: components.NewStringFlag(OutputFormat, "Defines the output format of the command. Acceptable values are: table, json.", components.WithStrDefaultValue("table")),
SolutionPath: components.NewStringFlag(SolutionPath, "Path to the .NET solution file (.sln) to use when multiple solution files are present in the directory."),
IncludeCachedPackages: components.NewBoolFlag(IncludeCachedPackages, "When set to true, the system will audit cached packages. This configuration is mandatory for Curation on-demand workflows, which rely on package caching."),
MvnIncludePluginDeps: components.NewBoolFlag(MvnIncludePluginDeps, "[Maven] When set to true, Maven build-plugin transitive dependencies are included in the curation evaluation. Requires two additional Maven invocations (help:effective-pom, dependency:resolve-plugins) which may slow down the scan. By default only project dependencies are scanned."),
Comment thread
gauriy-tech marked this conversation as resolved.
LegacyPeerDeps: components.NewBoolFlag(LegacyPeerDeps, "[npm] Pass --legacy-peer-deps to npm install to bypass peer-dependency version conflicts."),
RunNative: components.NewBoolFlag(RunNative, "[npm] Use the native npm client for dependency resolution. Reads Artifactory URL and repository from the project's .npmrc registry — no 'jf npm-config' required. Respects .npmrc and Volta configuration."),
binarySca: components.NewBoolFlag(Sca, fmt.Sprintf("Selective scanners mode: Execute SCA (Software Composition Analysis) sub-scan. Use --%s to run both SCA and Contextual Analysis. Use --%s --%s to to run SCA. Can be combined with --%s.", Sca, Sca, WithoutCA, Secrets)),
Expand Down
1 change: 1 addition & 0 deletions cli/scancommands.go
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,7 @@ func getCurationCommand(c *components.Context) (*curation.CurationAuditCommand,
SetSolutionFilePath(c.GetStringFlagValue(flags.SolutionPath))
curationAuditCommand.SetDockerImageName(c.GetStringFlagValue(flags.DockerImageName))
curationAuditCommand.SetIncludeCachedPackages(c.GetBoolFlagValue(flags.IncludeCachedPackages))
curationAuditCommand.SetMvnIncludePluginDeps(c.GetBoolFlagValue(flags.MvnIncludePluginDeps))
curationAuditCommand.SetLegacyPeerDeps(c.GetBoolFlagValue(flags.LegacyPeerDeps))
curationAuditCommand.SetRunNative(c.GetBoolFlagValue(flags.RunNative))
return curationAuditCommand, nil
Expand Down
13 changes: 10 additions & 3 deletions commands/curation/curationaudit.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ type CurationAuditCommand struct {
parallelRequests int
dockerImageName string
includeCachedPackages bool
mvnIncludePluginDeps bool
audit.AuditParamsInterface
}

Expand Down Expand Up @@ -285,6 +286,11 @@ func (ca *CurationAuditCommand) SetIncludeCachedPackages(includeCachedPackages b
return ca
}

func (ca *CurationAuditCommand) SetMvnIncludePluginDeps(mvnIncludePluginDeps bool) *CurationAuditCommand {
ca.mvnIncludePluginDeps = mvnIncludePluginDeps
return ca
}

func (ca *CurationAuditCommand) Run() (err error) {
rootDir, err := os.Getwd()
if err != nil {
Expand Down Expand Up @@ -499,9 +505,10 @@ func (ca *CurationAuditCommand) getBuildInfoParamsByTech() (technologies.BuildIn
Args: ca.Args(),
InstallCommandArgs: ca.InstallCommandArgs(),
// Curation params
IsCurationCmd: true,
ParallelRequests: ca.parallelRequests,
OutputFormat: ca.OutputFormat(),
IsCurationCmd: true,
MvnIncludePluginDeps: ca.mvnIncludePluginDeps,
ParallelRequests: ca.parallelRequests,
OutputFormat: ca.OutputFormat(),
// Java params
IsMavenDepTreeInstalled: true,
UseWrapper: ca.UseWrapper(),
Expand Down
81 changes: 81 additions & 0 deletions commands/curation/curationaudit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ func createCurationCmdAndRun(tt testCase) (cmdResults map[string]*CurationReport
curationCmd.SetInsecureTls(true)
curationCmd.SetIgnoreConfigFile(tt.shouldIgnoreConfigFile)
curationCmd.SetInsecureTls(tt.allowInsecureTls)
curationCmd.SetMvnIncludePluginDeps(tt.mvnIncludePluginDeps)
cmdResults = map[string]*CurationReport{}
err = curationCmd.doCurateAudit(cmdResults)
return
Expand Down Expand Up @@ -596,6 +597,15 @@ func validateCurationResults(t *testing.T, testCase testCase, results map[string
result.totalNumberOfPackages = 0
}
}
// Cases that exercise Maven plugin-dep injection pull in a plugin's full transitive
// closure (e.g. maven-jar-plugin -> maven-archiver -> plexus-utils ...), which varies
// across plugin/Maven versions. Suppress the count assertion when requested.
if testCase.skipPackageCount {
for key := range results {
result := results[key]
result.totalNumberOfPackages = 0
}
}
assert.Equal(t, testCase.expectedResp, results)
for _, requestDone := range testCase.expectedRequest {
assert.True(t, requestDone)
Expand Down Expand Up @@ -623,6 +633,13 @@ type testCase struct {
tech techutils.Technology
createServerWithoutCreds bool
allowInsecureTls bool
// mvnIncludePluginDeps wires the --mvn-include-plugin-deps CLI flag into the curation
// audit command so the test exercises Maven build-plugin transitive dep collection.
mvnIncludePluginDeps bool
// skipPackageCount tells validateCurationResults to ignore totalNumberOfPackages.
// Use for cases where the count depends on a Maven plugin's transitive closure
// (e.g. maven-jar-plugin) and would otherwise be brittle across Maven/plugin versions.
skipPackageCount bool
}

func (tc testCase) getPathToTests() string {
Expand Down Expand Up @@ -876,6 +893,70 @@ func getTestCasesForDoCurationAudit() []testCase {
},
allowInsecureTls: true,
},
{
// Regression coverage for --mvn-include-plugin-deps. The customer scenario was a
// build that downloaded a curated artifact only via a Maven build-plugin's transitive
// closure; `jf ca` would report "0 blocked" because mvn dependency:tree never sees
// plugin deps. The test pom pins maven-jar-plugin to 3.4.1, whose fixed transitive
// closure includes org.ow2.asm:asm:9.8 (via plexus-archiver:4.9.2). The mock server
// blocks that exact jar URL. With the flag on, the curation audit must resolve plugin
// deps, inject asm into the tree, and surface it as blocked.
name: "maven tree - one blocked plugin dependency",
tech: techutils.Maven,
pathToProject: filepath.Join("projects", "package-managers", "maven", "maven-curation-plugin-deps"),
pathToTest: "test",
pathToPreTest: "pretest",
preTestExec: "mvn",
funcToGetGoals: func(t *testing.T) []string {
// Curation cache is keyed off the project directory — compute it from the
// test/ dir (where the real test will run) so pretest writes into the same
// folder that the test phase reads. Mirrors the maven-curation case above.
cleanUpTestDirChange := testUtils.ChangeWDWithCallback(t, filepath.Join("..", "test"))
curationCache, err := utils.GetCurationCacheFolderByTech(techutils.Maven.String())
require.NoError(t, err)
cleanUpTestDirChange()
// One mvn invocation, multiple goals: maven-dep-tree:tree primes the project
// dep cache; dependency:resolve-plugins and help:effective-pom pre-download
// the plugins that resolvePluginDeps()/resolveInstallLifecyclePlugins() will
// re-run during the test phase against the mock server.
return []string{
"com.jfrog:maven-dep-tree:" + java.GetMavenDepTreeVersion() + ":tree",
"-DdepsTreeOutputFile=output",
"-Dmaven.repo.local=" + curationCache,
"dependency:resolve-plugins",
"help:effective-pom",
}
},
mvnIncludePluginDeps: true,
// The full plugin closure depends on the runner's ambient Maven plugin versions;
// only asm:9.8 (pinned via maven-jar-plugin:3.4.1) is deterministic, so we assert
// just that blocked package and skip the non-deterministic total count.
skipPackageCount: true,
requestToFail: map[string]bool{
"/maven-remote/org/ow2/asm/asm/9.8/asm-9.8.jar": false,
},
expectedResp: map[string]*CurationReport{
"test:plugin-dep-app:1.0.0": {packagesStatus: []*PackageStatus{
{
Action: "blocked",
ParentVersion: "9.8",
ParentName: "org.ow2.asm:asm",
BlockedPackageUrl: "/maven-remote/org/ow2/asm/asm/9.8/asm-9.8.jar",
PackageName: "org.ow2.asm:asm",
PackageVersion: "9.8",
BlockingReason: "Policy violations",
PkgType: "maven",
DepRelation: "direct",
Policy: []Policy{
{
Policy: "pol1",
Condition: "cond1",
},
},
},
}},
},
},
{
name: "maven tree - one blocked package",
tech: techutils.Maven,
Expand Down
1 change: 1 addition & 0 deletions sca/bom/buildinfo/buildinfobom.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ func GetTechDependencyTree(params technologies.BuildInfoBomGeneratorParams, arti
IsMavenDepTreeInstalled: params.IsMavenDepTreeInstalled,
UseWrapper: params.UseWrapper,
IsCurationCmd: params.IsCurationCmd,
MvnIncludePluginDeps: params.MvnIncludePluginDeps,
CurationCacheFolder: curationCacheFolder,
UseIncludedBuilds: params.UseIncludedBuilds,
}, tech)
Expand Down
5 changes: 3 additions & 2 deletions sca/bom/buildinfo/technologies/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ type BuildInfoBomGeneratorParams struct {
Args []string
InstallCommandArgs []string
// Curation params
IsCurationCmd bool
ParallelRequests int
IsCurationCmd bool
MvnIncludePluginDeps bool
ParallelRequests int
// OutputFormat is the --format flag value forwarded from the curation command.
// The zero value is treated as outFormat.Table by all renderers.
// Set by curation commands only; generic audit/scan commands leave this unset.
Expand Down
1 change: 1 addition & 0 deletions sca/bom/buildinfo/technologies/java/deptreemanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type DepTreeParams struct {
DepsRepo string
IsMavenDepTreeInstalled bool
IsCurationCmd bool
MvnIncludePluginDeps bool
CurationCacheFolder string
UseIncludedBuilds bool
}
Expand Down
Loading
Loading