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,115 @@
|
|
|
1
|
+
import click
|
|
2
|
+
# TODO: refactoring. all deploy create share some behavior
|
|
3
|
+
from convisoappsec.flow.util import project_metrics
|
|
4
|
+
from convisoappsec.flowcli.context import pass_flow_context
|
|
5
|
+
from convisoappsec.flow.version_searchers import SortedByVersioningStyle
|
|
6
|
+
from convisoappsec.flow.version_control_system_adapter import GitAdapter
|
|
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
|
+
|
|
11
|
+
from convisoappsec.flowcli.deploy.create.with_.tag_tracker.context import (
|
|
12
|
+
pass_tag_tracker_context
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@click.command()
|
|
17
|
+
@click.option(
|
|
18
|
+
'-c',
|
|
19
|
+
'--current-tag',
|
|
20
|
+
required=False,
|
|
21
|
+
help="""This value is used to ignore versions
|
|
22
|
+
bigger than this value if exists"""
|
|
23
|
+
)
|
|
24
|
+
@click.option(
|
|
25
|
+
'-i',
|
|
26
|
+
'--ignore-prefix',
|
|
27
|
+
required=False,
|
|
28
|
+
default='v',
|
|
29
|
+
show_default=True,
|
|
30
|
+
help="Prefix to be ignored on parsing to versioning style.",
|
|
31
|
+
)
|
|
32
|
+
@click.option(
|
|
33
|
+
'-s',
|
|
34
|
+
'--style',
|
|
35
|
+
required=False,
|
|
36
|
+
type=click.Choice(SortedByVersioningStyle.STYLES),
|
|
37
|
+
default=SortedByVersioningStyle.SEMANTIC_VERSIONING_STYLE,
|
|
38
|
+
show_default=True,
|
|
39
|
+
help="Versioning style type used at repository.",
|
|
40
|
+
)
|
|
41
|
+
@click.option(
|
|
42
|
+
"--attach-diff/--no-attach-diff",
|
|
43
|
+
default=True,
|
|
44
|
+
show_default=True,
|
|
45
|
+
required=False,
|
|
46
|
+
)
|
|
47
|
+
@help_option
|
|
48
|
+
@pass_tag_tracker_context
|
|
49
|
+
@pass_create_context
|
|
50
|
+
@pass_flow_context
|
|
51
|
+
def versioning_style(
|
|
52
|
+
flow_context, create_context, tag_tracker_context, ignore_prefix, style,
|
|
53
|
+
current_tag, attach_diff
|
|
54
|
+
):
|
|
55
|
+
try:
|
|
56
|
+
repository_dir = tag_tracker_context.repository_dir
|
|
57
|
+
git_adapter = GitAdapter(repository_dir)
|
|
58
|
+
|
|
59
|
+
searcher = SortedByVersioningStyle(
|
|
60
|
+
git_adapter,
|
|
61
|
+
ignore_prefix,
|
|
62
|
+
style,
|
|
63
|
+
current_tag,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
result = searcher.find_current_and_previous_version()
|
|
67
|
+
current_version = result.current_version
|
|
68
|
+
previous_version = result.previous_version
|
|
69
|
+
diff_content = None
|
|
70
|
+
|
|
71
|
+
current_commit = current_version.get('commit')
|
|
72
|
+
previous_commit = previous_version.get('commit')
|
|
73
|
+
|
|
74
|
+
if previous_commit == current_commit:
|
|
75
|
+
import sys
|
|
76
|
+
click.echo(
|
|
77
|
+
"Previous commit ({0}) and Current commit ({1}) are the same, nothing to do.".format(
|
|
78
|
+
previous_commit, current_commit
|
|
79
|
+
),
|
|
80
|
+
file=sys.stderr
|
|
81
|
+
)
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
if attach_diff:
|
|
85
|
+
diff_content = git_adapter.diff(
|
|
86
|
+
previous_commit,
|
|
87
|
+
current_commit,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
deploy_metrics = git_adapter.diff_stats(
|
|
91
|
+
previous_commit,
|
|
92
|
+
current_commit,
|
|
93
|
+
).dict
|
|
94
|
+
|
|
95
|
+
flow = flow_context.create_conviso_rest_api_client()
|
|
96
|
+
|
|
97
|
+
authors_data = git_adapter.get_commit_authors_by_range(
|
|
98
|
+
previous_commit, current_commit
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
deploy = flow.deploys.create(
|
|
102
|
+
current_version=current_version,
|
|
103
|
+
previous_version=previous_version,
|
|
104
|
+
diff_content=diff_content,
|
|
105
|
+
metrics=deploy_metrics,
|
|
106
|
+
project_metrics=project_metrics(repository_dir),
|
|
107
|
+
commit_authors=authors_data
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
click.echo(
|
|
111
|
+
create_context.output_formatter.format(deploy)
|
|
112
|
+
)
|
|
113
|
+
except Exception as e:
|
|
114
|
+
on_http_error(e)
|
|
115
|
+
raise click.ClickException(str(e)) from e
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import git
|
|
3
|
+
import time
|
|
4
|
+
import json
|
|
5
|
+
import tempfile
|
|
6
|
+
import traceback
|
|
7
|
+
from convisoappsec.flowcli.context import pass_flow_context
|
|
8
|
+
from convisoappsec.flowcli import help_option
|
|
9
|
+
from convisoappsec.flow import GitAdapter
|
|
10
|
+
from convisoappsec.flowcli.common import on_http_error
|
|
11
|
+
from convisoappsec.logger import LOGGER
|
|
12
|
+
|
|
13
|
+
class SameCommitException(Exception):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@click.command()
|
|
18
|
+
@help_option
|
|
19
|
+
@click.option(
|
|
20
|
+
"-c",
|
|
21
|
+
"--current-commit",
|
|
22
|
+
required=False,
|
|
23
|
+
help="If no value is given the HEAD commit of branch is used.",
|
|
24
|
+
)
|
|
25
|
+
@click.option(
|
|
26
|
+
"-p",
|
|
27
|
+
"--previous-commit",
|
|
28
|
+
required=False,
|
|
29
|
+
help="""If no value is given, the value is retrieved from the lastest
|
|
30
|
+
deploy at flow application.""",
|
|
31
|
+
)
|
|
32
|
+
@click.option(
|
|
33
|
+
"-r",
|
|
34
|
+
"--repository-dir",
|
|
35
|
+
required=False,
|
|
36
|
+
type=click.Path(exists=True, resolve_path=True),
|
|
37
|
+
default='.',
|
|
38
|
+
show_default=True,
|
|
39
|
+
help="Repository directory.",
|
|
40
|
+
)
|
|
41
|
+
@click.option(
|
|
42
|
+
"--asset-id",
|
|
43
|
+
required=False,
|
|
44
|
+
envvar=("CONVISO_ASSET_ID", "FLOW_ASSET_ID"),
|
|
45
|
+
help="Asset ID on Conviso Platform",
|
|
46
|
+
)
|
|
47
|
+
@click.pass_context
|
|
48
|
+
def values(context, repository_dir, current_commit, previous_commit, asset_id):
|
|
49
|
+
try:
|
|
50
|
+
if context.params['asset_id'] is not None and asset_id is None:
|
|
51
|
+
asset_id = context.params['asset_id']
|
|
52
|
+
|
|
53
|
+
git_adapter = GitAdapter(repository_dir)
|
|
54
|
+
commits = deploys_from_asset(asset_id=asset_id)
|
|
55
|
+
current_commit = current_commit or git_adapter.head_commit
|
|
56
|
+
last_commit = commits[0]['currentCommit'] if commits else git_adapter.empty_repository_tree_commit
|
|
57
|
+
|
|
58
|
+
if last_commit == current_commit:
|
|
59
|
+
raise SameCommitException(
|
|
60
|
+
"Previous commit ({0}) and Current commit ({1}) are the same, nothing to do."
|
|
61
|
+
.format(last_commit, current_commit)
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if not previous_commit:
|
|
65
|
+
previous_commit = commits[0]['currentCommit'] if commits else git_adapter.empty_repository_tree_commit
|
|
66
|
+
|
|
67
|
+
if previous_commit != '4b825dc642cb6eb9a060e54bf8d69288fbee4904':
|
|
68
|
+
try:
|
|
69
|
+
git_adapter._repo.commit(previous_commit)
|
|
70
|
+
except (git.exc.BadName, ValueError):
|
|
71
|
+
commits = deploys_from_asset(asset_id=asset_id)
|
|
72
|
+
previous_commit = None
|
|
73
|
+
|
|
74
|
+
for commit in commits:
|
|
75
|
+
commit_hash = commit['currentCommit']
|
|
76
|
+
try:
|
|
77
|
+
git_adapter._repo.commit(commit_hash)
|
|
78
|
+
previous_commit = commit_hash
|
|
79
|
+
break
|
|
80
|
+
except (git.exc.BadName, ValueError):
|
|
81
|
+
continue
|
|
82
|
+
|
|
83
|
+
if previous_commit is None:
|
|
84
|
+
previous_commit = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'
|
|
85
|
+
|
|
86
|
+
commit_history_list = git_adapter.get_commit_history()
|
|
87
|
+
|
|
88
|
+
commit_history_file = tempfile.NamedTemporaryFile(mode='w+', delete=False)
|
|
89
|
+
json.dump(commit_history_list, commit_history_file)
|
|
90
|
+
commit_history_file.seek(0)
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
"previous_commit": previous_commit,
|
|
94
|
+
"current_commit": current_commit,
|
|
95
|
+
"commit_history": commit_history_file.name,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
except SameCommitException as e:
|
|
99
|
+
LOGGER.warning(str(e))
|
|
100
|
+
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
except git.exc.GitError as e:
|
|
104
|
+
LOGGER.error(f"Git error: {str(e)}")
|
|
105
|
+
raise click.ClickException(f"Git error: {str(e)}") from e
|
|
106
|
+
|
|
107
|
+
except Exception as e:
|
|
108
|
+
if "GraphqlController" in str(e):
|
|
109
|
+
LOGGER.error(f"GraphQL API error: {str(e)}")
|
|
110
|
+
raise click.ClickException(f"Error communicating with Conviso API: {str(e)}") from e
|
|
111
|
+
|
|
112
|
+
LOGGER.warning("There was an error. Our team has been notified.")
|
|
113
|
+
full_trace = traceback.format_exc()
|
|
114
|
+
LOGGER.error(full_trace)
|
|
115
|
+
on_http_error(e)
|
|
116
|
+
raise click.ClickException(str(e)) from e
|
|
117
|
+
|
|
118
|
+
@pass_flow_context
|
|
119
|
+
def deploys_from_asset(flow_context, asset_id, max_retries=3):
|
|
120
|
+
""" Returns all deploys from an asset with retry logic """
|
|
121
|
+
for attempt in range(max_retries):
|
|
122
|
+
try:
|
|
123
|
+
conviso_api = flow_context.create_conviso_graphql_client()
|
|
124
|
+
deploys = conviso_api.deploys.get_deploys_by_asset(asset_id=asset_id)
|
|
125
|
+
|
|
126
|
+
return deploys
|
|
127
|
+
except Exception as e:
|
|
128
|
+
if attempt == max_retries - 1:
|
|
129
|
+
LOGGER.error(f"Failed to fetch deploys for asset {asset_id} after {max_retries} attempts: {str(e)}")
|
|
130
|
+
raise
|
|
131
|
+
LOGGER.warning(f"Attempt {attempt + 1} failed: {str(e)}. Retrying...")
|
|
132
|
+
time.sleep(2 ** attempt)
|
|
133
|
+
return None
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
import click_log
|
|
5
|
+
from convisoappsec.flow import api
|
|
6
|
+
from convisoappsec.flow.util.ci_provider import CIProvider
|
|
7
|
+
from convisoappsec.flowcli import help_option
|
|
8
|
+
from convisoappsec.flowcli.common import process_ci_provider_option
|
|
9
|
+
from convisoappsec.flowcli.iac.entrypoint import iac
|
|
10
|
+
from convisoappsec.logger import LOGGER
|
|
11
|
+
from convisoappsec.version import __version__
|
|
12
|
+
|
|
13
|
+
from .ast import ast
|
|
14
|
+
from .context import pass_flow_context
|
|
15
|
+
from .findings import findings
|
|
16
|
+
from .sast import sast
|
|
17
|
+
from .sca import sca
|
|
18
|
+
from .vulnerability import vulnerability
|
|
19
|
+
from .assets import assets
|
|
20
|
+
from .sbom import sbom
|
|
21
|
+
from .container import container
|
|
22
|
+
|
|
23
|
+
click_log.basic_config(LOGGER)
|
|
24
|
+
|
|
25
|
+
@click.group()
|
|
26
|
+
@click_log.simple_verbosity_option(LOGGER, '-l', '--verbosity')
|
|
27
|
+
@click.option(
|
|
28
|
+
'-k',
|
|
29
|
+
'--api-key',
|
|
30
|
+
show_envvar=True,
|
|
31
|
+
envvar=("CONVISO_API_KEY", "FLOW_API_KEY"),
|
|
32
|
+
help="The api key to access Conviso Platform resources.",
|
|
33
|
+
)
|
|
34
|
+
@click.option(
|
|
35
|
+
'-u',
|
|
36
|
+
'--api-url',
|
|
37
|
+
show_envvar=True,
|
|
38
|
+
envvar=("CONVISO_API_URL", "FLOW_API_URL"),
|
|
39
|
+
default=api.DEFAULT_API_URL,
|
|
40
|
+
show_default=True,
|
|
41
|
+
help='The api url to access Conviso Platform resources.',
|
|
42
|
+
)
|
|
43
|
+
@click.option(
|
|
44
|
+
'-i',
|
|
45
|
+
'--api-insecure',
|
|
46
|
+
show_envvar=True,
|
|
47
|
+
envvar=("CONVISO_API_INSECURE", "FLOW_API_INSECURE"),
|
|
48
|
+
default=False,
|
|
49
|
+
show_default=True,
|
|
50
|
+
is_flag=True,
|
|
51
|
+
help='HTTPS requests to untrusted hosts is enable.',
|
|
52
|
+
)
|
|
53
|
+
@click.option(
|
|
54
|
+
'-c',
|
|
55
|
+
'--ci-provider-name',
|
|
56
|
+
show_envvar=True,
|
|
57
|
+
envvar="CI_PROVIDER_NAME",
|
|
58
|
+
type=click.Choice(CIProvider.names()),
|
|
59
|
+
default=None,
|
|
60
|
+
show_default=True,
|
|
61
|
+
required=False,
|
|
62
|
+
help="The ci provider used by project. "
|
|
63
|
+
"When not informed, an automatic search will be performed."
|
|
64
|
+
)
|
|
65
|
+
@click.option(
|
|
66
|
+
'--experimental',
|
|
67
|
+
default=False,
|
|
68
|
+
is_flag=True,
|
|
69
|
+
hidden=True,
|
|
70
|
+
help="Enable experimental features.",
|
|
71
|
+
)
|
|
72
|
+
@help_option
|
|
73
|
+
@click.version_option(
|
|
74
|
+
__version__,
|
|
75
|
+
'-v',
|
|
76
|
+
'--version',
|
|
77
|
+
message='%(prog)s %(version)s'
|
|
78
|
+
)
|
|
79
|
+
@pass_flow_context
|
|
80
|
+
def cli(flow_context, api_key, api_url, api_insecure, experimental, ci_provider_name):
|
|
81
|
+
flow_context.key = api_key
|
|
82
|
+
flow_context.url = api_url
|
|
83
|
+
flow_context.insecure = api_insecure
|
|
84
|
+
flow_context.experimental = experimental
|
|
85
|
+
|
|
86
|
+
ci_provider = process_ci_provider_option(ci_provider_name, os.environ)
|
|
87
|
+
flow_context.ci_provider = ci_provider
|
|
88
|
+
LOGGER.debug('CI provider name detected: {}'.format(flow_context.ci_provider.name))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
cli.add_command(findings)
|
|
92
|
+
cli.add_command(sast)
|
|
93
|
+
cli.add_command(sca)
|
|
94
|
+
cli.add_command(vulnerability)
|
|
95
|
+
cli.add_command(ast)
|
|
96
|
+
cli.add_command(iac)
|
|
97
|
+
cli.add_command(assets)
|
|
98
|
+
cli.add_command(sbom)
|
|
99
|
+
cli.add_command(container)
|
|
100
|
+
|
|
101
|
+
cli.epilog = '''
|
|
102
|
+
Run conviso COMMAND --help for more information on a command.
|
|
103
|
+
'''
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import platform
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
class EnvironmentChecker:
|
|
6
|
+
"""
|
|
7
|
+
A class to check the system environment for required software and services.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self):
|
|
11
|
+
self.checks = {}
|
|
12
|
+
|
|
13
|
+
def _run_command(self, command, check_running=False):
|
|
14
|
+
"""Helper function to run shell commands and capture output/errors."""
|
|
15
|
+
try:
|
|
16
|
+
process = subprocess.run(command, capture_output=True, text=True, check=not check_running)
|
|
17
|
+
if check_running:
|
|
18
|
+
return process.returncode == 0, "", ""
|
|
19
|
+
return process.returncode == 0, process.stdout.strip(), process.stderr.strip()
|
|
20
|
+
except FileNotFoundError:
|
|
21
|
+
return False, "", "Command not found"
|
|
22
|
+
except subprocess.CalledProcessError as e:
|
|
23
|
+
return False, "", e.stderr.strip()
|
|
24
|
+
|
|
25
|
+
def check_docker(self):
|
|
26
|
+
"""Checks if Docker is installed and the daemon is running."""
|
|
27
|
+
installed, _, _ = self._run_command(["docker", "--version"])
|
|
28
|
+
running, _, _ = self._run_command(["docker", "info"], check_running=True)
|
|
29
|
+
self.checks["docker_installed"] = installed
|
|
30
|
+
self.checks["docker_running"] = running
|
|
31
|
+
return installed and running
|
|
32
|
+
|
|
33
|
+
def run_all_checks(self):
|
|
34
|
+
"""Runs all checks and prints a summary."""
|
|
35
|
+
self.check_docker()
|
|
36
|
+
|
|
37
|
+
print("Environment Check Summary:")
|
|
38
|
+
for check, result in self.checks.items():
|
|
39
|
+
if "version" in check:
|
|
40
|
+
print(f"- {check.replace('_',' ').title()}: {result}")
|
|
41
|
+
else:
|
|
42
|
+
status = "OK" if result else "FAILED"
|
|
43
|
+
print(f"- {check.replace('_',' ').title()}: {status}")
|
|
44
|
+
|
|
45
|
+
return all(self.checks.values())
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from convisoappsec.flowcli import help_option
|
|
4
|
+
|
|
5
|
+
from .with_ import with_
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@click.group()
|
|
9
|
+
@help_option
|
|
10
|
+
def create():
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
create.add_command(with_)
|
|
15
|
+
|
|
16
|
+
create.epilog = '''
|
|
17
|
+
Run flow findings create COMMAND --help for more information on a command.
|
|
18
|
+
'''
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from convisoappsec.flowcli import help_option
|
|
4
|
+
|
|
5
|
+
from .version_tracker import version_tracker
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@click.group('with')
|
|
9
|
+
@help_option
|
|
10
|
+
def with_():
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
with_.add_command(version_tracker)
|
|
15
|
+
|
|
16
|
+
with_.epilog = '''
|
|
17
|
+
Run flow findings create with COMMAND --help for more information
|
|
18
|
+
on a command.
|
|
19
|
+
'''
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from convisoappsec.flow.version_control_system_adapter import GitAdapter
|
|
5
|
+
from convisoappsec.flowcli.context import pass_flow_context
|
|
6
|
+
from convisoappsec.flowcli import help_option
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def finding_report_files_validation(_, __, finding_report_files):
|
|
10
|
+
allowed_extensions = ['.json']
|
|
11
|
+
allowed_extensions_str = '[{0}]'.format(
|
|
12
|
+
'|'.join(allowed_extensions)
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
for report_file in finding_report_files:
|
|
16
|
+
file_name = report_file.name
|
|
17
|
+
|
|
18
|
+
if Path(file_name).suffix not in allowed_extensions:
|
|
19
|
+
raise click.BadParameter(
|
|
20
|
+
'Allowed file extensions {0}. File given: {1}'.format(
|
|
21
|
+
allowed_extensions_str,
|
|
22
|
+
file_name
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
return finding_report_files
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@click.command()
|
|
30
|
+
@click.argument(
|
|
31
|
+
"finding-report-files",
|
|
32
|
+
nargs=-1,
|
|
33
|
+
required=False,
|
|
34
|
+
type=click.File('r'),
|
|
35
|
+
callback=finding_report_files_validation
|
|
36
|
+
)
|
|
37
|
+
@click.option(
|
|
38
|
+
'-c',
|
|
39
|
+
'--current-commit',
|
|
40
|
+
required=False,
|
|
41
|
+
help="""The hash of current commit. If no value is set
|
|
42
|
+
so the HEAD commit will be used.""",
|
|
43
|
+
)
|
|
44
|
+
@click.option(
|
|
45
|
+
"-r",
|
|
46
|
+
"--repository-dir",
|
|
47
|
+
required=False,
|
|
48
|
+
type=click.Path(exists=True),
|
|
49
|
+
default=".",
|
|
50
|
+
show_default=True,
|
|
51
|
+
help='The root dir of repository.',
|
|
52
|
+
)
|
|
53
|
+
@click.option(
|
|
54
|
+
"-t",
|
|
55
|
+
"--default-report-type",
|
|
56
|
+
required=False,
|
|
57
|
+
help="""This value is used when report type attribute is missing.
|
|
58
|
+
This not override an existing value at report file""",
|
|
59
|
+
)
|
|
60
|
+
@help_option
|
|
61
|
+
@pass_flow_context
|
|
62
|
+
def version_tracker(
|
|
63
|
+
flow_context, finding_report_files,
|
|
64
|
+
repository_dir, current_commit, default_report_type
|
|
65
|
+
):
|
|
66
|
+
try:
|
|
67
|
+
if not finding_report_files:
|
|
68
|
+
click.echo(
|
|
69
|
+
"Nothing to be done, finding report files argument empty"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
git = GitAdapter(repository_dir)
|
|
75
|
+
current_commit = current_commit or git.head_commit
|
|
76
|
+
commit_refs = git.show_commit_refs(current_commit)
|
|
77
|
+
finding_report_files_prog_bar_ctx = click.progressbar(
|
|
78
|
+
finding_report_files,
|
|
79
|
+
label='Sending finding reports'
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
flow = flow_context.create_conviso_rest_api_client()
|
|
83
|
+
|
|
84
|
+
with finding_report_files_prog_bar_ctx as reports_with_progressbar:
|
|
85
|
+
for finding_report in reports_with_progressbar:
|
|
86
|
+
flow.findings.create(
|
|
87
|
+
commit_refs,
|
|
88
|
+
finding_report,
|
|
89
|
+
default_report_type=default_report_type
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
except Exception as e:
|
|
93
|
+
raise click.ClickException(str(e)) from e
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from convisoappsec.flowcli import help_option
|
|
4
|
+
from .create import create
|
|
5
|
+
from .import_sarif import import_sarif
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@click.group()
|
|
9
|
+
@help_option
|
|
10
|
+
def findings():
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
findings.add_command(create)
|
|
15
|
+
findings.add_command(import_sarif)
|
|
16
|
+
|
|
17
|
+
findings.epilog = '''
|
|
18
|
+
Run flow findings COMMAND --help for more information on a command.
|
|
19
|
+
'''
|