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.
- conviso_ast-3.0.0.data/scripts/flow_bash_completer.sh +21 -0
- conviso_ast-3.0.0.data/scripts/flow_fish_completer.fish +1 -0
- conviso_ast-3.0.0.data/scripts/flow_zsh_completer.sh +32 -0
- conviso_ast-3.0.0.dist-info/METADATA +37 -0
- conviso_ast-3.0.0.dist-info/RECORD +128 -0
- conviso_ast-3.0.0.dist-info/WHEEL +5 -0
- conviso_ast-3.0.0.dist-info/entry_points.txt +3 -0
- conviso_ast-3.0.0.dist-info/top_level.txt +1 -0
- convisoappsec/__init__.py +0 -0
- convisoappsec/common/__init__.py +5 -0
- convisoappsec/common/box.py +251 -0
- convisoappsec/common/cleaner.py +78 -0
- convisoappsec/common/docker.py +399 -0
- convisoappsec/common/exceptions.py +8 -0
- convisoappsec/common/git_data_parser.py +76 -0
- convisoappsec/common/graphql/__init__.py +0 -0
- convisoappsec/common/graphql/error_handlers.py +75 -0
- convisoappsec/common/graphql/errors.py +16 -0
- convisoappsec/common/graphql/low_client.py +51 -0
- convisoappsec/common/retry_handler.py +40 -0
- convisoappsec/common/strings.py +8 -0
- convisoappsec/flow/__init__.py +3 -0
- convisoappsec/flow/api.py +104 -0
- convisoappsec/flow/cleaner.py +118 -0
- convisoappsec/flow/graphql_api/__init__.py +0 -0
- convisoappsec/flow/graphql_api/beta/__init__.py +0 -0
- convisoappsec/flow/graphql_api/beta/client.py +18 -0
- convisoappsec/flow/graphql_api/beta/models/__init__.py +0 -0
- convisoappsec/flow/graphql_api/beta/models/issues/__init__.py +0 -0
- convisoappsec/flow/graphql_api/beta/models/issues/container.py +72 -0
- convisoappsec/flow/graphql_api/beta/models/issues/iac.py +6 -0
- convisoappsec/flow/graphql_api/beta/models/issues/normalize.py +13 -0
- convisoappsec/flow/graphql_api/beta/models/issues/sast.py +53 -0
- convisoappsec/flow/graphql_api/beta/models/issues/sca.py +78 -0
- convisoappsec/flow/graphql_api/beta/resources_api.py +142 -0
- convisoappsec/flow/graphql_api/beta/schemas/__init__.py +0 -0
- convisoappsec/flow/graphql_api/beta/schemas/mutations/__init__.py +61 -0
- convisoappsec/flow/graphql_api/beta/schemas/resolvers/__init__.py +0 -0
- convisoappsec/flow/graphql_api/v1/__init__.py +0 -0
- convisoappsec/flow/graphql_api/v1/client.py +46 -0
- convisoappsec/flow/graphql_api/v1/models/__init__.py +0 -0
- convisoappsec/flow/graphql_api/v1/models/asset.py +14 -0
- convisoappsec/flow/graphql_api/v1/models/issues.py +16 -0
- convisoappsec/flow/graphql_api/v1/models/project.py +35 -0
- convisoappsec/flow/graphql_api/v1/resources_api.py +489 -0
- convisoappsec/flow/graphql_api/v1/schemas/__init__.py +0 -0
- convisoappsec/flow/graphql_api/v1/schemas/mutations/__init__.py +212 -0
- convisoappsec/flow/graphql_api/v1/schemas/resolvers/__init__.py +180 -0
- convisoappsec/flow/source_code_scanner/__init__.py +9 -0
- convisoappsec/flow/source_code_scanner/exceptions.py +2 -0
- convisoappsec/flow/source_code_scanner/scc.py +68 -0
- convisoappsec/flow/source_code_scanner/source_code_scanner.py +177 -0
- convisoappsec/flow/util/__init__.py +7 -0
- convisoappsec/flow/util/ci_provider.py +99 -0
- convisoappsec/flow/util/metrics.py +16 -0
- convisoappsec/flow/util/source_code_compressor.py +22 -0
- convisoappsec/flow/version_control_system_adapter.py +528 -0
- convisoappsec/flow/version_searchers/__init__.py +9 -0
- convisoappsec/flow/version_searchers/sorted_by_versioning_style.py +85 -0
- convisoappsec/flow/version_searchers/timebased_version_seacher.py +39 -0
- convisoappsec/flow/version_searchers/version_searcher_result.py +33 -0
- convisoappsec/flow/versioning_style/__init__.py +0 -0
- convisoappsec/flow/versioning_style/semantic_versioning.py +44 -0
- convisoappsec/flowcli/__init__.py +3 -0
- convisoappsec/flowcli/__main__.py +4 -0
- convisoappsec/flowcli/assets/__init__.py +4 -0
- convisoappsec/flowcli/assets/create.py +88 -0
- convisoappsec/flowcli/assets/entrypoint.py +20 -0
- convisoappsec/flowcli/assets/ls.py +63 -0
- convisoappsec/flowcli/ast/__init__.py +3 -0
- convisoappsec/flowcli/ast/entrypoint.py +427 -0
- convisoappsec/flowcli/common.py +175 -0
- convisoappsec/flowcli/companies/__init__.py +0 -0
- convisoappsec/flowcli/companies/ls.py +25 -0
- convisoappsec/flowcli/container/__init__.py +3 -0
- convisoappsec/flowcli/container/entrypoint.py +17 -0
- convisoappsec/flowcli/container/run.py +306 -0
- convisoappsec/flowcli/context.py +49 -0
- convisoappsec/flowcli/deploy/__init__.py +0 -0
- convisoappsec/flowcli/deploy/create/__init__.py +4 -0
- convisoappsec/flowcli/deploy/create/context.py +12 -0
- convisoappsec/flowcli/deploy/create/entrypoint.py +31 -0
- convisoappsec/flowcli/deploy/create/with_/__init__.py +3 -0
- convisoappsec/flowcli/deploy/create/with_/entrypoint.py +20 -0
- convisoappsec/flowcli/deploy/create/with_/tag_tracker/__init__.py +4 -0
- convisoappsec/flowcli/deploy/create/with_/tag_tracker/context.py +11 -0
- convisoappsec/flowcli/deploy/create/with_/tag_tracker/entrypoint.py +30 -0
- convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/__init__.py +4 -0
- convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/entrypoint.py +21 -0
- convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/time_.py +84 -0
- convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/versioning_style.py +115 -0
- convisoappsec/flowcli/deploy/create/with_/values.py +133 -0
- convisoappsec/flowcli/entrypoint.py +103 -0
- convisoappsec/flowcli/environment_checker.py +45 -0
- convisoappsec/flowcli/findings/__init__.py +4 -0
- convisoappsec/flowcli/findings/create/__init__.py +4 -0
- convisoappsec/flowcli/findings/create/entrypoint.py +18 -0
- convisoappsec/flowcli/findings/create/with_/__init__.py +3 -0
- convisoappsec/flowcli/findings/create/with_/entrypoint.py +19 -0
- convisoappsec/flowcli/findings/create/with_/version_tracker.py +93 -0
- convisoappsec/flowcli/findings/entrypoint.py +19 -0
- convisoappsec/flowcli/findings/import_sarif/__init__.py +4 -0
- convisoappsec/flowcli/findings/import_sarif/entrypoint.py +430 -0
- convisoappsec/flowcli/help_option.py +18 -0
- convisoappsec/flowcli/iac/__init__.py +3 -0
- convisoappsec/flowcli/iac/entrypoint.py +17 -0
- convisoappsec/flowcli/iac/run.py +328 -0
- convisoappsec/flowcli/requirements_verifier.py +132 -0
- convisoappsec/flowcli/sast/__init__.py +3 -0
- convisoappsec/flowcli/sast/entrypoint.py +17 -0
- convisoappsec/flowcli/sast/run.py +485 -0
- convisoappsec/flowcli/sbom/__init__.py +3 -0
- convisoappsec/flowcli/sbom/entrypoint.py +17 -0
- convisoappsec/flowcli/sbom/generate.py +235 -0
- convisoappsec/flowcli/sca/__init__.py +3 -0
- convisoappsec/flowcli/sca/entrypoint.py +17 -0
- convisoappsec/flowcli/sca/run.py +479 -0
- convisoappsec/flowcli/vulnerability/__init__.py +3 -0
- convisoappsec/flowcli/vulnerability/assert_security_rules.py +201 -0
- convisoappsec/flowcli/vulnerability/container_vulnerability_manager.py +175 -0
- convisoappsec/flowcli/vulnerability/entrypoint.py +18 -0
- convisoappsec/flowcli/vulnerability/rules_schema.json +53 -0
- convisoappsec/flowcli/vulnerability/run.py +487 -0
- convisoappsec/logger.py +29 -0
- convisoappsec/sast/__init__.py +0 -0
- convisoappsec/sast/decision.py +45 -0
- convisoappsec/sast/sastbox.py +296 -0
- convisoappsec/version.py +1 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import traceback
|
|
2
|
+
import click
|
|
3
|
+
import json
|
|
4
|
+
import subprocess
|
|
5
|
+
import shutil
|
|
6
|
+
import os
|
|
7
|
+
import datetime
|
|
8
|
+
from convisoappsec.flowcli import help_option
|
|
9
|
+
from convisoappsec.flowcli.context import pass_flow_context
|
|
10
|
+
from convisoappsec.logger import log_and_notify_ast_event
|
|
11
|
+
from convisoappsec.flowcli.requirements_verifier import RequirementsVerifier
|
|
12
|
+
from copy import deepcopy as clone
|
|
13
|
+
from convisoappsec.flowcli.common import asset_id_option
|
|
14
|
+
from convisoappsec.flowcli.vulnerability.container_vulnerability_manager import ContainerVulnerabilityManager
|
|
15
|
+
|
|
16
|
+
DEBUG_MODE = False
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@click.command()
|
|
20
|
+
@asset_id_option(required=False)
|
|
21
|
+
@click.option(
|
|
22
|
+
'--debug',
|
|
23
|
+
is_flag=True,
|
|
24
|
+
help='Enable debug mode.'
|
|
25
|
+
)
|
|
26
|
+
@click.option(
|
|
27
|
+
'-r',
|
|
28
|
+
'--repository-dir',
|
|
29
|
+
default=".",
|
|
30
|
+
show_default=True,
|
|
31
|
+
type=click.Path(
|
|
32
|
+
exists=True,
|
|
33
|
+
resolve_path=True,
|
|
34
|
+
),
|
|
35
|
+
required=False,
|
|
36
|
+
help="The source code repository directory.",
|
|
37
|
+
)
|
|
38
|
+
@click.option(
|
|
39
|
+
"--send-to-flow/--no-send-to-flow",
|
|
40
|
+
default=True,
|
|
41
|
+
show_default=True,
|
|
42
|
+
required=False,
|
|
43
|
+
hidden=True,
|
|
44
|
+
help="""Enable or disable the ability of send analysis result
|
|
45
|
+
reports to flow.""",
|
|
46
|
+
)
|
|
47
|
+
@click.option(
|
|
48
|
+
"--company-id",
|
|
49
|
+
required=False,
|
|
50
|
+
envvar=("CONVISO_COMPANY_ID", "FLOW_COMPANY_ID"),
|
|
51
|
+
help="Company ID on Conviso Platform",
|
|
52
|
+
)
|
|
53
|
+
@click.option(
|
|
54
|
+
'--asset-name',
|
|
55
|
+
required=False,
|
|
56
|
+
envvar=("CONVISO_ASSET_NAME", "FLOW_ASSET_NAME"),
|
|
57
|
+
help="Provides a asset name.",
|
|
58
|
+
)
|
|
59
|
+
@click.option(
|
|
60
|
+
'--vulnerability-auto-close',
|
|
61
|
+
default=False,
|
|
62
|
+
is_flag=True,
|
|
63
|
+
hidden=True,
|
|
64
|
+
help="Enable auto fixing vulnerabilities on cp.",
|
|
65
|
+
)
|
|
66
|
+
@click.argument('image_name')
|
|
67
|
+
@help_option
|
|
68
|
+
@pass_flow_context
|
|
69
|
+
@click.pass_context
|
|
70
|
+
def run(
|
|
71
|
+
context, flow_context, asset_id, debug, company_id, repository_dir,
|
|
72
|
+
send_to_flow, asset_name, vulnerability_auto_close, image_name,
|
|
73
|
+
|
|
74
|
+
):
|
|
75
|
+
""" Run command for container vulnerability scan focused on OS vulnerabilities """
|
|
76
|
+
global DEBUG_MODE
|
|
77
|
+
DEBUG_MODE = debug
|
|
78
|
+
start_time = datetime.datetime.now()
|
|
79
|
+
|
|
80
|
+
if send_to_flow:
|
|
81
|
+
prepared_context = RequirementsVerifier.prepare_context(clone(context))
|
|
82
|
+
|
|
83
|
+
if debug:
|
|
84
|
+
debug_message(f"Context after being prepared: {prepared_context.params}")
|
|
85
|
+
|
|
86
|
+
params_to_copy = [
|
|
87
|
+
'asset_id', 'send_to_flow', 'asset_name', 'vulnerability_auto_close',
|
|
88
|
+
'repository_dir', 'company_id'
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
for param_name in params_to_copy:
|
|
92
|
+
context.params[param_name] = (
|
|
93
|
+
locals()[param_name] or prepared_context.params[param_name]
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
asset_id = context.params['asset_id']
|
|
97
|
+
company_id = context.params['company_id']
|
|
98
|
+
else:
|
|
99
|
+
# this just verify if the api key is valid.
|
|
100
|
+
RequirementsVerifier.list_assets(company_id=company_id, asset_name='example', scan_type='SAST')
|
|
101
|
+
|
|
102
|
+
if debug:
|
|
103
|
+
debug_message("User validated!")
|
|
104
|
+
|
|
105
|
+
if command_exists('trivy'):
|
|
106
|
+
if debug:
|
|
107
|
+
debug_message("Trivy already installed.")
|
|
108
|
+
|
|
109
|
+
scan_command = f"trivy image --pkg-types os --format json --output result.json {image_name}"
|
|
110
|
+
else:
|
|
111
|
+
if debug:
|
|
112
|
+
debug_message("Installing trivy ...")
|
|
113
|
+
|
|
114
|
+
subprocess.run(
|
|
115
|
+
"curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b conviso/ v0.57.1",
|
|
116
|
+
shell=True,
|
|
117
|
+
stdout=subprocess.DEVNULL,
|
|
118
|
+
stderr=subprocess.DEVNULL
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
if debug:
|
|
122
|
+
debug_message("Trivy has been installed successfully!")
|
|
123
|
+
|
|
124
|
+
scan_command = [f"./conviso/trivy image --pkg-types os --format json --output result.json {image_name}"]
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
log_func(f"🔧 Scanning image {image_name} ...")
|
|
128
|
+
|
|
129
|
+
if debug:
|
|
130
|
+
debug_message(f"Running the following command: {scan_command}")
|
|
131
|
+
|
|
132
|
+
run_command(scan_command)
|
|
133
|
+
log_func("✅ Scan completed successfully.")
|
|
134
|
+
|
|
135
|
+
directory = 'conviso/'
|
|
136
|
+
if os.path.isdir(directory):
|
|
137
|
+
if debug:
|
|
138
|
+
debug_message(f"Removing the trivy installation dir, {directory}")
|
|
139
|
+
shutil.rmtree(directory)
|
|
140
|
+
|
|
141
|
+
if send_to_flow:
|
|
142
|
+
send_to_conviso_plataform(flow_context, asset_id, company_id)
|
|
143
|
+
else:
|
|
144
|
+
output_results()
|
|
145
|
+
|
|
146
|
+
end_time = datetime.datetime.now()
|
|
147
|
+
|
|
148
|
+
if debug:
|
|
149
|
+
execution_time = end_time - start_time
|
|
150
|
+
debug_message(f"Total execution time: {execution_time.total_seconds():.2f} seconds.")
|
|
151
|
+
|
|
152
|
+
try:
|
|
153
|
+
if vulnerability_auto_close is True:
|
|
154
|
+
vulnerability_manager = ContainerVulnerabilityManager()
|
|
155
|
+
vulnerability_manager.close_vulnerability()
|
|
156
|
+
except Exception:
|
|
157
|
+
log_func("An issue occurred while attempting to fix vulnerabilities. Our technical team has been notified.")
|
|
158
|
+
return
|
|
159
|
+
|
|
160
|
+
except Exception as error:
|
|
161
|
+
log_func(f"❌ Scan failed: {error}")
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def run_command(command):
|
|
165
|
+
"""
|
|
166
|
+
Runs a shell command and logs its execution.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
command (str): The scan command to execute.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
The result of a subproccess execution.
|
|
173
|
+
"""
|
|
174
|
+
result = subprocess.run(command, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
175
|
+
|
|
176
|
+
return result
|
|
177
|
+
|
|
178
|
+
def send_to_conviso_plataform(flow_context, asset_id, company_id):
|
|
179
|
+
"""
|
|
180
|
+
Process and send result to conviso platform.
|
|
181
|
+
|
|
182
|
+
This method read the result file, parse and try to send all founded vulnerabilities
|
|
183
|
+
If in any part of the process receive an error, should notify the ast-channel on conviso slack.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
conviso_api (object): Responsable to comunicate with conviso graphql api.
|
|
187
|
+
flow_content (object): Some helper methods.
|
|
188
|
+
asset_id (int): The asset where the result will be sended.
|
|
189
|
+
company_id (int): The user company on conviso platform.
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
str: Could return a message inform about no vulnerabilities or None
|
|
193
|
+
"""
|
|
194
|
+
log_func("🔧 Processing results ...")
|
|
195
|
+
result_file = "result.json"
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
vulnerabilities = extract_vulnerabilities(result_file)
|
|
199
|
+
|
|
200
|
+
if vulnerabilities:
|
|
201
|
+
log_func("🔍 Sending vulnerabilities to conviso platform.")
|
|
202
|
+
api_key = flow_context.key
|
|
203
|
+
conviso_api = flow_context.create_conviso_graphql_client()
|
|
204
|
+
conviso_api.container.send_container_file(
|
|
205
|
+
company_id=company_id, asset_id=asset_id, file_path=result_file, api_key=api_key
|
|
206
|
+
)
|
|
207
|
+
log_func("✅ Successfully!")
|
|
208
|
+
else:
|
|
209
|
+
log_func("✅ No vulnerabilities found.")
|
|
210
|
+
|
|
211
|
+
except FileNotFoundError:
|
|
212
|
+
log_func(f"❌ {result_file} not found. Ensure the scan was successful.")
|
|
213
|
+
full_trace = traceback.format_exc()
|
|
214
|
+
log_and_notify_ast_event(
|
|
215
|
+
flow_context=flow_context, company_id=company_id, asset_id=asset_id, ast_log=full_trace
|
|
216
|
+
)
|
|
217
|
+
except json.JSONDecodeError:
|
|
218
|
+
log_func(f"❌ Failed to parse {result_file}. Ensure it is valid JSON.")
|
|
219
|
+
full_trace = traceback.format_exc()
|
|
220
|
+
log_and_notify_ast_event(
|
|
221
|
+
flow_context=flow_context, company_id=company_id, asset_id=asset_id, ast_log=full_trace
|
|
222
|
+
)
|
|
223
|
+
except Exception:
|
|
224
|
+
full_trace = traceback.format_exc()
|
|
225
|
+
log_func(f"❌ An error occurred while processing results: {full_trace}")
|
|
226
|
+
log_and_notify_ast_event(
|
|
227
|
+
flow_context=flow_context, company_id=company_id, asset_id=asset_id, ast_log=full_trace
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def output_results():
|
|
232
|
+
"""
|
|
233
|
+
Output the scan result in case the user don't want to send to conviso platform.
|
|
234
|
+
"""
|
|
235
|
+
result_file = "result.json"
|
|
236
|
+
|
|
237
|
+
try:
|
|
238
|
+
vulnerabilities = extract_vulnerabilities(result_file)
|
|
239
|
+
|
|
240
|
+
if vulnerabilities:
|
|
241
|
+
log_func(f"🔍 Found: {len(vulnerabilities)} vulnerabilities!")
|
|
242
|
+
else:
|
|
243
|
+
log_func("✅ No vulnerabilities found.")
|
|
244
|
+
|
|
245
|
+
except Exception:
|
|
246
|
+
full_trace = traceback.format_exc()
|
|
247
|
+
log_func(f"❌ An error occurred while processing results: {full_trace}")
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def command_exists(command):
|
|
251
|
+
"""
|
|
252
|
+
Validates if a command exists.
|
|
253
|
+
|
|
254
|
+
Args: command (str): Command to validate.
|
|
255
|
+
Returns:
|
|
256
|
+
bool: True if the command exists.
|
|
257
|
+
"""
|
|
258
|
+
return shutil.which(command) is not None
|
|
259
|
+
|
|
260
|
+
def extract_vulnerabilities(result_file):
|
|
261
|
+
"""Reads a JSON scan result file and extracts vulnerabilities."""
|
|
262
|
+
with open(result_file, 'r') as file:
|
|
263
|
+
scan_results = json.load(file)
|
|
264
|
+
|
|
265
|
+
results = scan_results.get("Results", [])
|
|
266
|
+
if results and isinstance(results, list) and len(results) > 0:
|
|
267
|
+
return results[0].get("Vulnerabilities", [])
|
|
268
|
+
|
|
269
|
+
return []
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def log_func(msg, new_line=True):
|
|
273
|
+
"""
|
|
274
|
+
Output a message to the console with styled formatting.
|
|
275
|
+
|
|
276
|
+
This function uses `click` to output a styled message to the console. It supports
|
|
277
|
+
controlling whether the message ends with a newline and writes the output to `stderr`.
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
msg (str): The message to log.
|
|
281
|
+
new_line (bool, optional): Whether to append a newline at the end of the message.
|
|
282
|
+
Defaults to True.
|
|
283
|
+
|
|
284
|
+
Returns:
|
|
285
|
+
str: The output of the message.
|
|
286
|
+
"""
|
|
287
|
+
click.echo(click.style(msg), nl=new_line, err=True)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def debug_message(msg, new_line=True):
|
|
291
|
+
"""
|
|
292
|
+
If debug mode is enabled, this function should be
|
|
293
|
+
used for all debug messages and the message will be styled in orange.
|
|
294
|
+
Otherwise, it uses the default styling.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
msg (str): The message to log.
|
|
298
|
+
new_line (bool, optional): Whether to append a newline at the end of the message.
|
|
299
|
+
Defaults to True.
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
str: The output of the message.
|
|
303
|
+
"""
|
|
304
|
+
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
305
|
+
style = {"fg": "bright_yellow"} if DEBUG_MODE else {}
|
|
306
|
+
click.echo(click.style(f"🪲 [{timestamp}] DEBUG: {msg}", **style), nl=new_line, err=True)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from convisoappsec.common import safe_join_url
|
|
4
|
+
from convisoappsec.flow import api
|
|
5
|
+
from convisoappsec.flow.graphql_api.beta.client import ConvisoGraphQLClientBeta
|
|
6
|
+
from convisoappsec.flow.graphql_api.v1.client import ConvisoGraphQLClient
|
|
7
|
+
from convisoappsec.version import __version__
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class FlowContext(object):
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self.key = None
|
|
13
|
+
self.url = None
|
|
14
|
+
self.insecure = None
|
|
15
|
+
self.ci_provider = None
|
|
16
|
+
self.logger = None
|
|
17
|
+
|
|
18
|
+
def create_conviso_rest_api_client(self):
|
|
19
|
+
return api.RESTClient(
|
|
20
|
+
key=self.key,
|
|
21
|
+
url=self.url,
|
|
22
|
+
insecure=self.insecure,
|
|
23
|
+
user_agent={
|
|
24
|
+
'name': 'flowcli',
|
|
25
|
+
'version': __version__,
|
|
26
|
+
},
|
|
27
|
+
ci_provider_name=self.ci_provider.name
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def create_conviso_graphql_client(self):
|
|
31
|
+
url = safe_join_url(self.url, "/graphql")
|
|
32
|
+
|
|
33
|
+
return ConvisoGraphQLClient(
|
|
34
|
+
api_url=url,
|
|
35
|
+
api_key=self.key
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def create_conviso_api_client_beta(self):
|
|
39
|
+
url = safe_join_url(self.url, "/graphql")
|
|
40
|
+
|
|
41
|
+
return ConvisoGraphQLClientBeta(
|
|
42
|
+
api_url=url,
|
|
43
|
+
api_key=self.key,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
pass_flow_context = click.make_pass_decorator(
|
|
48
|
+
FlowContext, ensure=True
|
|
49
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from convisoappsec.flowcli import help_option
|
|
4
|
+
from convisoappsec.flowcli.common import DeployFormatter
|
|
5
|
+
|
|
6
|
+
from .context import pass_create_context
|
|
7
|
+
from .with_ import with_
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@click.group()
|
|
11
|
+
@click.option(
|
|
12
|
+
'-f',
|
|
13
|
+
'--output-format',
|
|
14
|
+
required=False,
|
|
15
|
+
type=click.Choice(DeployFormatter.FORMATS()),
|
|
16
|
+
default=DeployFormatter.DEFAULT,
|
|
17
|
+
show_default=True,
|
|
18
|
+
)
|
|
19
|
+
@help_option
|
|
20
|
+
@pass_create_context
|
|
21
|
+
def create(create_context, output_format):
|
|
22
|
+
create_context.output_formatter = DeployFormatter(
|
|
23
|
+
format=output_format,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
create.add_command(with_)
|
|
28
|
+
|
|
29
|
+
create.epilog = '''
|
|
30
|
+
Run flow deploy create COMMAND --help for more information on a command.
|
|
31
|
+
'''
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from convisoappsec.flowcli import help_option
|
|
4
|
+
|
|
5
|
+
from .values import values
|
|
6
|
+
from .tag_tracker import tag_tracker
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.group('with')
|
|
10
|
+
@help_option
|
|
11
|
+
def with_():
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
with_.add_command(values)
|
|
16
|
+
with_.add_command(tag_tracker)
|
|
17
|
+
|
|
18
|
+
with_.epilog = '''
|
|
19
|
+
Run flow deploy create with COMMAND --help for more information on a command.
|
|
20
|
+
'''
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from convisoappsec.flowcli import help_option
|
|
4
|
+
|
|
5
|
+
from .context import pass_tag_tracker_context
|
|
6
|
+
from .sort_by import sort_by
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.group()
|
|
10
|
+
@help_option
|
|
11
|
+
@click.option(
|
|
12
|
+
"-r",
|
|
13
|
+
"--repository-dir",
|
|
14
|
+
required=False,
|
|
15
|
+
type=click.Path(exists=True, resolve_path=True),
|
|
16
|
+
default='.',
|
|
17
|
+
show_default=True,
|
|
18
|
+
help="Repository dir to track version tags.",
|
|
19
|
+
)
|
|
20
|
+
@pass_tag_tracker_context
|
|
21
|
+
def tag_tracker(tag_tracker_context, repository_dir):
|
|
22
|
+
tag_tracker_context.repository_dir = repository_dir
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
tag_tracker.add_command(sort_by)
|
|
26
|
+
|
|
27
|
+
tag_tracker.epilog = '''
|
|
28
|
+
Run flow deploy create with tag-tracker COMMAND --help for
|
|
29
|
+
more information on a command.
|
|
30
|
+
'''
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from convisoappsec.flowcli import help_option
|
|
4
|
+
|
|
5
|
+
from .time_ import time_
|
|
6
|
+
from .versioning_style import versioning_style
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.group()
|
|
10
|
+
@help_option
|
|
11
|
+
def sort_by():
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
sort_by.add_command(time_)
|
|
16
|
+
sort_by.add_command(versioning_style)
|
|
17
|
+
|
|
18
|
+
sort_by.epilog = '''
|
|
19
|
+
Run flow deploy create with tag-tracker sort-by COMMAND --help
|
|
20
|
+
for more information on a command.
|
|
21
|
+
'''
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import click
|
|
2
|
+
# TODO: refactoring. all deploy create share some behavior
|
|
3
|
+
from convisoappsec.flow.util import project_metrics
|
|
4
|
+
from convisoappsec.flow.version_searchers import TimeBasedVersionSearcher
|
|
5
|
+
from convisoappsec.flow.version_control_system_adapter import GitAdapter
|
|
6
|
+
from convisoappsec.flowcli.context import pass_flow_context
|
|
7
|
+
from convisoappsec.flowcli import help_option
|
|
8
|
+
from convisoappsec.flowcli.common import on_http_error
|
|
9
|
+
from convisoappsec.flowcli.deploy.create.context import pass_create_context
|
|
10
|
+
from convisoappsec.flowcli.deploy.create.with_.tag_tracker.context import (
|
|
11
|
+
pass_tag_tracker_context
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@click.command('time')
|
|
16
|
+
@help_option
|
|
17
|
+
@click.option(
|
|
18
|
+
"--attach-diff/--no-attach-diff",
|
|
19
|
+
default=True,
|
|
20
|
+
show_default=True,
|
|
21
|
+
required=False,
|
|
22
|
+
)
|
|
23
|
+
@pass_tag_tracker_context
|
|
24
|
+
@pass_create_context
|
|
25
|
+
@pass_flow_context
|
|
26
|
+
def time_(flow_context, create_context, tag_tracker_context, attach_diff):
|
|
27
|
+
try:
|
|
28
|
+
repository_dir = tag_tracker_context.repository_dir
|
|
29
|
+
git_adapter = GitAdapter(repository_dir)
|
|
30
|
+
|
|
31
|
+
version_searcher = TimeBasedVersionSearcher(
|
|
32
|
+
git_adapter
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
result = version_searcher.find_current_and_previous_version()
|
|
36
|
+
current_version = result.current_version
|
|
37
|
+
previous_version = result.previous_version
|
|
38
|
+
diff_content = None
|
|
39
|
+
|
|
40
|
+
current_commit = current_version.get('commit')
|
|
41
|
+
previous_commit = previous_version.get('commit')
|
|
42
|
+
|
|
43
|
+
if previous_commit == current_commit:
|
|
44
|
+
import sys
|
|
45
|
+
click.echo(
|
|
46
|
+
"Previous commit ({0}) and Current commit ({1}) are the same, nothing to do.".format(
|
|
47
|
+
previous_commit, current_commit
|
|
48
|
+
),
|
|
49
|
+
file=sys.stderr
|
|
50
|
+
)
|
|
51
|
+
return
|
|
52
|
+
|
|
53
|
+
if attach_diff:
|
|
54
|
+
diff_content = git_adapter.diff(
|
|
55
|
+
previous_commit,
|
|
56
|
+
current_commit,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
deploy_metrics = git_adapter.diff_stats(
|
|
60
|
+
previous_commit,
|
|
61
|
+
current_commit,
|
|
62
|
+
).dict
|
|
63
|
+
|
|
64
|
+
flow = flow_context.create_conviso_rest_api_client()
|
|
65
|
+
|
|
66
|
+
authors_data = git_adapter.get_commit_authors_by_range(
|
|
67
|
+
previous_commit, current_commit
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
deploy = flow.deploys.create(
|
|
71
|
+
current_version=current_version,
|
|
72
|
+
previous_version=previous_version,
|
|
73
|
+
diff_content=diff_content,
|
|
74
|
+
metrics=deploy_metrics,
|
|
75
|
+
project_metrics=project_metrics(repository_dir),
|
|
76
|
+
commit_authors=authors_data
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
click.echo(
|
|
80
|
+
create_context.output_formatter.format(deploy)
|
|
81
|
+
)
|
|
82
|
+
except Exception as e:
|
|
83
|
+
on_http_error(e)
|
|
84
|
+
raise click.ClickException(str(e)) from e
|