boman-cli 2.1__tar.gz → 2.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: boman-cli
3
- Version: 2.1
3
+ Version: 2.2.0
4
4
  Summary: CLI tool of boman.ai
5
5
  Home-page: https://boman.ai
6
6
  Author: Sumeru Software Solutions Pvt. Ltd.
@@ -83,6 +83,12 @@ Example: boman-cli -a run -zap_session_script ./session.js
83
83
 
84
84
  ### Release Note:
85
85
 
86
+ ### V2.2.0
87
+ - New scan added: IaC.
88
+
89
+ ### V2.1.1
90
+ - Ignore files or directory for SAST and SCA
91
+
86
92
  ### V2.1
87
93
  - New scan added: SBOM.
88
94
 
@@ -68,6 +68,12 @@ Example: boman-cli -a run -zap_session_script ./session.js
68
68
 
69
69
  ### Release Note:
70
70
 
71
+ ### V2.2.0
72
+ - New scan added: IaC.
73
+
74
+ ### V2.1.1
75
+ - Ignore files or directory for SAST and SCA
76
+
71
77
  ### V2.1
72
78
  - New scan added: SBOM.
73
79
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: boman-cli
3
- Version: 2.1
3
+ Version: 2.2.0
4
4
  Summary: CLI tool of boman.ai
5
5
  Home-page: https://boman.ai
6
6
  Author: Sumeru Software Solutions Pvt. Ltd.
@@ -83,6 +83,12 @@ Example: boman-cli -a run -zap_session_script ./session.js
83
83
 
84
84
  ### Release Note:
85
85
 
86
+ ### V2.2.0
87
+ - New scan added: IaC.
88
+
89
+ ### V2.1.1
90
+ - Ignore files or directory for SAST and SCA
91
+
86
92
  ### V2.1
87
93
  - New scan added: SBOM.
88
94
 
@@ -25,6 +25,7 @@ class Config:
25
25
  sast_upload_status = None
26
26
  sast_message = None
27
27
  sast_errors = None
28
+ sast_ignore = False
28
29
 
29
30
  dast_present = None
30
31
  dast_target = None
@@ -56,6 +57,8 @@ class Config:
56
57
  sca_upload_status = None
57
58
  sca_message = None
58
59
  sca_errors = None
60
+ sca_ignore = False
61
+ sca_exclude_paths=None
59
62
 
60
63
  app_token = None
61
64
  customer_token = None
@@ -115,7 +118,7 @@ class Config:
115
118
 
116
119
  log_level = "INFO"
117
120
 
118
- version = 'v2.1'
121
+ version = 'v2.2.0'
119
122
 
120
123
  boman_config_file = 'boman.yaml'
121
124
 
@@ -159,4 +162,16 @@ class Config:
159
162
  sbom_errors=None
160
163
  sbom_upload_status=None
161
164
  sbom_scan_status=None
162
- sbom_target=None
165
+ sbom_target=None
166
+
167
+ #IAC scanning
168
+ iac_scan_present=None
169
+ iac_scan_build_dir=None
170
+ iac_scan_message=None
171
+ iac_scan_response=None
172
+ iac_scan_errors=None
173
+ iac_scan_upload_status=None
174
+ iac_scan_status=None
175
+ iac_scan_type=None
176
+ iac_scan_target=None
177
+ iac_valid_exit_status = [0,60,50,40,30,20]
@@ -46,8 +46,9 @@ def authorize():
46
46
 
47
47
  logging.info(f"Boman opted for: {Config.sca_lang} scan")
48
48
  logging.info('Authenticating with boman server')
49
- data = {'app_token': Config.app_token, 'customer_token': Config.customer_token, 'sast':Config.sast_present,"dast":Config.dast_present,"dast_type":Config.dast_type,"dast_auth_enabled":Config.dast_auth_present,"sast_langs":Config.sast_lang,"sca":Config.sca_present,"sca_langs":Config.sca_lang,"sca_scan_type":Config.sca_type,"secret_scan":Config.secret_scan_present,'container_scan': Config.con_scan_present,'container_scan_type': Config.con_scan_type,"sbom":Config.sbom_present}
49
+ data = {'app_token': Config.app_token, 'customer_token': Config.customer_token, 'sast':Config.sast_present,"dast":Config.dast_present,"dast_type":Config.dast_type,"dast_auth_enabled":Config.dast_auth_present,"sast_langs":Config.sast_lang,"sca":Config.sca_present,"sca_langs":Config.sca_lang,"sca_scan_type":Config.sca_type,"secret_scan":Config.secret_scan_present,'container_scan': Config.con_scan_present,'container_scan_type': Config.con_scan_type,"sbom":Config.sbom_present,'iac':Config.iac_scan_present}
50
50
  headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
