diff --git a/artifactory_test.go b/artifactory_test.go index 26df2789..2861e13b 100644 --- a/artifactory_test.go +++ b/artifactory_test.go @@ -2,12 +2,14 @@ package main import ( "errors" - "github.com/stretchr/testify/require" + "fmt" "os" "os/exec" "path/filepath" "testing" + "github.com/stretchr/testify/require" + "github.com/jfrog/jfrog-cli-core/v2/utils/dependencies" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" @@ -45,6 +47,12 @@ func TestDependencyResolutionFromArtifactory(t *testing.T) { cacheRepoName: securityTests.NpmRemoteRepo, projectType: project.Npm, }, + { + testProjectPath: []string{"npm", "npm-no-lock"}, + resolveRepoName: securityTests.PnpmRemoteRepo, + cacheRepoName: securityTests.PnpmRemoteRepo, + projectType: project.Pnpm, + }, { testProjectPath: []string{"dotnet", "dotnet-single"}, resolveRepoName: securityTests.NugetRemoteRepo, @@ -145,7 +153,7 @@ func testSingleTechDependencyResolution(t *testing.T, testProjectPartialPath []s } // Executing the 'audit' command on an uninstalled project, we anticipate the resolution of dependencies from the configured Artifactory server and repository. - assert.NoError(t, securityTests.PlatformCli.WithoutCredentials().Exec("audit")) + assert.NoError(t, securityTests.PlatformCli.WithoutCredentials().Exec("audit", fmt.Sprintf("--%s", projectType.String()))) // Following resolution from Artifactory, we anticipate the repository's cache to contain data. output := coreTests.RunCmdWithOutput(t, func() error { diff --git a/commands/audit/sca/npm/npm.go b/commands/audit/sca/npm/npm.go index 00478a7a..0fc73f78 100644 --- a/commands/audit/sca/npm/npm.go +++ b/commands/audit/sca/npm/npm.go @@ -35,7 +35,7 @@ func BuildDependencyTree(params utils.AuditParams) (dependencyTrees []*xrayUtils treeDepsParam := createTreeDepsParam(params) - clearResolutionServerFunc, err := configNpmResolutionServerIfNeeded(params) + clearResolutionServerFunc, err := ConfigNpmResolutionServerIfNeeded(params) if err != nil { err = fmt.Errorf("failed while configuring a resolution server: %s", err.Error()) return @@ -63,7 +63,7 @@ func BuildDependencyTree(params utils.AuditParams) (dependencyTrees []*xrayUtils } // Generates a .npmrc file to configure an Artifactory server as the resolver server. -func configNpmResolutionServerIfNeeded(params utils.AuditParams) (clearResolutionServerFunc func() error, err error) { +func ConfigNpmResolutionServerIfNeeded(params utils.AuditParams) (clearResolutionServerFunc func() error, err error) { // If we don't have an artifactory repo's name we don't need to configure any Artifactory server as resolution server if params.DepsRepo() == "" { return diff --git a/commands/audit/sca/pnpm/pnpm.go b/commands/audit/sca/pnpm/pnpm.go index b254baee..f3039a5e 100644 --- a/commands/audit/sca/pnpm/pnpm.go +++ b/commands/audit/sca/pnpm/pnpm.go @@ -3,6 +3,7 @@ package pnpm import ( "encoding/json" "errors" + "fmt" "os/exec" "path/filepath" @@ -45,6 +46,16 @@ func BuildDependencyTree(params utils.AuditParams) (dependencyTrees []*xrayUtils if err != nil { return } + clearResolutionServerFunc, err := npm.ConfigNpmResolutionServerIfNeeded(params) + if err != nil { + err = fmt.Errorf("failed while configuring a resolution server: %s", err.Error()) + return + } + defer func() { + if clearResolutionServerFunc != nil { + err = errors.Join(err, clearResolutionServerFunc()) + } + }() // Build if err = installProjectIfNeeded(pnpmExecPath, currentDir); errorutils.CheckError(err) != nil { return diff --git a/tests/consts.go b/tests/consts.go index 2b39678b..d53789c4 100644 --- a/tests/consts.go +++ b/tests/consts.go @@ -36,6 +36,7 @@ var ( DockerLocalRepo = "cli-docker-local" DockerRemoteRepo = "cli-docker-remote" NpmRemoteRepo = "cli-npm-remote" + PnpmRemoteRepo = "cli-pnpm-remote" NugetRemoteRepo = "cli-nuget-remote" YarnRemoteRepo = "cli-yarn-remote" GradleRemoteRepo = "cli-gradle-remote" @@ -52,6 +53,7 @@ const ( DockerLocalRepositoryConfig = "docker_local_repository_config.json" DockerRemoteRepositoryConfig = "docker_remote_repository_config.json" NpmRemoteRepositoryConfig = "npm_remote_repository_config.json" + PnpmRemoteRepositoryConfig = "pnpm_remote_repository_config.json" NugetRemoteRepositoryConfig = "nuget_remote_repository_config.json" YarnRemoteRepositoryConfig = "yarn_remote_repository_config.json" GradleRemoteRepositoryConfig = "gradle_remote_repository_config.json" @@ -73,6 +75,7 @@ var reposConfigMap = map[*string]string{ &DockerLocalRepo: DockerLocalRepositoryConfig, &DockerRemoteRepo: DockerRemoteRepositoryConfig, &NpmRemoteRepo: NpmRemoteRepositoryConfig, + &PnpmRemoteRepo: PnpmRemoteRepositoryConfig, &NugetRemoteRepo: NugetRemoteRepositoryConfig, &YarnRemoteRepo: YarnRemoteRepositoryConfig, &GradleRemoteRepo: GradleRemoteRepositoryConfig, @@ -87,7 +90,7 @@ var reposConfigMap = map[*string]string{ func GetNonVirtualRepositories() map[*string]string { nonVirtualReposMap := map[*bool][]*string{ TestDockerScan: {&DockerLocalRepo, &DockerRemoteRepo}, - TestSecurity: {&NpmRemoteRepo, &NugetRemoteRepo, &YarnRemoteRepo, &GradleRemoteRepo, &MvnRemoteRepo, &GoRepo, &GoRemoteRepo, &PypiRemoteRepo}, + TestSecurity: {&NpmRemoteRepo, &PnpmRemoteRepo, &NugetRemoteRepo, &YarnRemoteRepo, &GradleRemoteRepo, &MvnRemoteRepo, &GoRepo, &GoRemoteRepo, &PypiRemoteRepo}, } return getNeededRepositories(nonVirtualReposMap) } @@ -151,6 +154,7 @@ func AddTimestampToGlobalVars() { GradleRemoteRepo += uniqueSuffix MvnRemoteRepo += uniqueSuffix NpmRemoteRepo += uniqueSuffix + PnpmRemoteRepo += uniqueSuffix NugetRemoteRepo += uniqueSuffix YarnRemoteRepo += uniqueSuffix PypiRemoteRepo += uniqueSuffix @@ -175,6 +179,7 @@ func GetSubstitutionMap() map[string]string { "${GRADLE_REMOTE_REPO}": GradleRemoteRepo, "${MAVEN_REMOTE_REPO}": MvnRemoteRepo, "${NPM_REMOTE_REPO}": NpmRemoteRepo, + "${PNPM_REMOTE_REPO}": PnpmRemoteRepo, "${NUGET_REMOTE_REPO}": NugetRemoteRepo, "${PYPI_REMOTE_REPO}": PypiRemoteRepo, "${YARN_REMOTE_REPO}": YarnRemoteRepo, diff --git a/tests/testdata/artifactory-repo-configs/pnpm_remote_repository_config.json b/tests/testdata/artifactory-repo-configs/pnpm_remote_repository_config.json new file mode 100644 index 00000000..dc7057f3 --- /dev/null +++ b/tests/testdata/artifactory-repo-configs/pnpm_remote_repository_config.json @@ -0,0 +1,6 @@ +{ + "key": "${PNPM_REMOTE_REPO}", + "rclass": "remote", + "packageType": "npm", + "url": "https://registry.npmjs.org" +}