32
32
from cycode .cli .utils .progress_bar import ScanProgressBarSection
33
33
from cycode .cli .utils .scan_batch import run_parallel_batched_scan
34
34
from cycode .cli .utils .scan_utils import set_issue_detected
35
+ from cycode .cli .utils .shell_executor import shell
35
36
from cycode .cyclient import logger
36
37
from cycode .cyclient .config import set_logging_level
37
38
from cycode .cyclient .models import Detection , DetectionSchema , DetectionsPerFile , ZippedFileScanResult
@@ -666,6 +667,9 @@ def get_scan_parameters(context: click.Context, paths: Optional[Tuple[str]] = No
666
667
return scan_parameters
667
668
668
669
remote_url = try_get_git_remote_url (paths [0 ])
670
+ if not remote_url :
671
+ remote_url = try_to_get_plastic_remote_url (paths [0 ])
672
+
669
673
if remote_url :
670
674
# TODO(MarshalX): remove hardcode in context
671
675
context .obj ['remote_url' ] = remote_url
@@ -684,6 +688,93 @@ def try_get_git_remote_url(path: str) -> Optional[str]:
684
688
return None
685
689
686
690
691
+ def _get_plastic_repository_name (path : str ) -> Optional [str ]:
692
+ """Gets the name of the Plastic repository from the current working directory.
693
+
694
+ The command to execute is:
695
+ cm status --header --machinereadable --fieldseparator=":::"
696
+
697
+ Example of status header in machine-readable format:
698
+ STATUS:::0:::Project/RepoName:::OrgName@ServerInfo
699
+ """
700
+
701
+ try :
702
+ command = [
703
+ 'cm' ,
704
+ 'status' ,
705
+ '--header' ,
706
+ '--machinereadable' ,
707
+ f'--fieldseparator={ consts .PLASTIC_VCS_DATA_SEPARATOR } ' ,
708
+ ]
709
+
710
+ status = shell (command = command , timeout = consts .PLASTIC_VSC_CLI_TIMEOUT , working_directory = path )
711
+ if not status :
712
+ logger .debug ('Failed to get Plastic repository name (command failed)' )
713
+ return None
714
+
715
+ status_parts = status .split (consts .PLASTIC_VCS_DATA_SEPARATOR )
716
+ if len (status_parts ) < 2 :
717
+ logger .debug ('Failed to parse Plastic repository name (command returned unexpected format)' )
718
+ return None
719
+
720
+ return status_parts [2 ].strip ()
721
+ except Exception as e :
722
+ logger .debug ('Failed to get Plastic repository name' , exc_info = e )
723
+ return None
724
+
725
+
726
+ def _get_plastic_repository_list (working_dir : Optional [str ] = None ) -> Dict [str , str ]:
727
+ """Gets the list of Plastic repositories and their GUIDs.
728
+
729
+ The command to execute is:
730
+ cm repo list --format="{repname}:::{repguid}"
731
+
732
+ Example line with data:
733
+ Project/RepoName:::tapo1zqt-wn99-4752-h61m-7d9k79d40r4v
734
+
735
+ Each line represents an individual repository.
736
+ """
737
+
738
+ repo_name_to_guid = {}
739
+
740
+ try :
741
+ command = ['cm' , 'repo' , 'ls' , f'--format={{repname}}{ consts .PLASTIC_VCS_DATA_SEPARATOR } {{repguid}}' ]
742
+
743
+ status = shell (command = command , timeout = consts .PLASTIC_VSC_CLI_TIMEOUT , working_directory = working_dir )
744
+ if not status :
745
+ logger .debug ('Failed to get Plastic repository list (command failed)' )
746
+ return repo_name_to_guid
747
+
748
+ status_lines = status .splitlines ()
749
+ for line in status_lines :
750
+ data_parts = line .split (consts .PLASTIC_VCS_DATA_SEPARATOR )
751
+ if len (data_parts ) < 2 :
752
+ logger .debug ('Failed to parse Plastic repository list line (unexpected format), %s' , {'line' : line })
753
+ continue
754
+
755
+ repo_name , repo_guid = data_parts
756
+ repo_name_to_guid [repo_name .strip ()] = repo_guid .strip ()
757
+
758
+ return repo_name_to_guid
759
+ except Exception as e :
760
+ logger .debug ('Failed to get Plastic repository list' , exc_info = e )
761
+ return repo_name_to_guid
762
+
763
+
764
+ def try_to_get_plastic_remote_url (path : str ) -> Optional [str ]:
765
+ repository_name = _get_plastic_repository_name (path )
766
+ if not repository_name :
767
+ return None
768
+
769
+ repository_map = _get_plastic_repository_list (path )
770
+ if repository_name not in repository_map :
771
+ logger .debug ('Failed to get Plastic repository GUID (repository not found in the list)' )
772
+ return None
773
+
774
+ repository_guid = repository_map [repository_name ]
775
+ return f'{ consts .PLASTIC_VCS_REMOTE_URI_PREFIX } { repository_guid } '
776
+
777
+
687
778
def exclude_irrelevant_detections (
688
779
detections : List [Detection ], scan_type : str , command_scan_type : str , severity_threshold : str
689
780
) -> List [Detection ]:
0 commit comments