conviso-ast 3.0.0__py3-none-any.whl

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.
Files changed (128) hide show
  1. conviso_ast-3.0.0.data/scripts/flow_bash_completer.sh +21 -0
  2. conviso_ast-3.0.0.data/scripts/flow_fish_completer.fish +1 -0
  3. conviso_ast-3.0.0.data/scripts/flow_zsh_completer.sh +32 -0
  4. conviso_ast-3.0.0.dist-info/METADATA +37 -0
  5. conviso_ast-3.0.0.dist-info/RECORD +128 -0
  6. conviso_ast-3.0.0.dist-info/WHEEL +5 -0
  7. conviso_ast-3.0.0.dist-info/entry_points.txt +3 -0
  8. conviso_ast-3.0.0.dist-info/top_level.txt +1 -0
  9. convisoappsec/__init__.py +0 -0
  10. convisoappsec/common/__init__.py +5 -0
  11. convisoappsec/common/box.py +251 -0
  12. convisoappsec/common/cleaner.py +78 -0
  13. convisoappsec/common/docker.py +399 -0
  14. convisoappsec/common/exceptions.py +8 -0
  15. convisoappsec/common/git_data_parser.py +76 -0
  16. convisoappsec/common/graphql/__init__.py +0 -0
  17. convisoappsec/common/graphql/error_handlers.py +75 -0
  18. convisoappsec/common/graphql/errors.py +16 -0
  19. convisoappsec/common/graphql/low_client.py +51 -0
  20. convisoappsec/common/retry_handler.py +40 -0
  21. convisoappsec/common/strings.py +8 -0
  22. convisoappsec/flow/__init__.py +3 -0
  23. convisoappsec/flow/api.py +104 -0
  24. convisoappsec/flow/cleaner.py +118 -0
  25. convisoappsec/flow/graphql_api/__init__.py +0 -0
  26. convisoappsec/flow/graphql_api/beta/__init__.py +0 -0
  27. convisoappsec/flow/graphql_api/beta/client.py +18 -0
  28. convisoappsec/flow/graphql_api/beta/models/__init__.py +0 -0
  29. convisoappsec/flow/graphql_api/beta/models/issues/__init__.py +0 -0
  30. convisoappsec/flow/graphql_api/beta/models/issues/container.py +72 -0
  31. convisoappsec/flow/graphql_api/beta/models/issues/iac.py +6 -0
  32. convisoappsec/flow/graphql_api/beta/models/issues/normalize.py +13 -0
  33. convisoappsec/flow/graphql_api/beta/models/issues/sast.py +53 -0
  34. convisoappsec/flow/graphql_api/beta/models/issues/sca.py +78 -0
  35. convisoappsec/flow/graphql_api/beta/resources_api.py +142 -0
  36. convisoappsec/flow/graphql_api/beta/schemas/__init__.py +0 -0
  37. convisoappsec/flow/graphql_api/beta/schemas/mutations/__init__.py +61 -0
  38. convisoappsec/flow/graphql_api/beta/schemas/resolvers/__init__.py +0 -0
  39. convisoappsec/flow/graphql_api/v1/__init__.py +0 -0
  40. convisoappsec/flow/graphql_api/v1/client.py +46 -0
  41. convisoappsec/flow/graphql_api/v1/models/__init__.py +0 -0
  42. convisoappsec/flow/graphql_api/v1/models/asset.py +14 -0
  43. convisoappsec/flow/graphql_api/v1/models/issues.py +16 -0
  44. convisoappsec/flow/graphql_api/v1/models/project.py +35 -0
  45. convisoappsec/flow/graphql_api/v1/resources_api.py +489 -0
  46. convisoappsec/flow/graphql_api/v1/schemas/__init__.py +0 -0
  47. convisoappsec/flow/graphql_api/v1/schemas/mutations/__init__.py +212 -0
  48. convisoappsec/flow/graphql_api/v1/schemas/resolvers/__init__.py +180 -0
  49. convisoappsec/flow/source_code_scanner/__init__.py +9 -0
  50. convisoappsec/flow/source_code_scanner/exceptions.py +2 -0
  51. convisoappsec/flow/source_code_scanner/scc.py +68 -0
  52. convisoappsec/flow/source_code_scanner/source_code_scanner.py +177 -0
  53. convisoappsec/flow/util/__init__.py +7 -0
  54. convisoappsec/flow/util/ci_provider.py +99 -0
  55. convisoappsec/flow/util/metrics.py +16 -0
  56. convisoappsec/flow/util/source_code_compressor.py +22 -0
  57. convisoappsec/flow/version_control_system_adapter.py +528 -0
  58. convisoappsec/flow/version_searchers/__init__.py +9 -0
  59. convisoappsec/flow/version_searchers/sorted_by_versioning_style.py +85 -0
  60. convisoappsec/flow/version_searchers/timebased_version_seacher.py +39 -0
  61. convisoappsec/flow/version_searchers/version_searcher_result.py +33 -0
  62. convisoappsec/flow/versioning_style/__init__.py +0 -0
  63. convisoappsec/flow/versioning_style/semantic_versioning.py +44 -0
  64. convisoappsec/flowcli/__init__.py +3 -0
  65. convisoappsec/flowcli/__main__.py +4 -0
  66. convisoappsec/flowcli/assets/__init__.py +4 -0
  67. convisoappsec/flowcli/assets/create.py +88 -0
  68. convisoappsec/flowcli/assets/entrypoint.py +20 -0
  69. convisoappsec/flowcli/assets/ls.py +63 -0
  70. convisoappsec/flowcli/ast/__init__.py +3 -0
  71. convisoappsec/flowcli/ast/entrypoint.py +427 -0
  72. convisoappsec/flowcli/common.py +175 -0
  73. convisoappsec/flowcli/companies/__init__.py +0 -0
  74. convisoappsec/flowcli/companies/ls.py +25 -0
  75. convisoappsec/flowcli/container/__init__.py +3 -0
  76. convisoappsec/flowcli/container/entrypoint.py +17 -0
  77. convisoappsec/flowcli/container/run.py +306 -0
  78. convisoappsec/flowcli/context.py +49 -0
  79. convisoappsec/flowcli/deploy/__init__.py +0 -0
  80. convisoappsec/flowcli/deploy/create/__init__.py +4 -0
  81. convisoappsec/flowcli/deploy/create/context.py +12 -0
  82. convisoappsec/flowcli/deploy/create/entrypoint.py +31 -0
  83. convisoappsec/flowcli/deploy/create/with_/__init__.py +3 -0
  84. convisoappsec/flowcli/deploy/create/with_/entrypoint.py +20 -0
  85. convisoappsec/flowcli/deploy/create/with_/tag_tracker/__init__.py +4 -0
  86. convisoappsec/flowcli/deploy/create/with_/tag_tracker/context.py +11 -0
  87. convisoappsec/flowcli/deploy/create/with_/tag_tracker/entrypoint.py +30 -0
  88. convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/__init__.py +4 -0
  89. convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/entrypoint.py +21 -0
  90. convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/time_.py +84 -0
  91. convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/versioning_style.py +115 -0
  92. convisoappsec/flowcli/deploy/create/with_/values.py +133 -0
  93. convisoappsec/flowcli/entrypoint.py +103 -0
  94. convisoappsec/flowcli/environment_checker.py +45 -0
  95. convisoappsec/flowcli/findings/__init__.py +4 -0
  96. convisoappsec/flowcli/findings/create/__init__.py +4 -0
  97. convisoappsec/flowcli/findings/create/entrypoint.py +18 -0
  98. convisoappsec/flowcli/findings/create/with_/__init__.py +3 -0
  99. convisoappsec/flowcli/findings/create/with_/entrypoint.py +19 -0
  100. convisoappsec/flowcli/findings/create/with_/version_tracker.py +93 -0
  101. convisoappsec/flowcli/findings/entrypoint.py +19 -0
  102. convisoappsec/flowcli/findings/import_sarif/__init__.py +4 -0
  103. convisoappsec/flowcli/findings/import_sarif/entrypoint.py +430 -0
  104. convisoappsec/flowcli/help_option.py +18 -0
  105. convisoappsec/flowcli/iac/__init__.py +3 -0
  106. convisoappsec/flowcli/iac/entrypoint.py +17 -0
  107. convisoappsec/flowcli/iac/run.py +328 -0
  108. convisoappsec/flowcli/requirements_verifier.py +132 -0
  109. convisoappsec/flowcli/sast/__init__.py +3 -0
  110. convisoappsec/flowcli/sast/entrypoint.py +17 -0
  111. convisoappsec/flowcli/sast/run.py +485 -0
  112. convisoappsec/flowcli/sbom/__init__.py +3 -0
  113. convisoappsec/flowcli/sbom/entrypoint.py +17 -0
  114. convisoappsec/flowcli/sbom/generate.py +235 -0
  115. convisoappsec/flowcli/sca/__init__.py +3 -0
  116. convisoappsec/flowcli/sca/entrypoint.py +17 -0
  117. convisoappsec/flowcli/sca/run.py +479 -0
  118. convisoappsec/flowcli/vulnerability/__init__.py +3 -0
  119. convisoappsec/flowcli/vulnerability/assert_security_rules.py +201 -0
  120. convisoappsec/flowcli/vulnerability/container_vulnerability_manager.py +175 -0
  121. convisoappsec/flowcli/vulnerability/entrypoint.py +18 -0
  122. convisoappsec/flowcli/vulnerability/rules_schema.json +53 -0
  123. convisoappsec/flowcli/vulnerability/run.py +487 -0
  124. convisoappsec/logger.py +29 -0
  125. convisoappsec/sast/__init__.py +0 -0
  126. convisoappsec/sast/decision.py +45 -0
  127. convisoappsec/sast/sastbox.py +296 -0
  128. convisoappsec/version.py +1 -0
