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,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,4 @@
1
+ from .entrypoint import create
2
+
3
+
4
+ __all__ = ['create']
@@ -0,0 +1,12 @@
1
+ import click
2
+
3
+
4
+ class CreateContext(object):
5
+
6
+ def __init__(self):
7
+ self.output_formatter = None
8
+
9
+
10
+ pass_create_context = click.make_pass_decorator(
11
+ CreateContext, ensure=True
12
+ )
@@ -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,3 @@
1
+ from .entrypoint import with_
2
+
3
+ __all__ = ['with_']
@@ -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,4 @@
1
+ from .entrypoint import tag_tracker
2
+
3
+
4
+ __all__ = ['tag_tracker']
@@ -0,0 +1,11 @@
1
+ import click
2
+
3
+
4
+ class TagTrackerWith(object):
5
+ def __init__(self):
6
+ self.repository_dir = None
7
+
8
+
9
+ pass_tag_tracker_context = click.make_pass_decorator(
10
+ TagTrackerWith, ensure=True
11
+ )
@@ -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,4 @@
1
+ from .entrypoint import sort_by
2
+
3
+
4
+ __all__ = ['sort_by']
@@ -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