51
+ # logging.info(data)
51
52
  try:
52
53
  res = requests.post(url, json=data, headers=headers)
53
54
  #print('req:', json.dumps(data))
@@ -60,6 +61,7 @@ def authorize():
60
61
  try:
61
62
  json_response = json.loads(res.content)
62
63
  logging.info('Authentication Done')
64
+ # logging.info(json_response)
63
65
  except:
64
66
  logging.info('Authentication Failure')
65
67
  try:
@@ -70,7 +72,8 @@ def authorize():
70
72
  Config.scan_token = json_response['data']['scan_token']
71
73
  Config.scan_name = json_response['data']['scan_name']
72
74
  Config.con_scan_response = json_response['data']['cs']
73
- Config.sbom_response = json_response['data']['sbom']
75
+ Config.sbom_response = json_response['data']['sbom']
76
+ Config.iac_scan_response = json_response['data']['iac']
74
77
 
75
78
  return 1
76
79
  except:
@@ -125,6 +125,12 @@ def runImage(data=None,type=None):
125
125
 
126
126
 
127
127
  if type == 'SAST':
128
+ if Config.sast_ignore:
129
+ if Utils.copy_file('.bomanignore','.semgrepignore'):
130
+ logging.info("Files and Folders to be ignored is added to .semgrepignore file")
131
+ else:
132
+ logging.error(".bomanignore file was not found")
133
+ exit(4)
128
134
  target_file = Config.sast_target
129
135
  Utils.checkImageAlreadyExsist(docker_image)
130
136
 
@@ -220,7 +226,8 @@ def runImage(data=None,type=None):
220
226
 
221
227
 
222
228
  try:
223
-
229
+ if Config.sast_ignore:
230
+ os.remove('.semgrepignore')
224
231
  if will_generate_output == 1:
225
232
  #logging.info('WILL GENERATE OUTPUT')
226
233
  if uploadReport(output_file,tool_name,tool_id,scan_details_id,'SAST'):
@@ -446,7 +453,12 @@ def runImage(data=None,type=None):
446
453
  container_output = docker.containers.run(docker_image, command_line, volumes={Config.sca_build_dir: {
447
454
  'bind': data['bind']}}, user=uid)
448
455
  logging.info('[SUCCESS]: %s Scan Completed',tool_name)
449
- else:
456
+ else:
457
+ if Config.sca_ignore:
458
+ Config.sca_exclude_files = Utils.read_bomanignore('.bomanignore')
459
+ if Config.sca_exclude_files:
460
+ command_line = f'{command_line} {Config.sca_exclude_files}'
461
+ logging.info('Comment for SCA with ignore %s',command_line)
450
462
  Config.build_dir = Config.sca_build_dir
451
463
  container_output = docker.containers.run(docker_image, command_line, volumes={Config.sca_build_dir: {
452
464
  'bind': data['bind']}}, user=uid)
@@ -508,7 +520,7 @@ def runImage(data=None,type=None):
508
520
  except errors.ContainerError as exc:
509
521
  logging.error('Some Error recorded while scanning %s',tool_name)
510
522
  logging.error('%s',str(exc))
511
- msg='\n The following error has been recorded while scanning sca'
523
+ msg='\n The following error has been recorded while scanning Container'
512
524
  Config.con_scan_status ='Failed'
513
525
  Config.con_scan_errors ='Some Error recorded while scanning [',str(exc),']'
514
526
  Utils.logError(msg,str(exc))
@@ -576,6 +588,54 @@ def runImage(data=None,type=None):
576
588
  Config.sbom_message ='Error recorded while uploading the report of SBOM, Please check your directory for the files.' ## need to change logic here -- MM
577
589
  msg = 'Error recorded while uploading the report'
578
590
  Utils.logError(msg,str(e))