@@ -0,0 +1,430 @@
1
+ import click
2
+ import click_log
3
+ import json
4
+ from base64 import b64decode
5
+ from re import search as regex_search
6
+ from copy import deepcopy as clone
7
+ from convisoappsec.flowcli import help_option
8
+ from convisoappsec.flowcli.context import pass_flow_context
9
+ from convisoappsec.logger import LOGGER
10
+ from convisoappsec.flowcli.requirements_verifier import RequirementsVerifier
11
+ from convisoappsec.flow.graphql_api.beta.models.issues.sast import (CreateSastFindingInput)
12
+ from convisoappsec.flow.graphql_api.beta.models.issues.sca import CreateScaFindingInput
13
+ from convisoappsec.common.graphql.errors import ResponseError
14
+
15
+ click_log.basic_config(LOGGER)
16
+
17
+
18
+ @click.command()
19
+ @click.option(
20
+ "-i",
21
+ "--input-file",
22
+ required=True,
23
+ type=click.Path(exists=True),
24
+ help='The path to SARIF file.',
25
+ )
26
+ @click.option(
27
+ "--company-id",
28
+ required=False,
29
+ envvar=("CONVISO_COMPANY_ID", "FLOW_COMPANY_ID"),
30
+ help="Company ID on Conviso Platform",
31
+ )
32
+ @click.option(
33
+ "-r",
34
+ "--repository-dir",
35
+ default=".",
36
+ show_default=True,
37
+ type=click.Path(
38
+ exists=True,
39
+ resolve_path=True,
40
+ ),
41
+ required=False,
42
+ help="The source code repository directory.",
43
+ )
44
+ @click.option(
45
+ '--asset-name',
46
+ required=False,
47
+ envvar=("CONVISO_ASSET_NAME", "FLOW_ASSET_NAME"),
48
+ help="Provides a asset name.",
49
+ )
50
+ @help_option
51
+ @pass_flow_context
52
+ @click.pass_context
53
+ def import_sarif(context, flow_context, input_file, company_id, repository_dir, asset_name):
54
+ context.params['company_id'] = company_id if company_id is not None else None
55
+ context.params['repository_dir'] = repository_dir
56
+
57
+ prepared_context = RequirementsVerifier.prepare_context(clone(context))
58
+ asset_id = prepared_context.params['asset_id']
59
+
60
+ try:
61
+ conviso_api = flow_context.create_conviso_api_client_beta()
62
+ LOGGER.info("💬 Starting the import process for the SARIF file.")
63
+ parse_sarif_file(conviso_api, asset_id, input_file)
64
+ except Exception as e:
65
+ LOGGER.error(f"❌ Error during SARIF file import: {str(e)}")
66
+ raise Exception("SARIF file import failed. Please contact support and provide the SARIF file for assistance.")
67
+
68
+
69
+ def parse_sarif_file(conviso_api, asset_id, sarif_file):
70
+ try:
71
+ sarif_data = _load_sarif_data(sarif_file)
72
+ if not sarif_data:
73
+ raise Exception("Failed to load SARIF file")
74
+
75
+ sarif_infos = _extract_rules_info(sarif_data)
76
+
77
+ success_count = 0
78
+ error_count = 0
79
+
80
+ for run in sarif_data.get('runs', []):
81
+ for result in run.get('results', []):
82
+ try:
83
+ if _process_vulnerability(conviso_api, asset_id, result, sarif_infos):
84
+ success_count += 1
85
+ else:
86
+ error_count += 1
87
+ except Exception as e:
88
+ LOGGER.error(f"❌ Error processing vulnerability: {str(e)}")
89
+ error_count += 1
90
+
91
+ LOGGER.info(f"✅ Successfully processed {success_count} vulnerabilities")
92
+ if error_count > 0:
93
+ LOGGER.warning(f"⚠️ {error_count} vulnerabilities with errors")
94
+
95
+ LOGGER.info("✅ SARIF file import completed successfully.")
96
+
97
+ except Exception as e:
98
+ LOGGER.error(f"❌ Error during SARIF file parsing: {str(e)}")
99
+ raise
100
+
101
+
102
+ def _load_sarif_data(sarif_file):
103
+ try:
104
+ cleaned_file = clean_file(sarif_file)
105
+
106
+ with open(cleaned_file, 'r', encoding='utf-8') as file:
107
+ sarif_data = json.load(file)
108
+
109
+ if not isinstance(sarif_data, dict) or 'runs' not in sarif_data:
110
+ LOGGER.error("❌ Invalid SARIF file: 'runs' structure not found")
111
+ return None
112
+
113
+ return sarif_data
114
+
115
+ except json.JSONDecodeError as e:
116
+ LOGGER.error(f"❌ Error decoding JSON: {str(e)}")
117
+ return None
118
+ except Exception as e:
119
+ LOGGER.error(f"❌ Error loading file: {str(e)}")
120
+ return None
121
+
122
+
123
+ def _extract_rules_info(sarif_data):
124
+ sarif_infos = []
125
+
126
+ for run in sarif_data.get('runs', []):
127
+ for rule in run.get('tool', {}).get('driver', {}).get('rules', []):
128
+ title = (rule.get('shortDescription', {}).get('text') or
129
+ rule.get('name') or
130
+ rule.get('fullDescription', {}).get('text') or
131
+ rule.get('help', {}).get('text'))
132
+
133
+ rule_info = {
134
+ "id": rule.get('id'),
135
+ "name": title,
136
+ "references": rule.get('helpUri'),
137
+ "description": _get_rule_description(rule)
138
+ }
139
+ sarif_infos.append(rule_info)
140
+
141
+ return sarif_infos
142
+
143
+
144
+ def _get_rule_description(rule):
145
+ return (rule.get('help', {}).get('text') or
146
+ rule.get('fullDescription', {}).get('text') or
147
+ rule.get('shortDescription', {}).get('text'))
148
+
149
+
150
+ def _process_vulnerability(conviso_api, asset_id, result, sarif_infos):
151
+ try:
152
+ if not result.get('ruleId'):
153
+ LOGGER.warning("⚠️ Result without ruleId, skipping...")
154
+ return False
155
+
156
+ vuln_data = _extract_vulnerability_data(result, sarif_infos)
157
+ if not vuln_data:
158
+ LOGGER.warning(f"⚠️ Could not extract data for {result.get('ruleId')}")
159
+ return False
160
+
161
+ rule_id = result.get('ruleId', '')
162
+
163
+ if "(sca)" in rule_id.lower():
164
+ return _process_sca_vulnerability(conviso_api, asset_id, result, vuln_data)
165
+ elif "(sast)" in rule_id.lower():
166
+ return _process_sast_vulnerability(conviso_api, asset_id, result, vuln_data)
167
+ else:
168
+ return _process_sast_vulnerability(conviso_api, asset_id, result, vuln_data)
169
+
170
+ except Exception as e:
171
+ LOGGER.error(f"❌ Error processing vulnerability: {str(e)}")
172
+ return False
173
+
174
+
175
+ def _extract_vulnerability_data(result, sarif_infos):
176
+ try:
177
+ rule_id = result.get('ruleId')
178
+ matching_info = next((info for info in sarif_infos if info['id'] == rule_id), None)
179
+ title = None
180
+ references = None
181
+ description = None
182
+
183
+ if matching_info:
184
+ title = matching_info['name']
185
+ references = matching_info['references']
186
+ description = matching_info['description']
187
+
188
+ if not title:
189
+ title = result.get('message', {}).get('text', 'No title provided')
190
+ if not description:
191
+ description = result.get('message', {}).get('text', 'No description provided')
192
+
193
+ locations = result.get('locations', [])
194
+ if not locations:
195
+ LOGGER.warning(f"⚠️ No location found for {rule_id}")
196
+ return None
197
+
198
+ first_location = locations[0]
199
+ physical_location = first_location.get('physicalLocation', {})
200
+
201
+ return {
202
+ 'title': title,
203
+ 'references': references,
204
+ 'description': description,
205
+ 'severity': result.get('level', 'info'),
206
+ 'file_name': physical_location.get('artifactLocation', {}).get('uri'),
207
+ 'vulnerable_line': physical_location.get('region', {}).get('startLine'),
208
+ 'first_line': physical_location.get('region', {}).get('startLine', 1),
209
+ 'code_snippet': physical_location.get('contextRegion', {}).get('snippet', {}).get('text', ''),
210
+ }
211
+
212
+ except Exception as e:
213
+ LOGGER.error(f"❌ Error extracting vulnerability data: {str(e)}")
214
+ return None
215
+
216
+
217
+ def _process_sca_vulnerability(conviso_api, asset_id, result, vuln_data):
218
+ try:
219
+ message_text = result.get('message', {}).get('text', '')
220
+ sca_data = _parse_sca_data(message_text)
221
+
222
+ if not sca_data:
223
+ LOGGER.warning(f"⚠️ Could not extract SCA data from: {message_text}")
224
+ return False
225
+
226
+ create_sca_vulnerabilities(
227
+ conviso_api, asset_id, message_text,
228
+ vuln_data['references'], vuln_data['description'],
229
+ vuln_data['severity'], vuln_data['file_name'],
230
+ vuln_data['first_line'], sca_data['package'],
231
+ sca_data['version'], sca_data['cve']
232
+ )
233
+
234
+ return True
235
+
236
+ except Exception as e:
237
+ LOGGER.error(f"❌ Error processing SCA vulnerability: {str(e)}")
238
+ return False
239
+
240
+
241
+ def _parse_sca_data(message_text):
242
+ try:
243
+ if ':' not in message_text:
244
+ return None
245
+
246
+ package = message_text.split(':')[1].split(' ')[0]
247
+ version = package.split('-')[-1] if '-' in package else 'Unknown'
248
+ cve = 'Unknown'
249
+
250
+ if '(' in message_text and ')' in message_text:
251
+ parts = message_text.split(' ')
252
+ for part in parts:
253
+ if part.startswith('(') and part.endswith(')'):
254
+ cve = part.strip('()')
255
+ break
256
+
257
+ return {
258
+ 'package': package,
259
+ 'version': version,
260
+ 'cve': cve
261
+ }
262
+
263
+ except Exception as e:
264
+ LOGGER.error(f"❌ Error parsing SCA data: {str(e)}")
265
+ return None
266
+
267
+
268
+ def _process_sast_vulnerability(conviso_api, asset_id, result, vuln_data):
269
+ try:
270
+ create_sast_vulnerabilities(
271
+ conviso_api, asset_id, vuln_data['title'],
272
+ vuln_data['references'], vuln_data['description'],
273
+ vuln_data['vulnerable_line'], vuln_data['severity'],
274
+ vuln_data['file_name'], vuln_data['code_snippet'],
275
+ vuln_data['first_line'], None
276
+ )
277
+
278
+ return True
279
+
280
+ except Exception as e:
281
+ LOGGER.error(f"❌ Error processing SAST vulnerability: {str(e)}")
282
+ return False
283
+
284
+
285
+ def create_sast_vulnerabilities(conviso_api, asset_id, *args):
286
+ title, references, description, vulnerable_line, severity, file_name, code_snippet, first_line, cve = args
287
+
288
+ issue_model = CreateSastFindingInput(
289
+ asset_id=asset_id,
290
+ file_name=file_name,
291
+ vulnerable_line=vulnerable_line or 0,
292
+ title=title or 'No title provided',
293
+ description=description or 'No description provided',
294
+ severity=severity,
295
+ commit_ref=None,
296
+ deploy_id=None,
297
+ code_snippet=parse_code_snippet(code_snippet),
298
+ reference=parse_conviso_references(references),
299
+ first_line=first_line,
300
+ category=None,
301
+ original_issue_id_from_tool=None,
302
+ solution=None
303
+ )
304
+
305
+ try:
306
+ conviso_api.issues.create_sast(issue_model)
307
+ LOGGER.debug(f"✅ SAST vulnerability created: {title}")
308
+ except ResponseError as error:
309
+ if error.code == 'RECORD_NOT_UNIQUE':
310
+ LOGGER.debug(f"ℹ️ SAST vulnerability already exists: {title}")
311
+ else:
312
+ LOGGER.error(f"❌ Error creating SAST vulnerability: {error}")
313
+ raise
314
+ except Exception as e:
315
+ LOGGER.error(f"❌ Unexpected error creating SAST vulnerability: {str(e)}")
316
+ raise
317
+
318
+
319
+ def create_sca_vulnerabilities(conviso_api, asset_id, *args):
320
+ title, references, description, severity, file_name, first_line, package, version, cve = args
321
+
322
+ issue_model = CreateScaFindingInput(
323
+ asset_id=asset_id,
324
+ title=title,
325
+ description=description,
326
+ severity=severity,
327
+ solution="Update to the last package version.",
328
+ reference=references,
329
+ file_name=file_name,
330
+ affected_version=version,
331
+ package=package,
332
+ cve=cve,
333
+ patched_version='',
334
+ category='',
335
+ original_issue_id_from_tool=''
336
+ )
337
+
338
+ try:
339
+ conviso_api.issues.create_sca(issue_model)
340
+ LOGGER.debug(f"✅ SCA vulnerability created: {title}")
341
+ except ResponseError as error:
342
+ if error.code == 'RECORD_NOT_UNIQUE':
343
+ LOGGER.debug(f"ℹ️ SCA vulnerability already exists: {title}")
344
+ else:
345
+ LOGGER.error(f"❌ Error creating SCA vulnerability: {error}")
346
+ raise
347
+ except Exception as e:
348
+ LOGGER.error(f"❌ Unexpected error creating SCA vulnerability: {str(e)}")
349
+ raise
350
+
351
+
352
+ def parse_code_snippet(code_snippet):
353
+ try:
354
+ decoded_text = b64decode(code_snippet).decode("utf-8")
355
+ lines = decoded_text.split("\n")
356
+ cleaned_lines = []
357
+
358
+ for line in lines:
359
+ cleaned_line = line.split(": ", 1)[-1]
360
+ cleaned_lines.append(cleaned_line)
361
+
362
+ code_snippet = "\n".join(cleaned_lines)
363
+
364
+ return code_snippet
365
+ except Exception:
366
+ return code_snippet
367
+
368
+
369
+ def parse_conviso_references(references=[]):
370
+ if not references:
371
+ return ""
372
+
373
+ DIVIDER = "\n"
374
+
375
+ references_to_join = []
376
+
377
+ for reference in references:
378
+ if reference:
379
+ references_to_join.append(reference)
380
+
381
+ return DIVIDER.join(references_to_join)
382
+
383
+
384
+ def parse_first_line_number(encoded_base64):
385
+ decoded_text = b64decode(encoded_base64).decode("utf-8")
386
+
387
+ regex = r"^(\d+):"
388
+
389
+ result = regex_search(regex, decoded_text)
390
+
391
+ if result and result.group(1):
392
+ return result.group(1)
393
+
394
+ LINE_NUMBER_WHEN_NOT_FOUND = 1
395
+ return LINE_NUMBER_WHEN_NOT_FOUND
396
+
397
+
398
+ def clean_file(input_file):
399
+ with open(input_file, mode="rb") as file:
400
+ content = file.read()
401
+
402
+ if content.startswith(b'\xef\xbb\xbf'):
403
+ content = content[3:]
404
+
405
+ cleaned_file = input_file + ".cleaned"
406
+ with open(cleaned_file, mode="wb") as file:
407
+ file.write(content)
408
+
409
+ return cleaned_file
410
+
411
+
412
+ import_sarif.epilog = '''
413
+ '''
414
+ EPILOG = '''
415
+ Examples:
416
+
417
+ \b
418
+ 1 - Import results on SARIF file to Conviso Platform:
419
+ $ export CONVISO_API_KEY='your-api-key'
420
+ $ {command} --input-file /path/to/file.sarif
421
+
422
+ ''' # noqa: E501
423
+
424
+ SHORT_HELP = "Perform import of vulnerabilities from SARIF file to Conviso Platform"
425
+
426
+ command = 'conviso findings import-sarif'
427
+ import_sarif.short_help = SHORT_HELP
428
+ import_sarif.epilog = EPILOG.format(
429
+ command=command,
430
+ )
@@ -0,0 +1,18 @@
1
+ import click
2
+
3
+
4
+ def print_help(ctx, param, value):
5
+ if not value or ctx.resilient_parsing:
6
+ return
7
+ click.echo(ctx.get_help())
8
+ ctx.exit()
9
+
10
+
11
+ help_option = click.option(
12
+ '-h', '--help',
13
+ is_flag=True,
14
+ callback=print_help,
15
+ expose_value=False,
16
+ is_eager=True,
17
+ help="Show this message and exit."
18
+ )
@@ -0,0 +1,3 @@
1
+ from .entrypoint import iac
2
+
3
+ __all__ = ['iac']
@@ -0,0 +1,17 @@
1
+ import click
2
+
3
+ from convisoappsec.flowcli import help_option
4
+ from .run import run
5
+
6
+
7
+ @click.group()
8
+ @help_option
9
+ def iac():
10
+ pass
11
+
12
+
13
+ iac.add_command(run)
14
+
15
+ iac.epilog = '''
16
+ Run flow iac COMMAND --help for more information on a command.
17
+ '''