From 706d66b227bc47974a49eeb16cbf33b2fddce15b Mon Sep 17 00:00:00 2001 From: anjali-deore <200181980+cx-anjali-deore@users.noreply.github.com> Date: Thu, 12 Mar 2026 18:39:36 +0530 Subject: [PATCH 1/4] - Fixed the issue of lockVersion --- internal/parsers/npm/package_json_parser.go | 55 ++++++++++++++++++- .../parsers/npm/package_json_parser_test.go | 43 +++++++++++++++ 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/internal/parsers/npm/package_json_parser.go b/internal/parsers/npm/package_json_parser.go index 99430c9..be94102 100644 --- a/internal/parsers/npm/package_json_parser.go +++ b/internal/parsers/npm/package_json_parser.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" "sort" + "strconv" "strings" "github.com/Checkmarx/manifest-parser/pkg/parser/models" @@ -202,7 +203,7 @@ func getResolvedVersion(name, specVersion string, lock lockFile) string { // Try v1 format first if deps := lock.Dependencies; deps != nil { - if entry, ok := deps[name]; ok && entry.Version != "" { + if entry, ok := deps[name]; ok && entry.Version != "" && isLockVersionGreater(specVersion, entry.Version) { return entry.Version } } @@ -215,11 +216,10 @@ func getResolvedVersion(name, specVersion string, lock lockFile) string { "node_modules/" + name + "@" + specVersion, "node_modules/" + name + "@" + strings.TrimPrefix(specVersion, "^"), "node_modules/" + name + "@" + strings.TrimPrefix(specVersion, "~"), - "", // Root package } for _, path := range pathVariations { - if entry, ok := pkgs[path]; ok && entry.Version != "" { + if entry, ok := pkgs[path]; ok && entry.Version != "" && isLockVersionGreater(specVersion, entry.Version) { return entry.Version } } @@ -237,3 +237,52 @@ func getResolvedVersion(name, specVersion string, lock lockFile) string { // Otherwise return the specified version return specVersion } +func isLockVersionGreater(specVersion, lockVersion string) bool { + specVersion = stripRangeSpecifier(specVersion) + lockVersion = stripRangeSpecifier(lockVersion) + + specParts := strings.Split(specVersion, ".") + lockParts := strings.Split(lockVersion, ".") + + maxLen := len(specParts) + if len(lockParts) > maxLen { + maxLen = len(lockParts) + } + for i := 0; i < maxLen; i++ { + var specPart, lockPart int + if i < len(specParts) { + specPart, _ = strconv.Atoi(specParts[i]) + } + if i < len(lockParts) { + lockPart, _ = strconv.Atoi(lockParts[i]) + } + if lockPart == specPart { + continue + } + if lockPart > specPart { + return true + } else if lockPart < specPart { + return false + } + } + // In case if the lock version is same as the spec version, we consider it + // in case of range specifiers , lock file can also have same version if not greater + return true +} + +func stripRangeSpecifier(version string) string { + if checkRangeSpecifiersPresent(version) { + return version[1:] + } + return version +} +func checkRangeSpecifiersPresent(version string) bool { + if strings.HasPrefix(version, "^") || + strings.HasPrefix(version, "~") || + strings.Contains(version, "*") || + strings.Contains(version, ">") || + strings.Contains(version, "<") { + return true + } + return false +} diff --git a/internal/parsers/npm/package_json_parser_test.go b/internal/parsers/npm/package_json_parser_test.go index ab307f7..145016f 100644 --- a/internal/parsers/npm/package_json_parser_test.go +++ b/internal/parsers/npm/package_json_parser_test.go @@ -701,3 +701,46 @@ func TestSectionAwareParsing(t *testing.T) { t.Errorf("expected %d packages, got %d", expectedCount, len(packages)) } } + +// TestGetResolvedVersionComparisonWithLock tests comparison logic between package.json spec and package-lock.json +func TestGetResolvedVersionComparisonWithLock(t *testing.T) { + // Create a lock file JSON with various scenarios: + // - foo: same version as spec (should return lock version) + // - bar: lock version smaller than spec (should return "latest") + // - baz: lock version greater than spec (should return lock version) + // - missing: not present in lock (should return "latest") + lockJSON := `{ + "lockfileVersion": 2, + "packages": { + "node_modules/foo": { "version": "1.2.3" }, + "node_modules/bar": { "version": "1.2.2" }, + "node_modules/baz": { "version": "2.0.0" } + } + }` + + var lock lockFile + if err := json.Unmarshal([]byte(lockJSON), &lock); err != nil { + t.Fatalf("failed to unmarshal lock JSON: %v", err) + } + + tests := []struct { + name string + pkg string + spec string + expected string + }{ + {"lock equal to spec", "foo", "^1.2.3", "1.2.3"}, + {"lock smaller than spec", "bar", "^1.2.3", "latest"}, + {"lock greater than spec", "baz", "^1.2.0", "2.0.0"}, + {"lock missing", "missing", "^3.0.0", "latest"}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + res := getResolvedVersion(tc.pkg, tc.spec, lock) + if res != tc.expected { + t.Fatalf("expected %q for %s, got %q", tc.expected, tc.pkg, res) + } + }) + } +} From 73a476d5859669acfefde826156b6d7d942ccdcf Mon Sep 17 00:00:00 2001 From: anjali-deore <200181980+cx-anjali-deore@users.noreply.github.com> Date: Thu, 12 Mar 2026 18:43:52 +0530 Subject: [PATCH 2/4] - Fixed comment --- internal/parsers/npm/package_json_parser.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/parsers/npm/package_json_parser.go b/internal/parsers/npm/package_json_parser.go index be94102..2bda92e 100644 --- a/internal/parsers/npm/package_json_parser.go +++ b/internal/parsers/npm/package_json_parser.go @@ -265,8 +265,8 @@ func isLockVersionGreater(specVersion, lockVersion string) bool { return false } } - // In case if the lock version is same as the spec version, we consider it - // in case of range specifiers , lock file can also have same version if not greater + // In case if the lock version is same as the spec version, we consider it, + // as range specifiers indicate version greaterThan or equalTo return true } From 3ec12ec91cee53053db440f41fdf79d867281b42 Mon Sep 17 00:00:00 2001 From: anjali-deore <200181980+cx-anjali-deore@users.noreply.github.com> Date: Thu, 12 Mar 2026 23:11:09 +0530 Subject: [PATCH 3/4] - replaces duplicate code with ,method --- internal/parsers/npm/package_json_parser.go | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/internal/parsers/npm/package_json_parser.go b/internal/parsers/npm/package_json_parser.go index 2bda92e..0398820 100644 --- a/internal/parsers/npm/package_json_parser.go +++ b/internal/parsers/npm/package_json_parser.go @@ -192,12 +192,8 @@ func (p *NpmPackageJsonParser) Parse(manifestFile string) ([]models.Package, err // - Falls back to sensible defaults if necessary func getResolvedVersion(name, specVersion string, lock lockFile) string { // Check if version is already exact - if so, return it directly - if !strings.HasPrefix(specVersion, "^") && - !strings.HasPrefix(specVersion, "~") && - !strings.Contains(specVersion, "*") && - !strings.Contains(specVersion, ">") && - !strings.Contains(specVersion, "<") && - !strings.Contains(specVersion, "latest") { + + if !checkRangeSpecifiersPresent(specVersion) && !strings.Contains(specVersion, "latest") { return specVersion } @@ -226,14 +222,10 @@ func getResolvedVersion(name, specVersion string, lock lockFile) string { } // For version specifiers, return "latest" as fallback - if strings.HasPrefix(specVersion, "^") || - strings.HasPrefix(specVersion, "~") || - strings.Contains(specVersion, "*") || - strings.Contains(specVersion, ">") || - strings.Contains(specVersion, "<") { + + if checkRangeSpecifiersPresent(specVersion) { return "latest" } - // Otherwise return the specified version return specVersion } From a11b07740d416de88e780eef831aa3f135a0395a Mon Sep 17 00:00:00 2001 From: anjali-deore <200181980+cx-anjali-deore@users.noreply.github.com> Date: Mon, 16 Mar 2026 10:35:36 +0530 Subject: [PATCH 4/4] - Updated SHA of cx-one scan yaml --- .github/workflows/cxone-scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cxone-scan.yml b/.github/workflows/cxone-scan.yml index 528a2bc..390d959 100644 --- a/.github/workflows/cxone-scan.yml +++ b/.github/workflows/cxone-scan.yml @@ -16,7 +16,7 @@ jobs: - name: Checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Checkmarx One Scan - uses: checkmarx/ast-github-action@f0869bd1a37fddc06499a096101e6c900e815d81 # v.2.0.36 + uses: checkmarx/ast-github-action@327efb5d1dd16ac6c7c21a9ff8ec1e8ec393b5e6 # v.2.3.46 with: base_uri: ${{ secrets.AST_RND_SCANS_BASE_URI }} cx_tenant: ${{ secrets.AST_RND_SCANS_TENANT }}