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,175 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import json
|
|
3
|
+
import hashlib
|
|
4
|
+
from convisoappsec.flowcli.context import pass_flow_context
|
|
5
|
+
from convisoappsec.common.graphql.errors import ResponseError
|
|
6
|
+
|
|
7
|
+
class ContainerVulnerabilityManager:
|
|
8
|
+
"""
|
|
9
|
+
Manages the lifecycle of vulnerabilities detected in container/image scans, including closing and reopening.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self):
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
def close_vulnerability(self):
|
|
16
|
+
"""
|
|
17
|
+
Close vulnerabilities on conviso platform when is not detected anymore.
|
|
18
|
+
"""
|
|
19
|
+
result_file = "result.json"
|
|
20
|
+
hash_issues = []
|
|
21
|
+
|
|
22
|
+
log_func("Running automatic closure of vulnerabilities for image/container...")
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
with open(result_file, 'r') as file:
|
|
26
|
+
data = json.load(file)
|
|
27
|
+
results = data.get('Results', [])
|
|
28
|
+
|
|
29
|
+
for result in results:
|
|
30
|
+
if 'Vulnerabilities' in result and isinstance(result['Vulnerabilities'], list):
|
|
31
|
+
for vulnerability in result['Vulnerabilities']:
|
|
32
|
+
title = vulnerability.get('Title', '')
|
|
33
|
+
description = vulnerability.get('Description', '')
|
|
34
|
+
severity = vulnerability.get('Severity', '')
|
|
35
|
+
cve = vulnerability.get('VulnerabilityID', '')
|
|
36
|
+
package_name = vulnerability.get('PkgName', '')
|
|
37
|
+
|
|
38
|
+
hash_value = generate_hash_issue(title, description, severity, cve, package_name)
|
|
39
|
+
hash_issues.append(hash_value)
|
|
40
|
+
except FileNotFoundError:
|
|
41
|
+
print(f"Error: The file '{result_file}' was not found.")
|
|
42
|
+
except json.JSONDecodeError:
|
|
43
|
+
print(f"Error: Could not decode JSON from '{result_file}'. Check file format.")
|
|
44
|
+
except Exception as e:
|
|
45
|
+
print(f"An unexpected error occurred: {e}")
|
|
46
|
+
|
|
47
|
+
issues_from_conviso = fetch_and_merge_conviso_issues()
|
|
48
|
+
|
|
49
|
+
if len(issues_from_conviso) == 0:
|
|
50
|
+
log_func("No vulnerabilities were found on the Conviso Platform!")
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
issues_with_fix_accepted = [item for item in issues_from_conviso if item['status'] == 'FIX_ACCEPTED']
|
|
54
|
+
issues_without_fix_accepted = [item for item in issues_from_conviso if item['status'] != 'FIX_ACCEPTED']
|
|
55
|
+
set_of_hash_issues = set(hash_issues)
|
|
56
|
+
|
|
57
|
+
close_issues(issues_from_cp=issues_without_fix_accepted, issues_from_current_scan=set_of_hash_issues)
|
|
58
|
+
reopen_vulnerability(issues_with_fix_accepted=issues_with_fix_accepted, hash_issues=set_of_hash_issues)
|
|
59
|
+
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
def generate_hash_issue(title, description, severity, cve, package_name):
|
|
63
|
+
"""
|
|
64
|
+
Generates a SHA256 hash based on the provided vulnerability details.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
concatenated_string = f"{title}{description}{severity}{cve}{package_name}"
|
|
68
|
+
|
|
69
|
+
return hashlib.sha256(concatenated_string.encode('utf-8')).hexdigest()
|
|
70
|
+
|
|
71
|
+
@pass_flow_context
|
|
72
|
+
def close_issues(flow_context, issues_from_cp, issues_from_current_scan):
|
|
73
|
+
"""
|
|
74
|
+
method to close container issues on conviso platform
|
|
75
|
+
|
|
76
|
+
# issues_from_cp are issues already on conviso platform.
|
|
77
|
+
# issues_from_current_scan are issues identify on each time the ast command runs, these are always from a full code
|
|
78
|
+
base scan
|
|
79
|
+
"""
|
|
80
|
+
conviso_api = flow_context.create_conviso_api_client_beta()
|
|
81
|
+
differences = [
|
|
82
|
+
{'id': item['id'], 'originalIssueIdFromTool': item['originalIssueIdFromTool']}
|
|
83
|
+
for item in issues_from_cp if item['originalIssueIdFromTool'] not in issues_from_current_scan
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
if len(differences) == 0:
|
|
87
|
+
log_func("No vulnerabilities have been fixed yet...")
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
log_func("Container: Fixing {issues} vulnerabilities on the Conviso Platform...".format(issues=len(differences)))
|
|
91
|
+
|
|
92
|
+
for issue in differences:
|
|
93
|
+
issue_id = issue['id']
|
|
94
|
+
status = 'FIX_ACCEPTED'
|
|
95
|
+
reason = ("The vulnerability is no longer found in the specified image. Its status has been updated by "
|
|
96
|
+
"Conviso AST")
|
|
97
|
+
|
|
98
|
+
conviso_api.issues.update_issue_status(issue_id=issue_id, status=status, reason=reason)
|
|
99
|
+
|
|
100
|
+
@pass_flow_context
|
|
101
|
+
def reopen_vulnerability(flow_context, issues_with_fix_accepted, hash_issues):
|
|
102
|
+
"""
|
|
103
|
+
Reopen vulnerabilities on conviso platform when is detected and already exists on conviso platform and
|
|
104
|
+
was fixed in other moment.
|
|
105
|
+
"""
|
|
106
|
+
conviso_api = flow_context.create_conviso_api_client_beta()
|
|
107
|
+
|
|
108
|
+
issues_to_reopen = [
|
|
109
|
+
{'id': item['id'], 'originalIssueIdFromTool': item['originalIssueIdFromTool']}
|
|
110
|
+
for item in issues_with_fix_accepted if item['originalIssueIdFromTool'] in hash_issues
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
if issues_to_reopen:
|
|
114
|
+
log_func("Container: Reopening {issues} vulnerability/vulnerabilities on conviso platform ...".format(
|
|
115
|
+
issues=len(issues_to_reopen))
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
for issue in issues_to_reopen:
|
|
119
|
+
issue_id = issue['id']
|
|
120
|
+
status = 'IDENTIFIED'
|
|
121
|
+
reason = 'Status has been updated from Fixed to Identified by Conviso AST'
|
|
122
|
+
|
|
123
|
+
conviso_api.issues.update_issue_status(issue_id=issue_id, status=status, reason=reason)
|
|
124
|
+
|
|
125
|
+
@pass_flow_context
|
|
126
|
+
@click.pass_context
|
|
127
|
+
def fetch_and_merge_conviso_issues(context, flow_context):
|
|
128
|
+
page = 1
|
|
129
|
+
conviso_api = flow_context.create_conviso_api_client_beta()
|
|
130
|
+
company_id = context.params['company_id']
|
|
131
|
+
asset_id = context.params['asset_id']
|
|
132
|
+
statuses = ['CREATED', 'IDENTIFIED', 'IN_PROGRESS', 'AWAITING_VALIDATION', 'FIX_ACCEPTED']
|
|
133
|
+
merged_issues = []
|
|
134
|
+
|
|
135
|
+
while True:
|
|
136
|
+
try:
|
|
137
|
+
issues_from_cp = conviso_api.issues.auto_close_vulnerabilities(
|
|
138
|
+
company_id, asset_id, statuses, page, vulnerability_type='CONTAINER_FINDING'
|
|
139
|
+
)
|
|
140
|
+
except ResponseError as error:
|
|
141
|
+
if 'Variable $company_id' in str(error):
|
|
142
|
+
log_func(f"Invalid company_id passed: {company_id}", fg='red')
|
|
143
|
+
else:
|
|
144
|
+
log_func(f"error: {error}", fg='red')
|
|
145
|
+
|
|
146
|
+
log_func(
|
|
147
|
+
"⚠️ Auto-close will not be performed at this time. "
|
|
148
|
+
"Please set it using --company-id and try again.",
|
|
149
|
+
fg='red'
|
|
150
|
+
)
|
|
151
|
+
return None
|
|
152
|
+
|
|
153
|
+
total_pages = issues_from_cp['metadata']['totalPages']
|
|
154
|
+
issues_collection = issues_from_cp['collection']
|
|
155
|
+
|
|
156
|
+
issues_collection = [
|
|
157
|
+
item for item in issues_collection
|
|
158
|
+
if item.get('scanSource') == 'conviso_scanner'
|
|
159
|
+
]
|
|
160
|
+
container_issues = [
|
|
161
|
+
item for item in issues_collection
|
|
162
|
+
if item.get('type') == 'CONTAINER_FINDING'
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
if container_issues:
|
|
166
|
+
merged_issues.extend(container_issues)
|
|
167
|
+
|
|
168
|
+
if page >= total_pages:
|
|
169
|
+
break
|
|
170
|
+
page += 1
|
|
171
|
+
|
|
172
|
+
return merged_issues
|
|
173
|
+
|
|
174
|
+
def log_func(msg, new_line=True, fg='white'):
|
|
175
|
+
click.echo(click.style(msg, bold=True, fg=fg), nl=new_line, err=True)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from convisoappsec.flowcli import help_option
|
|
3
|
+
from .assert_security_rules import assert_security_rules
|
|
4
|
+
from .run import run
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@click.group()
|
|
8
|
+
@help_option
|
|
9
|
+
def vulnerability():
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
vulnerability.add_command(assert_security_rules)
|
|
14
|
+
vulnerability.add_command(run)
|
|
15
|
+
|
|
16
|
+
vulnerability.epilog = '''
|
|
17
|
+
Run flow vulnerability COMMAND --help for more information on a command.
|
|
18
|
+
'''
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"definitions": {
|
|
3
|
+
"criticity": {
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": [
|
|
6
|
+
"maximum"
|
|
7
|
+
],
|
|
8
|
+
"properties": {
|
|
9
|
+
"maximum": {
|
|
10
|
+
"type": "integer",
|
|
11
|
+
"minimum": 0
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"severity": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"minProperties": 1,
|
|
18
|
+
"patternProperties": {
|
|
19
|
+
"^(critical|high|medium|low)$": {
|
|
20
|
+
"$ref": "#/definitions/criticity"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"additionalProperties": false
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"type": "object",
|
|
27
|
+
"required": [
|
|
28
|
+
"rules"
|
|
29
|
+
],
|
|
30
|
+
"properties": {
|
|
31
|
+
"rules": {
|
|
32
|
+
"type": "array",
|
|
33
|
+
"default": [],
|
|
34
|
+
"items": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"required": [
|
|
37
|
+
"from",
|
|
38
|
+
"severity"
|
|
39
|
+
],
|
|
40
|
+
"properties": {
|
|
41
|
+
"from": {
|
|
42
|
+
"enum": [
|
|
43
|
+
"any"
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
"severity": {
|
|
47
|
+
"$ref": "#/definitions/severity"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|