591
+
592
+ if type == 'iac':
593
+ Utils.checkImageAlreadyExsist(docker_image)
594
+ logging.info('Running %s',tool_name)
595
+
596
+ try:
597
+ command_line = "% s" % command_line.format(target = '/src'+Config.iac_scan_target)
598
+ Config.build_dir = Config.iac_scan_build_dir
599
+ container_output = docker.containers.run(docker_image, command_line, volumes={Config.iac_scan_build_dir: {
600
+ 'bind': data['bind']}}, user=uid)
601
+ logging.info('[SUCCESS]: %s Scan Completed',tool_name)
602
+ Config.iac_scan_message ='IaC Scan completed'
603
+ Config.iac_scan_status ='Completed'
604
+ except errors.ContainerError as exc:
605
+ if exc.exit_status in Config.iac_valid_exit_status:
606
+ Config.iac_scan_message ='IaC scan completed'
607
+ Config.iac_scan_status ='Completed'
608
+ logging.info('[SUCCESS]: %s Scan Completed',tool_name)
609
+ logging.info(f'IaC: {exc.stderr}')
610
+ else:
611
+ logging.error('Some Error recorded while scanning %s',tool_name)
612
+ logging.error('%s',str(exc))
613
+ msg='\n The following error has been recorded while scanning IaC'
614
+ Config.iac_scan_status ='Failed'
615
+ Config.iac_scan_errors ='Some Error recorded while scanning [',str(exc),']'
616
+ Utils.logError(msg,str(exc))
617
+
618
+ try:
619
+ if will_generate_output == 1:
620
+ logging.info('Uploading %s to the server',output_file)
621
+ if uploadReport(output_file,tool_name,tool_id,scan_details_id,'iac'):
622
+ Config.iac_scan_status ='Completed'
623
+ Config.iac_scan_upload_status = 'Completed'
624
+ Config.iac_scan_message ='Scan Completed'
625
+ else:
626
+ Config.iac_scan_status ='Failed'
627
+ Config.iac_scan_upload_status = 'Failed'
628
+ Config.iac_scan_message ='Error occured while uploading the report, Please check the cli logs'
629
+ else:
630
+ logging.error('Cant upload files to the server',tool_name)
631
+ Config.iac_scan_message ='Cant upload files to the server for IaC Scan,Please check your directory for the files.'
632
+
633
+ except EnvironmentError as e:
634
+ logging.error('Error recorded while uploading the report %s',tool_name)
635
+ logging.error('%s',str(e))
636
+ Config.iac_scan_message ='Error recorded while uploading the report of IaC Scan, Please check your directory for the files.' ## need to change logic here -- MM
637
+ msg = 'Error recorded while uploading the report'
638
+ Utils.logError(msg,str(e))
579
639
 
580
640
 
581
641
  #### function to upload the test report to the server with other data -- MM ------------------------------------
@@ -607,6 +667,9 @@ def uploadReport(filename,toolname,tool_id,scan_details_id,type):
607
667
  elif type =="sbom":
608
668
  message = Config.sbom_message
609
669
  errors = Config.sbom_errors
670
+ elif type =="iac":
671
+ message = Config.iac_scan_message
672
+ errors = Config.iac_scan_errors
610
673
  except:
611
674
  message = 'NA'
612
675
  errors = 'NA'
@@ -787,7 +850,7 @@ def main():
787
850
 
788
851
  init()
789
852
  Validation.yamlValidation()
790
- if Config.secret_scan_present == True or Config.sast_present is True or Config.dast_present is True or Config.sca_present is True or Config.con_scan_present is True or Config.sbom_present:
853
+ if Config.secret_scan_present == True or Config.sast_present is True or Config.dast_present is True or Config.sca_present is True or Config.con_scan_present is True or Config.sbom_present or Config.iac_scan_present:
791
854
  Utils.testServer()
792
855
  else:
793
856
  content = Auth.authorize()
@@ -939,6 +1002,19 @@ def main():
939
1002
  runImage(data=data,type='sbom')
940
1003
  else:
941
1004
  logging.info('Ignoring SBOM')
1005
+
1006
+ if Config.iac_scan_present is True:
1007
+ logging.info("Preparing IaC Scan requirements")
1008
+
1009
+ for data in Config.iac_scan_response:
1010
+
1011
+ if data['scan_status'] == 0 :
1012
+ logging.info('No IaC Scan Configuration found from SaaS')
1013
+ logging.info('Ignoring IaC Scan')
1014
+ else:
1015
+ runImage(data=data,type='iac')
1016
+ else:
1017
+ logging.info('Ignoring IaC Scan')
942
1018
 
943
1019
  exitFunction()
944
1020
  return 1
@@ -339,8 +339,16 @@ def showSummary():
339
339
  logging.info('SCAN MESSAGE : %s', Config.sbom_message)
340
340
  logging.info('-------------------------------------')
341
341
 
342
-
343
-
342
+ logging.info('-------- IaC SCAN STATUS --------- ')
343
+ if Config.iac_scan_present:
344
+ logging.info('SCAN STATUS: %s',Config.iac_scan_status)
345
+ logging.info('UPLOAD STATUS: %s',Config.iac_scan_upload_status)
346
+ logging.info('SCAN MESSAGE : %s', Config.iac_scan_message)
347
+
348
+ logging.info('ERRORS: %s',Config.iac_scan_errors)
349
+ else:
350
+ logging.info('SCAN MESSAGE : %s', Config.iac_scan_message)
351
+ logging.info('-------------------------------------')
344
352
  # logging.info(Config.sast_message)
