From 865be0a317ad5d529b94f3b4627d478117dfe2d1 Mon Sep 17 00:00:00 2001 From: Mor Samouchian Date: Sun, 23 Nov 2025 14:58:24 +0200 Subject: [PATCH 1/7] CM-55551 CLI SCA Scan Fails to Detect Indirect Dependencies Due to PNPM Lock File Handling --- cycode/cli/files_collector/sca/base_restore_dependencies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cycode/cli/files_collector/sca/base_restore_dependencies.py b/cycode/cli/files_collector/sca/base_restore_dependencies.py index de409f05..e2ad72ba 100644 --- a/cycode/cli/files_collector/sca/base_restore_dependencies.py +++ b/cycode/cli/files_collector/sca/base_restore_dependencies.py @@ -55,7 +55,7 @@ def get_manifest_file_path(self, document: Document) -> str: join_paths(get_path_from_context(self.ctx), document.path) if self.ctx.obj.get('monitor') else document.path ) - def try_restore_dependencies(self, document: Document) -> Optional[Document]: + def try_restore_dependencies(self, document: Document) -> Optional[Document]: manifest_file_path = self.get_manifest_file_path(document) restore_file_path = build_dep_tree_path(document.absolute_path, self.get_lock_file_name()) relative_restore_file_path = build_dep_tree_path(document.path, self.get_lock_file_name()) From 6c8ebdfdd57cc14cf6ba8cfd4a26fac4032e1cb1 Mon Sep 17 00:00:00 2001 From: Mor Samouchian Date: Sun, 23 Nov 2025 15:02:38 +0200 Subject: [PATCH 2/7] CM-55551 CLI SCA Scan Fails to Detect Indirect Dependencies Due to PNPM Lock File Handling --- .../sca/base_restore_dependencies.py | 28 +++++++++++++++---- .../sca/go/restore_go_dependencies.py | 3 ++ .../sca/maven/restore_gradle_dependencies.py | 3 ++ .../sca/maven/restore_maven_dependencies.py | 3 ++ .../sca/npm/restore_npm_dependencies.py | 12 ++++++++ .../sca/nuget/restore_nuget_dependencies.py | 3 ++ .../sca/ruby/restore_ruby_dependencies.py | 3 ++ .../sca/sbt/restore_sbt_dependencies.py | 3 ++ 8 files changed, 52 insertions(+), 6 deletions(-) diff --git a/cycode/cli/files_collector/sca/base_restore_dependencies.py b/cycode/cli/files_collector/sca/base_restore_dependencies.py index e2ad72ba..0cabc6f8 100644 --- a/cycode/cli/files_collector/sca/base_restore_dependencies.py +++ b/cycode/cli/files_collector/sca/base_restore_dependencies.py @@ -55,12 +55,13 @@ def get_manifest_file_path(self, document: Document) -> str: join_paths(get_path_from_context(self.ctx), document.path) if self.ctx.obj.get('monitor') else document.path ) - def try_restore_dependencies(self, document: Document) -> Optional[Document]: + def try_restore_dependencies(self, document: Document) -> Optional[Document]: manifest_file_path = self.get_manifest_file_path(document) - restore_file_path = build_dep_tree_path(document.absolute_path, self.get_lock_file_name()) - relative_restore_file_path = build_dep_tree_path(document.path, self.get_lock_file_name()) + restore_file_paths = [build_dep_tree_path(document.absolute_path, restore_file_path_item) for restore_file_path_item in self.get_lock_file_names()] + restore_file_path = self.get_any_restore_file_already_exist(restore_file_paths) + relative_restore_file_path = build_dep_tree_path(document.path, self.get_restored_lock_file_name(restore_file_path)) - if not self.verify_restore_file_already_exist(restore_file_path): + if self.verify_lockfile_missing(restore_file_path): output = execute_commands( commands=self.get_commands(manifest_file_path), timeout=self.command_timeout, @@ -75,10 +76,21 @@ def try_restore_dependencies(self, document: Document) -> Optional[Document]: def get_working_directory(self, document: Document) -> Optional[str]: return os.path.dirname(document.absolute_path) + + def get_restored_lock_file_name(self, restore_file_path: str) -> str: + return self.get_lock_file_name() + + @staticmethod + def get_any_restore_file_already_exist(restore_file_paths: list[str]) -> Optional[str]: + for restore_file_path in restore_file_paths: + if os.path.isfile(restore_file_path): + return restore_file_path + + return None @staticmethod - def verify_restore_file_already_exist(restore_file_path: str) -> bool: - return os.path.isfile(restore_file_path) + def verify_lockfile_missing(restore_file_path: Optional[str]) -> bool: + return restore_file_path is None @abstractmethod def is_project(self, document: Document) -> bool: @@ -91,3 +103,7 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: @abstractmethod def get_lock_file_name(self) -> str: pass + + @abstractmethod + def get_lock_file_names(self) -> list[str]: + pass diff --git a/cycode/cli/files_collector/sca/go/restore_go_dependencies.py b/cycode/cli/files_collector/sca/go/restore_go_dependencies.py index 156b0cc0..6f9713ba 100644 --- a/cycode/cli/files_collector/sca/go/restore_go_dependencies.py +++ b/cycode/cli/files_collector/sca/go/restore_go_dependencies.py @@ -43,3 +43,6 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: def get_lock_file_name(self) -> str: return GO_RESTORE_FILE_NAME + + def get_lock_file_names(self) -> str: + return [self.get_lock_file_name()] diff --git a/cycode/cli/files_collector/sca/maven/restore_gradle_dependencies.py b/cycode/cli/files_collector/sca/maven/restore_gradle_dependencies.py index 75e1e8f7..27a6f991 100644 --- a/cycode/cli/files_collector/sca/maven/restore_gradle_dependencies.py +++ b/cycode/cli/files_collector/sca/maven/restore_gradle_dependencies.py @@ -40,6 +40,9 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: def get_lock_file_name(self) -> str: return BUILD_GRADLE_DEP_TREE_FILE_NAME + + def get_lock_file_names(self) -> str: + return [self.get_lock_file_name()] def get_working_directory(self, document: Document) -> Optional[str]: return get_path_from_context(self.ctx) if self.is_gradle_sub_projects() else None diff --git a/cycode/cli/files_collector/sca/maven/restore_maven_dependencies.py b/cycode/cli/files_collector/sca/maven/restore_maven_dependencies.py index 51c91aa9..2f618fac 100644 --- a/cycode/cli/files_collector/sca/maven/restore_maven_dependencies.py +++ b/cycode/cli/files_collector/sca/maven/restore_maven_dependencies.py @@ -33,6 +33,9 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: def get_lock_file_name(self) -> str: return join_paths('target', MAVEN_CYCLONE_DEP_TREE_FILE_NAME) + + def get_lock_file_names(self) -> str: + return [self.get_lock_file_name()] def try_restore_dependencies(self, document: Document) -> Optional[Document]: manifest_file_path = self.get_manifest_file_path(document) diff --git a/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py b/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py index 2563612f..92fa9e88 100644 --- a/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py +++ b/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py @@ -7,6 +7,12 @@ NPM_PROJECT_FILE_EXTENSIONS = ['.json'] NPM_LOCK_FILE_NAME = 'package-lock.json' +NPM_LOCK_FILE_NAMES = [ + NPM_LOCK_FILE_NAME, + 'yarn.lock', + 'pnpm-lock.yaml', + 'deno.lock' +] NPM_MANIFEST_FILE_NAME = 'package.json' @@ -29,9 +35,15 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: '--no-audit', ] ] + + def get_restored_lock_file_name(self, restore_file_path: str) -> str: + return NPM_LOCK_FILE_NAME if restore_file_path is None else os.path.basename(restore_file_path) def get_lock_file_name(self) -> str: return NPM_LOCK_FILE_NAME + + def get_lock_file_names(self) -> str: + return NPM_LOCK_FILE_NAMES @staticmethod def prepare_manifest_file_path_for_command(manifest_file_path: str) -> str: diff --git a/cycode/cli/files_collector/sca/nuget/restore_nuget_dependencies.py b/cycode/cli/files_collector/sca/nuget/restore_nuget_dependencies.py index 3035e206..d91f1691 100644 --- a/cycode/cli/files_collector/sca/nuget/restore_nuget_dependencies.py +++ b/cycode/cli/files_collector/sca/nuget/restore_nuget_dependencies.py @@ -19,3 +19,6 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: def get_lock_file_name(self) -> str: return NUGET_LOCK_FILE_NAME + + def get_lock_file_names(self) -> str: + return [self.get_lock_file_name()] diff --git a/cycode/cli/files_collector/sca/ruby/restore_ruby_dependencies.py b/cycode/cli/files_collector/sca/ruby/restore_ruby_dependencies.py index fb4a7771..bde59724 100644 --- a/cycode/cli/files_collector/sca/ruby/restore_ruby_dependencies.py +++ b/cycode/cli/files_collector/sca/ruby/restore_ruby_dependencies.py @@ -14,3 +14,6 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: def get_lock_file_name(self) -> str: return RUBY_LOCK_FILE_NAME + + def get_lock_file_names(self) -> str: + return [self.get_lock_file_name()] diff --git a/cycode/cli/files_collector/sca/sbt/restore_sbt_dependencies.py b/cycode/cli/files_collector/sca/sbt/restore_sbt_dependencies.py index 4f4bbd5a..04655047 100644 --- a/cycode/cli/files_collector/sca/sbt/restore_sbt_dependencies.py +++ b/cycode/cli/files_collector/sca/sbt/restore_sbt_dependencies.py @@ -14,3 +14,6 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: def get_lock_file_name(self) -> str: return SBT_LOCK_FILE_NAME + + def get_lock_file_names(self) -> str: + return [self.get_lock_file_name()] From 5e9883d5b041733feaa0a5c340cb9260bd098340 Mon Sep 17 00:00:00 2001 From: Mor Samouchian Date: Sun, 23 Nov 2025 16:12:12 +0200 Subject: [PATCH 3/7] CM-55551 CLI SCA Scan Fails to Detect Indirect Dependencies Due to PNPM Lock File Handling --- .../sca/base_restore_dependencies.py | 24 ++++++++++--------- .../sca/go/restore_go_dependencies.py | 2 +- .../sca/maven/restore_gradle_dependencies.py | 2 +- .../sca/maven/restore_maven_dependencies.py | 2 +- .../sca/npm/restore_npm_dependencies.py | 4 ++-- .../sca/nuget/restore_nuget_dependencies.py | 2 +- .../sca/ruby/restore_ruby_dependencies.py | 2 +- .../sca/sbt/restore_sbt_dependencies.py | 2 +- 8 files changed, 21 insertions(+), 19 deletions(-) diff --git a/cycode/cli/files_collector/sca/base_restore_dependencies.py b/cycode/cli/files_collector/sca/base_restore_dependencies.py index 0cabc6f8..9a71ef47 100644 --- a/cycode/cli/files_collector/sca/base_restore_dependencies.py +++ b/cycode/cli/files_collector/sca/base_restore_dependencies.py @@ -14,10 +14,10 @@ def build_dep_tree_path(path: str, generated_file_name: str) -> str: def execute_commands( - commands: list[list[str]], - timeout: int, - output_file_path: Optional[str] = None, - working_directory: Optional[str] = None, + commands: list[list[str]], + timeout: int, + output_file_path: Optional[str] = None, + working_directory: Optional[str] = None, ) -> Optional[str]: try: outputs = [] @@ -40,7 +40,7 @@ def execute_commands( class BaseRestoreDependencies(ABC): def __init__( - self, ctx: typer.Context, is_git_diff: bool, command_timeout: int, create_output_file_manually: bool = False + self, ctx: typer.Context, is_git_diff: bool, command_timeout: int, create_output_file_manually: bool = False ) -> None: self.ctx = ctx self.is_git_diff = is_git_diff @@ -57,9 +57,11 @@ def get_manifest_file_path(self, document: Document) -> str: def try_restore_dependencies(self, document: Document) -> Optional[Document]: manifest_file_path = self.get_manifest_file_path(document) - restore_file_paths = [build_dep_tree_path(document.absolute_path, restore_file_path_item) for restore_file_path_item in self.get_lock_file_names()] + restore_file_paths = [build_dep_tree_path(document.absolute_path, restore_file_path_item) for + restore_file_path_item in self.get_lock_file_names()] restore_file_path = self.get_any_restore_file_already_exist(restore_file_paths) - relative_restore_file_path = build_dep_tree_path(document.path, self.get_restored_lock_file_name(restore_file_path)) + relative_restore_file_path = build_dep_tree_path(document.path, + self.get_restored_lock_file_name(restore_file_path)) if self.verify_lockfile_missing(restore_file_path): output = execute_commands( @@ -76,16 +78,16 @@ def try_restore_dependencies(self, document: Document) -> Optional[Document]: def get_working_directory(self, document: Document) -> Optional[str]: return os.path.dirname(document.absolute_path) - + def get_restored_lock_file_name(self, restore_file_path: str) -> str: return self.get_lock_file_name() - + @staticmethod def get_any_restore_file_already_exist(restore_file_paths: list[str]) -> Optional[str]: for restore_file_path in restore_file_paths: if os.path.isfile(restore_file_path): return restore_file_path - + return None @staticmethod @@ -103,7 +105,7 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: @abstractmethod def get_lock_file_name(self) -> str: pass - + @abstractmethod def get_lock_file_names(self) -> list[str]: pass diff --git a/cycode/cli/files_collector/sca/go/restore_go_dependencies.py b/cycode/cli/files_collector/sca/go/restore_go_dependencies.py index 6f9713ba..b57812b9 100644 --- a/cycode/cli/files_collector/sca/go/restore_go_dependencies.py +++ b/cycode/cli/files_collector/sca/go/restore_go_dependencies.py @@ -43,6 +43,6 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: def get_lock_file_name(self) -> str: return GO_RESTORE_FILE_NAME - + def get_lock_file_names(self) -> str: return [self.get_lock_file_name()] diff --git a/cycode/cli/files_collector/sca/maven/restore_gradle_dependencies.py b/cycode/cli/files_collector/sca/maven/restore_gradle_dependencies.py index 27a6f991..4e4f36eb 100644 --- a/cycode/cli/files_collector/sca/maven/restore_gradle_dependencies.py +++ b/cycode/cli/files_collector/sca/maven/restore_gradle_dependencies.py @@ -40,7 +40,7 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: def get_lock_file_name(self) -> str: return BUILD_GRADLE_DEP_TREE_FILE_NAME - + def get_lock_file_names(self) -> str: return [self.get_lock_file_name()] diff --git a/cycode/cli/files_collector/sca/maven/restore_maven_dependencies.py b/cycode/cli/files_collector/sca/maven/restore_maven_dependencies.py index 2f618fac..50e55f10 100644 --- a/cycode/cli/files_collector/sca/maven/restore_maven_dependencies.py +++ b/cycode/cli/files_collector/sca/maven/restore_maven_dependencies.py @@ -33,7 +33,7 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: def get_lock_file_name(self) -> str: return join_paths('target', MAVEN_CYCLONE_DEP_TREE_FILE_NAME) - + def get_lock_file_names(self) -> str: return [self.get_lock_file_name()] diff --git a/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py b/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py index 92fa9e88..3f7ddbe0 100644 --- a/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py +++ b/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py @@ -35,13 +35,13 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: '--no-audit', ] ] - + def get_restored_lock_file_name(self, restore_file_path: str) -> str: return NPM_LOCK_FILE_NAME if restore_file_path is None else os.path.basename(restore_file_path) def get_lock_file_name(self) -> str: return NPM_LOCK_FILE_NAME - + def get_lock_file_names(self) -> str: return NPM_LOCK_FILE_NAMES diff --git a/cycode/cli/files_collector/sca/nuget/restore_nuget_dependencies.py b/cycode/cli/files_collector/sca/nuget/restore_nuget_dependencies.py index d91f1691..1e439bbd 100644 --- a/cycode/cli/files_collector/sca/nuget/restore_nuget_dependencies.py +++ b/cycode/cli/files_collector/sca/nuget/restore_nuget_dependencies.py @@ -19,6 +19,6 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: def get_lock_file_name(self) -> str: return NUGET_LOCK_FILE_NAME - + def get_lock_file_names(self) -> str: return [self.get_lock_file_name()] diff --git a/cycode/cli/files_collector/sca/ruby/restore_ruby_dependencies.py b/cycode/cli/files_collector/sca/ruby/restore_ruby_dependencies.py index bde59724..5e0fbe75 100644 --- a/cycode/cli/files_collector/sca/ruby/restore_ruby_dependencies.py +++ b/cycode/cli/files_collector/sca/ruby/restore_ruby_dependencies.py @@ -14,6 +14,6 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: def get_lock_file_name(self) -> str: return RUBY_LOCK_FILE_NAME - + def get_lock_file_names(self) -> str: return [self.get_lock_file_name()] diff --git a/cycode/cli/files_collector/sca/sbt/restore_sbt_dependencies.py b/cycode/cli/files_collector/sca/sbt/restore_sbt_dependencies.py index 04655047..bb2a9626 100644 --- a/cycode/cli/files_collector/sca/sbt/restore_sbt_dependencies.py +++ b/cycode/cli/files_collector/sca/sbt/restore_sbt_dependencies.py @@ -14,6 +14,6 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: def get_lock_file_name(self) -> str: return SBT_LOCK_FILE_NAME - + def get_lock_file_names(self) -> str: return [self.get_lock_file_name()] From 9b17d7c78dbadef9d12886d050a74fc5ccc83f64 Mon Sep 17 00:00:00 2001 From: Mor Samouchian Date: Sun, 23 Nov 2025 16:14:33 +0200 Subject: [PATCH 4/7] CM-55551 CLI SCA Scan Fails to Detect Indirect Dependencies Due to PNPM Lock File Handling --- cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py b/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py index 3f7ddbe0..0dc21d2c 100644 --- a/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py +++ b/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py @@ -37,7 +37,7 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: ] def get_restored_lock_file_name(self, restore_file_path: str) -> str: - return NPM_LOCK_FILE_NAME if restore_file_path is None else os.path.basename(restore_file_path) + return NPM_LOCK_FILE_NAME if restore_file_path is None else os.path.basename(restore_file_path) def get_lock_file_name(self) -> str: return NPM_LOCK_FILE_NAME From bb936975f477c002d3d1d441f515f49e46104584 Mon Sep 17 00:00:00 2001 From: Mor Samouchian Date: Sun, 23 Nov 2025 16:15:58 +0200 Subject: [PATCH 5/7] CM-55551 CLI SCA Scan Fails to Detect Indirect Dependencies Due to PNPM Lock File Handling --- .../sca/base_restore_dependencies.py | 21 +++++++++++-------- .../sca/npm/restore_npm_dependencies.py | 7 +------ 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/cycode/cli/files_collector/sca/base_restore_dependencies.py b/cycode/cli/files_collector/sca/base_restore_dependencies.py index 9a71ef47..b1c83261 100644 --- a/cycode/cli/files_collector/sca/base_restore_dependencies.py +++ b/cycode/cli/files_collector/sca/base_restore_dependencies.py @@ -14,10 +14,10 @@ def build_dep_tree_path(path: str, generated_file_name: str) -> str: def execute_commands( - commands: list[list[str]], - timeout: int, - output_file_path: Optional[str] = None, - working_directory: Optional[str] = None, + commands: list[list[str]], + timeout: int, + output_file_path: Optional[str] = None, + working_directory: Optional[str] = None, ) -> Optional[str]: try: outputs = [] @@ -40,7 +40,7 @@ def execute_commands( class BaseRestoreDependencies(ABC): def __init__( - self, ctx: typer.Context, is_git_diff: bool, command_timeout: int, create_output_file_manually: bool = False + self, ctx: typer.Context, is_git_diff: bool, command_timeout: int, create_output_file_manually: bool = False ) -> None: self.ctx = ctx self.is_git_diff = is_git_diff @@ -57,11 +57,14 @@ def get_manifest_file_path(self, document: Document) -> str: def try_restore_dependencies(self, document: Document) -> Optional[Document]: manifest_file_path = self.get_manifest_file_path(document) - restore_file_paths = [build_dep_tree_path(document.absolute_path, restore_file_path_item) for - restore_file_path_item in self.get_lock_file_names()] + restore_file_paths = [ + build_dep_tree_path(document.absolute_path, restore_file_path_item) + for restore_file_path_item in self.get_lock_file_names() + ] restore_file_path = self.get_any_restore_file_already_exist(restore_file_paths) - relative_restore_file_path = build_dep_tree_path(document.path, - self.get_restored_lock_file_name(restore_file_path)) + relative_restore_file_path = build_dep_tree_path( + document.path, self.get_restored_lock_file_name(restore_file_path) + ) if self.verify_lockfile_missing(restore_file_path): output = execute_commands( diff --git a/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py b/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py index 0dc21d2c..b832467d 100644 --- a/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py +++ b/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py @@ -7,12 +7,7 @@ NPM_PROJECT_FILE_EXTENSIONS = ['.json'] NPM_LOCK_FILE_NAME = 'package-lock.json' -NPM_LOCK_FILE_NAMES = [ - NPM_LOCK_FILE_NAME, - 'yarn.lock', - 'pnpm-lock.yaml', - 'deno.lock' -] +NPM_LOCK_FILE_NAMES = [NPM_LOCK_FILE_NAME, 'yarn.lock', 'pnpm-lock.yaml', 'deno.lock'] NPM_MANIFEST_FILE_NAME = 'package.json' From 119eab3d2d2885b2c14b2f1eb4b98633500ce45b Mon Sep 17 00:00:00 2001 From: Mor Samouchian Date: Mon, 24 Nov 2025 12:31:54 +0200 Subject: [PATCH 6/7] CM-55551 CLI SCA Scan Fails to Detect Indirect Dependencies Due to PNPM Lock File Handling --- .../sca/base_restore_dependencies.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cycode/cli/files_collector/sca/base_restore_dependencies.py b/cycode/cli/files_collector/sca/base_restore_dependencies.py index b1c83261..c673d4b3 100644 --- a/cycode/cli/files_collector/sca/base_restore_dependencies.py +++ b/cycode/cli/files_collector/sca/base_restore_dependencies.py @@ -61,12 +61,12 @@ def try_restore_dependencies(self, document: Document) -> Optional[Document]: build_dep_tree_path(document.absolute_path, restore_file_path_item) for restore_file_path_item in self.get_lock_file_names() ] - restore_file_path = self.get_any_restore_file_already_exist(restore_file_paths) + restore_file_path = self.get_any_restore_file_already_exist(document, restore_file_paths) relative_restore_file_path = build_dep_tree_path( document.path, self.get_restored_lock_file_name(restore_file_path) ) - if self.verify_lockfile_missing(restore_file_path): + if not self.verify_restore_file_already_exist(restore_file_path): output = execute_commands( commands=self.get_commands(manifest_file_path), timeout=self.command_timeout, @@ -85,17 +85,16 @@ def get_working_directory(self, document: Document) -> Optional[str]: def get_restored_lock_file_name(self, restore_file_path: str) -> str: return self.get_lock_file_name() - @staticmethod - def get_any_restore_file_already_exist(restore_file_paths: list[str]) -> Optional[str]: + def get_any_restore_file_already_exist(self, document: Document, restore_file_paths: list[str]) -> Optional[str]: for restore_file_path in restore_file_paths: if os.path.isfile(restore_file_path): return restore_file_path - return None + return build_dep_tree_path(document.absolute_path, self.get_lock_file_name()) @staticmethod - def verify_lockfile_missing(restore_file_path: Optional[str]) -> bool: - return restore_file_path is None + def verify_restore_file_already_exist(restore_file_path: Optional[str]) -> bool: + return os.path.isfile(restore_file_path) @abstractmethod def is_project(self, document: Document) -> bool: From ac7116c647253d8b9239a30a3e017b828458fa5b Mon Sep 17 00:00:00 2001 From: Mor Samouchian Date: Mon, 24 Nov 2025 12:53:58 +0200 Subject: [PATCH 7/7] CM-55551 CLI SCA Scan Fails to Detect Indirect Dependencies Due to PNPM Lock File Handling --- cycode/cli/files_collector/sca/base_restore_dependencies.py | 4 ++-- .../cli/files_collector/sca/npm/restore_npm_dependencies.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cycode/cli/files_collector/sca/base_restore_dependencies.py b/cycode/cli/files_collector/sca/base_restore_dependencies.py index c673d4b3..80ef4183 100644 --- a/cycode/cli/files_collector/sca/base_restore_dependencies.py +++ b/cycode/cli/files_collector/sca/base_restore_dependencies.py @@ -85,7 +85,7 @@ def get_working_directory(self, document: Document) -> Optional[str]: def get_restored_lock_file_name(self, restore_file_path: str) -> str: return self.get_lock_file_name() - def get_any_restore_file_already_exist(self, document: Document, restore_file_paths: list[str]) -> Optional[str]: + def get_any_restore_file_already_exist(self, document: Document, restore_file_paths: list[str]) -> str: for restore_file_path in restore_file_paths: if os.path.isfile(restore_file_path): return restore_file_path @@ -93,7 +93,7 @@ def get_any_restore_file_already_exist(self, document: Document, restore_file_pa return build_dep_tree_path(document.absolute_path, self.get_lock_file_name()) @staticmethod - def verify_restore_file_already_exist(restore_file_path: Optional[str]) -> bool: + def verify_restore_file_already_exist(restore_file_path: str) -> bool: return os.path.isfile(restore_file_path) @abstractmethod diff --git a/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py b/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py index b832467d..120d7de7 100644 --- a/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py +++ b/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py @@ -32,7 +32,7 @@ def get_commands(self, manifest_file_path: str) -> list[list[str]]: ] def get_restored_lock_file_name(self, restore_file_path: str) -> str: - return NPM_LOCK_FILE_NAME if restore_file_path is None else os.path.basename(restore_file_path) + return os.path.basename(restore_file_path) def get_lock_file_name(self) -> str: return NPM_LOCK_FILE_NAME