From 01396c12434f885aec4739bdcf880439f6390d32 Mon Sep 17 00:00:00 2001 From: Manav sethi <mail@manav.co.in> Date: Tue, 14 Jan 2025 15:23:12 +0530 Subject: [PATCH] Minor bugfix to handle cases where the package name doesn't resolve properly (#305) * Minor bugfix to handle cases where the package name doesn't resolve to a proper URL * Remove accidental changes * PR review fixes * Pass the trustedURLs directly instead of ignoring the npm configured URL * Updated the test cases --- pkg/analyzer/lfp_npm.go | 38 +++++++++++++++++++++--------------- pkg/analyzer/lfp_npm_test.go | 9 ++++++++- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/pkg/analyzer/lfp_npm.go b/pkg/analyzer/lfp_npm.go index 1577dfc2..ca8c7604 100644 --- a/pkg/analyzer/lfp_npm.go +++ b/pkg/analyzer/lfp_npm.go @@ -115,7 +115,7 @@ func (npm *npmLockfilePoisoningAnalyzer) Analyze(manifest *models.PackageManifes trustedRegistryUrls := []string{npmRegistryTrustedUrlBase} trustedRegistryUrls = append(trustedRegistryUrls, npm.config.TrustedRegistryUrls...) - + userTrustUrls := npm.config.TrustedRegistryUrls logger.Debugf("npmLockfilePoisoningAnalyzer: Analyzing package [%s] with %d trusted registry URLs in config", packageName, len(trustedRegistryUrls)) @@ -147,7 +147,7 @@ func (npm *npmLockfilePoisoningAnalyzer) Analyze(manifest *models.PackageManifes }) } - if !npmIsUrlFollowsPathConvention(lockfilePackage.Resolved, packageName, trustedRegistryUrls) { + if !npmIsUrlFollowsPathConvention(lockfilePackage.Resolved, packageName, trustedRegistryUrls, userTrustUrls) { logger.Debugf("npmLockfilePoisoningAnalyzer: Package [%s] resolved to an unconventional URL [%s]", packageName, lockfilePackage.Resolved) @@ -247,12 +247,11 @@ func npmNodeModulesPackagePathToName(path string) string { // Test if URL follows the pkg name path convention as per NPM package registry // specification https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json -func npmIsUrlFollowsPathConvention(sourceUrl string, pkg string, trustedUrls []string) bool { - // Example: https://registry.npmjs.org/express/-/express-4.17.1.tgz +func npmIsUrlFollowsPathConvention(sourceUrl string, pkg string, trustedUrls []string, userTrustedUrls []string) bool { + // Parse the source URL parsedUrl, err := npmParseSourceUrl(sourceUrl) if err != nil { - logger.Errorf("npmIsUrlFollowsPathConvention: Failed to parse URL %s: %v", - sourceUrl, err) + logger.Errorf("npmIsUrlFollowsPathConvention: Failed to parse URL %s: %v", sourceUrl, err) return false } @@ -265,25 +264,32 @@ func npmIsUrlFollowsPathConvention(sourceUrl string, pkg string, trustedUrls []s path = path[1:] } + // Build a list of acceptable package names acceptablePackageNames := []string{pkg} for _, trustedUrl := range trustedUrls { parsedTrustedUrl, err := npmParseSourceUrl(trustedUrl) if err != nil { - logger.Errorf("npmIsUrlFollowsPathConvention: Failed to parse trusted URL %s: %v", - trustedUrl, err) + logger.Errorf("npmIsUrlFollowsPathConvention: Failed to parse trusted URL %s: %v", trustedUrl, err) continue } - trustedBase := parsedTrustedUrl.Path - trustedBase = strings.TrimPrefix(trustedBase, "/") - trustedBase = strings.TrimSuffix(trustedBase, "/") - - acceptablePackageNames = append(acceptablePackageNames, - fmt.Sprintf("%s/%s", trustedBase, pkg)) + trustedBase := strings.Trim(parsedTrustedUrl.Path, "/") + acceptablePackageNames = append(acceptablePackageNames, fmt.Sprintf("%s/%s", trustedBase, pkg)) } - // Example: @angular/core from https://registry.npmjs.org/@angular/core/-/core-1.0.0.tgz + // Extract the scoped package name scopedPackageName := strings.Split(path, "/-/")[0] + if slices.Contains(acceptablePackageNames, scopedPackageName) { + return true + } - return slices.Contains(acceptablePackageNames, scopedPackageName) + // Check if the source URL starts with any trusted URL except the NPM trusted base URL + for _, trustedUrl := range userTrustedUrls { + if strings.HasPrefix(sourceUrl, trustedUrl) { + return true + } + } + + // Default fallback + return false } diff --git a/pkg/analyzer/lfp_npm_test.go b/pkg/analyzer/lfp_npm_test.go index d5cee319..c32e5373 100644 --- a/pkg/analyzer/lfp_npm_test.go +++ b/pkg/analyzer/lfp_npm_test.go @@ -160,11 +160,18 @@ func TestNpmIsUrlFollowsPathConvention(t *testing.T) { []string{"https://registry.npmjs.org/base", "https://registry.npmjs.org/base1"}, true, }, + { + "strip_ansi_cjs package path matches trusted url path", + "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "strip-ansi-cjs", + []string{"https://registry.npmjs.org/strip-ansi"}, + true, + }, } for _, test := range cases { t.Run(test.name, func(t *testing.T) { - actual := npmIsUrlFollowsPathConvention(test.url, test.pkgName, test.trustedUrls) + actual := npmIsUrlFollowsPathConvention(test.url, test.pkgName, test.trustedUrls, test.trustedUrls) assert.Equal(t, test.expected, actual) }) }