345
353
  # logging.info(Config.dast_message)
346
354
  # logging.info(Config.sca_message)
@@ -889,4 +897,31 @@ def uploadLogs():
889
897
 
890
898
  def remove_leading_slash(s):
891
899
  # Check if the first character is a slash and remove it
892
- return s[1:] if s.startswith('/') else s
900
+ return s[1:] if s.startswith('/') else s
901
+
902
+ def read_bomanignore(file_path):
903
+ exclude_paths = []
904
+ try:
905
+ with open(file_path, 'r') as file:
906
+ for line in file:
907
+ # Skip comments and empty lines
908
+ line = line.strip()
909
+ if line and not line.startswith('#'):
910
+ full_command = " --exclude "+line
911
+ exclude_paths.append(full_command)
912
+ except FileNotFoundError:
913
+ logging.info(f"Error: {file_path} not found.")
914
+ return False
915
+ # Join the list into a space separated string
916
+ return ''.join(exclude_paths)
917
+
918
+ def copy_file(source_path, dest_path):
919
+ try:
920
+ with open(source_path, 'r') as source_file:
921
+ source_content = source_file.read()
922
+ with open(dest_path, 'w') as dest_file:
923
+ dest_file.write(source_content)
924
+ return True # Successfully copied
925
+ except FileNotFoundError:
926
+ logging.info(f"Error: {source_path} not found.")
927
+ return False # Source file not found
@@ -61,6 +61,13 @@ def yamlValidation():
61
61
  except KeyError:
62
62
  logging.info('work dir not specified in config, choosing the default sast working directory')
63
63
  Config.sast_build_dir = os.getcwd()+'/'
64
+
65
+ try:
66
+ logging.info('Ignoring file and folder check')
67
+ Config.sast_ignore = Config.config_data['SAST']['ignore_files']
68
+ except KeyError:
69
+ logging.info('ignore_files config was not found')
70
+
64
71
 
65
72
  #logging.info('snyk is choosen, and the env var declared was %s', str('s'))
66
73
 
@@ -170,6 +177,11 @@ def yamlValidation():
170
177
  # ##after sbom and lockfile type check
171
178
  # Config.sca_build_dir = os.getcwd()+'/'
172
179
 
180
+ try:
181
+ logging.info('Ignoring file and folder check')
182
+ Config.sca_ignore = Config.config_data['SCA']['ignore_files']
183
+ except KeyError:
184
+ logging.info('ignore_files config was not found')
173
185
 
174
186
  try:
175
187
  logging.info('Configuring target for SCA')
@@ -282,7 +294,36 @@ def yamlValidation():
282
294
  Config.sbom_present = False
283
295
  logging.warning('SBOM is not properly configured. Cant read the "sbom" configuration.')
284
296
  Config.sbom_message ='sbom is not properly configured'
285
-
297
+
298
+ # Validation of boman.yaml for IaC scanning
299
+ try:
300
+ if "IAC" in Config.config_data:
301
+ Config.iac_scan_present = True
302
+ Config.iac_scan_build_dir= os.getcwd()+'/'
303
+
304
+ try:
305
+ logging.info('Configuring target for IaC Scan.')
306
+ Config.iac_scan_target = Config.config_data['IAC']['target']
307
+ logging.info(f'Target configured for IaC Scan: {Config.iac_scan_target}')
308
+ except KeyError:
309
+ Config.iac_scan_target="/"
310
+ logging.info("KEY ERROR")
311
+ logging.info('target is missing for IaC Scan. target configured to default path')
312
+ except TypeError:
313
+ Config.iac_scan_target="/"
314
+ logging.info("TYPE ERROR")
315
+ logging.info('target is missing for IaC Scan. target configured to default path')
316
+
317
+ logging.info('IaC Scan is properly configured and ready to scan')
318
+ Config.iac_scan_message ='IaC Scan is properly configured and ready to scan'
319
+ else:
320
+ Config.iac_scan_present = False
321
+ logging.warning('IaC Scan is not properly configured. Cant read the "IAC" configuration.')
322
+ Config.iac_scan_message ='IaC Scan is not properly configured'
323
+ except:
324
+ Config.iac_scan_present = False
325
+ logging.warning('IaC Scan is not properly configured. Cant read the "IAC" configuration.')
326
+ Config.iac_scan_message ='IaC Scan is not properly configured'
286
327
 
287
328
 
288
329
  ## need to use lingudetect here, but the results are not trustable and misleading ------ MM -------------------
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  environment = prod
3
- version = 2.1
3
+ version = 2.2.0
4
4
  name = boman-cli
5
5
  saas_base_url =
6
6
  https = //dashboard.boman.ai/
File without changes
File without changes