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,212 @@
|
|
|
1
|
+
CREATE_ASSET = """
|
|
2
|
+
mutation (
|
|
3
|
+
$companyId: Int!,
|
|
4
|
+
$name: String!,
|
|
5
|
+
$scanType: AssetScan!
|
|
6
|
+
) {
|
|
7
|
+
createAsset(
|
|
8
|
+
input: {
|
|
9
|
+
companyId: $companyId,
|
|
10
|
+
name: $name,
|
|
11
|
+
scanType: $scanType
|
|
12
|
+
}
|
|
13
|
+
) {
|
|
14
|
+
asset {
|
|
15
|
+
id
|
|
16
|
+
name
|
|
17
|
+
createdAt
|
|
18
|
+
}
|
|
19
|
+
errors
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
UPDATE_ASSET = """
|
|
25
|
+
mutation (
|
|
26
|
+
$id: ID!,
|
|
27
|
+
$companyId: Int!,
|
|
28
|
+
$name: String!,
|
|
29
|
+
$tecnologyList: [String!],
|
|
30
|
+
$repoUrl: String
|
|
31
|
+
) {
|
|
32
|
+
updateAsset(
|
|
33
|
+
input: {
|
|
34
|
+
id: $id,
|
|
35
|
+
companyId: $companyId,
|
|
36
|
+
name: $name,
|
|
37
|
+
tecnologyList: $tecnologyList,
|
|
38
|
+
repoUrl: $repoUrl
|
|
39
|
+
}
|
|
40
|
+
) {
|
|
41
|
+
asset {
|
|
42
|
+
id
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
IMPORT_SBOM = """
|
|
49
|
+
mutation (
|
|
50
|
+
$file: Upload!,
|
|
51
|
+
$assetId: ID!,
|
|
52
|
+
$companyId: ID!
|
|
53
|
+
) {
|
|
54
|
+
importSbom(
|
|
55
|
+
input: {
|
|
56
|
+
file: $file,
|
|
57
|
+
assetId: $assetId,
|
|
58
|
+
companyId: $companyId
|
|
59
|
+
}
|
|
60
|
+
) {
|
|
61
|
+
success
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
IMPORT_CONTAINER = """
|
|
67
|
+
mutation (
|
|
68
|
+
$file: Upload!,
|
|
69
|
+
$assetId: ID!,
|
|
70
|
+
$companyId: ID!
|
|
71
|
+
) {
|
|
72
|
+
importContainerFindingsFile(
|
|
73
|
+
input: {
|
|
74
|
+
file: $file,
|
|
75
|
+
assetId: $assetId,
|
|
76
|
+
companyId: $companyId
|
|
77
|
+
}
|
|
78
|
+
) {
|
|
79
|
+
success
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
LOG_AST_ERROR = """
|
|
85
|
+
mutation (
|
|
86
|
+
$companyId: ID!,
|
|
87
|
+
$assetId: ID!,
|
|
88
|
+
$log: String!
|
|
89
|
+
) {
|
|
90
|
+
logAstError(
|
|
91
|
+
input: {
|
|
92
|
+
companyId: $companyId,
|
|
93
|
+
assetId: $assetId,
|
|
94
|
+
log: $log
|
|
95
|
+
}
|
|
96
|
+
) {
|
|
97
|
+
success
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
CREATE_DEPLOY = """
|
|
103
|
+
mutation (
|
|
104
|
+
$assetId: ID!,
|
|
105
|
+
$previousCommit: String!,
|
|
106
|
+
$currentCommit: String!,
|
|
107
|
+
$branchName: String,
|
|
108
|
+
$diffContent: Upload!,
|
|
109
|
+
$commitHistory: Upload!
|
|
110
|
+
) {
|
|
111
|
+
createDeploy(
|
|
112
|
+
input: {
|
|
113
|
+
assetId: $assetId,
|
|
114
|
+
previousCommit: $previousCommit,
|
|
115
|
+
currentCommit: $currentCommit,
|
|
116
|
+
branchName: $branchName,
|
|
117
|
+
diffContent: $diffContent,
|
|
118
|
+
commitHistory: $commitHistory
|
|
119
|
+
}
|
|
120
|
+
) {
|
|
121
|
+
deploy {
|
|
122
|
+
id
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
IMPORT_FINDINGS = """
|
|
129
|
+
mutation (
|
|
130
|
+
$file: Upload!,
|
|
131
|
+
$assetId: ID!,
|
|
132
|
+
$companyId: ID!
|
|
133
|
+
$vulnerabilityTypes: [Issue!]!
|
|
134
|
+
$deployId: ID
|
|
135
|
+
$commitRef: String
|
|
136
|
+
$controlSyncStatusId: ID
|
|
137
|
+
) {
|
|
138
|
+
importAstFindingsFile(
|
|
139
|
+
input: {
|
|
140
|
+
file: $file,
|
|
141
|
+
assetId: $assetId,
|
|
142
|
+
companyId: $companyId,
|
|
143
|
+
vulnerabilityTypes: $vulnerabilityTypes,
|
|
144
|
+
deployId: $deployId,
|
|
145
|
+
commitRef: $commitRef
|
|
146
|
+
controlSyncStatusId: $controlSyncStatusId
|
|
147
|
+
}
|
|
148
|
+
) {
|
|
149
|
+
success
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
CREATE_CONTROL_SYNC_STATUS = """
|
|
155
|
+
mutation ($assetId: ID!) {
|
|
156
|
+
createControlSyncStatus(
|
|
157
|
+
input: {
|
|
158
|
+
assetId: $assetId,
|
|
159
|
+
integration: CONVISO_AST,
|
|
160
|
+
externalVulnerabilityCount: 0
|
|
161
|
+
}
|
|
162
|
+
) {
|
|
163
|
+
controlSyncStatus {
|
|
164
|
+
id
|
|
165
|
+
}
|
|
166
|
+
success
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
UPDATE_CONTROL_SYNC_STATUS = """
|
|
172
|
+
mutation (
|
|
173
|
+
$id: ID!
|
|
174
|
+
$externalVulnerabilityCount: Int!
|
|
175
|
+
) {
|
|
176
|
+
updateControlSyncStatus(
|
|
177
|
+
input: {
|
|
178
|
+
id: $id
|
|
179
|
+
externalVulnerabilityCount: $externalVulnerabilityCount
|
|
180
|
+
}
|
|
181
|
+
) {
|
|
182
|
+
controlSyncStatus {
|
|
183
|
+
id
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
"""
|
|
188
|
+
|
|
189
|
+
INCREASE_ISSUE_SCAN_COUNT = """
|
|
190
|
+
mutation (
|
|
191
|
+
$controlSyncStatusId: ID!
|
|
192
|
+
$assetId: ID!
|
|
193
|
+
$successCount: Int
|
|
194
|
+
$failureCount: Int
|
|
195
|
+
$failureReason: String
|
|
196
|
+
) {
|
|
197
|
+
increaseIssueScanCount(
|
|
198
|
+
input: {
|
|
199
|
+
controlSyncStatusId: $controlSyncStatusId
|
|
200
|
+
assetId: $assetId
|
|
201
|
+
successCount: $successCount
|
|
202
|
+
failureCount: $failureCount
|
|
203
|
+
failureReason: $failureReason
|
|
204
|
+
integration: CONVISO_AST
|
|
205
|
+
}
|
|
206
|
+
) {
|
|
207
|
+
controlSyncStatus {
|
|
208
|
+
id
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
"""
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
GET_ASSETS = """
|
|
2
|
+
query (
|
|
3
|
+
$id: ID!,
|
|
4
|
+
$name: String!,
|
|
5
|
+
$page: Int,
|
|
6
|
+
$limit: Int
|
|
7
|
+
) {
|
|
8
|
+
assets(
|
|
9
|
+
companyId: $id
|
|
10
|
+
page: $page
|
|
11
|
+
limit: $limit
|
|
12
|
+
search: {
|
|
13
|
+
name: $name
|
|
14
|
+
}
|
|
15
|
+
) {
|
|
16
|
+
collection {
|
|
17
|
+
id
|
|
18
|
+
name
|
|
19
|
+
createdAt
|
|
20
|
+
projects(includeAst: true) {
|
|
21
|
+
type
|
|
22
|
+
apiCode
|
|
23
|
+
label
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
metadata {
|
|
28
|
+
currentPage
|
|
29
|
+
limitValue
|
|
30
|
+
totalCount
|
|
31
|
+
totalPages
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
GET_ISSUES_STATS = """
|
|
38
|
+
query (
|
|
39
|
+
$asset_id: [ID!],
|
|
40
|
+
$company_id: ID!,
|
|
41
|
+
$statuses: [IssueStatusLabel!],
|
|
42
|
+
$end_date: ISO8601DateTime
|
|
43
|
+
) {
|
|
44
|
+
issuesStats(
|
|
45
|
+
companyId: $company_id
|
|
46
|
+
filters: {
|
|
47
|
+
assetIds: $asset_id
|
|
48
|
+
statuses: $statuses
|
|
49
|
+
createdAtRange: {
|
|
50
|
+
endDate: $end_date
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
) {
|
|
54
|
+
severities {
|
|
55
|
+
value
|
|
56
|
+
count
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
GET_PROJECTS = """
|
|
63
|
+
query (
|
|
64
|
+
$project_code: String!,
|
|
65
|
+
$project_label: String!,
|
|
66
|
+
$company_id: ID!,
|
|
67
|
+
$page: Int,
|
|
68
|
+
$limit: Int
|
|
69
|
+
) {
|
|
70
|
+
projects(
|
|
71
|
+
page: $page
|
|
72
|
+
limit: $limit
|
|
73
|
+
params: {
|
|
74
|
+
apiCodeEq: $project_code
|
|
75
|
+
labelEq: $project_label
|
|
76
|
+
scopeIdEq: $company_id
|
|
77
|
+
showHidden: true
|
|
78
|
+
projectTypeLabelEq: "ast"
|
|
79
|
+
}
|
|
80
|
+
) {
|
|
81
|
+
collection {
|
|
82
|
+
id
|
|
83
|
+
apiCode
|
|
84
|
+
assets {
|
|
85
|
+
id
|
|
86
|
+
name
|
|
87
|
+
}
|
|
88
|
+
company {
|
|
89
|
+
id
|
|
90
|
+
customFeatures
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
metadata {
|
|
94
|
+
currentPage
|
|
95
|
+
limitValue
|
|
96
|
+
totalCount
|
|
97
|
+
totalPages
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
GET_COMPANY = """
|
|
104
|
+
query get_company($company_id: ID!) {
|
|
105
|
+
company(id: $company_id) {
|
|
106
|
+
id
|
|
107
|
+
label
|
|
108
|
+
customFeatures
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
GET_COMPANIES = """
|
|
114
|
+
query Companies {
|
|
115
|
+
companies (
|
|
116
|
+
limit: 50,
|
|
117
|
+
order: label,
|
|
118
|
+
orderType: ASC
|
|
119
|
+
) {
|
|
120
|
+
collection {
|
|
121
|
+
id
|
|
122
|
+
label
|
|
123
|
+
customFeatures
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
GET_ISSUES_FINGERPRINT = """
|
|
130
|
+
query GetIssuesFingerprint(
|
|
131
|
+
$company_id: ID!,
|
|
132
|
+
$page: Int,
|
|
133
|
+
$per_page: Int,
|
|
134
|
+
$asset_id: [ID!],
|
|
135
|
+
$statuses: [IssueStatusLabel!]
|
|
136
|
+
$failure_types: [Issue!]
|
|
137
|
+
) {
|
|
138
|
+
issues(
|
|
139
|
+
companyId: $company_id,
|
|
140
|
+
pagination: {
|
|
141
|
+
page: $page,
|
|
142
|
+
perPage: $per_page
|
|
143
|
+
},
|
|
144
|
+
filters: {
|
|
145
|
+
assetIds: $asset_id,
|
|
146
|
+
statuses: $statuses,
|
|
147
|
+
failureTypes: $failure_types
|
|
148
|
+
}
|
|
149
|
+
) {
|
|
150
|
+
collection {
|
|
151
|
+
id
|
|
152
|
+
type
|
|
153
|
+
... on FindingInterface {
|
|
154
|
+
originalIssueIdFromTool
|
|
155
|
+
scanSource
|
|
156
|
+
}
|
|
157
|
+
status
|
|
158
|
+
}
|
|
159
|
+
metadata {
|
|
160
|
+
totalCount
|
|
161
|
+
totalPages
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
GET_DEPLOYS_BY_ASSET = """
|
|
168
|
+
query GetDeploysByAsset(
|
|
169
|
+
$asset_id: ID!
|
|
170
|
+
) {
|
|
171
|
+
deploysByAsset(
|
|
172
|
+
assetId: $asset_id
|
|
173
|
+
) {
|
|
174
|
+
collection {
|
|
175
|
+
currentCommit
|
|
176
|
+
previousCommit
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
"""
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import yaml
|
|
2
|
+
import tempfile
|
|
3
|
+
|
|
4
|
+
from .source_code_scanner import SourceCodeScanner
|
|
5
|
+
from .exceptions import SourceCodeScannerException
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SCC(SourceCodeScanner):
|
|
9
|
+
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
source_code_dir,
|
|
13
|
+
container_source_dir = '/code',
|
|
14
|
+
create_source_code_volume = True
|
|
15
|
+
):
|
|
16
|
+
super().__init__(
|
|
17
|
+
source_code_dir,
|
|
18
|
+
create_source_code_volume=create_source_code_volume
|
|
19
|
+
)
|
|
20
|
+
self.__scan_result = {}
|
|
21
|
+
self.__container_source_dir = container_source_dir
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def repository(self):
|
|
25
|
+
return 'convisoappsec/scc'
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def tag(self):
|
|
29
|
+
return 'latest'
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def container_source_dir(self):
|
|
33
|
+
return self.__container_source_dir
|
|
34
|
+
|
|
35
|
+
def _read_scan_stdout(self, stdout_generator):
|
|
36
|
+
with tempfile.TemporaryFile() as yaml_output:
|
|
37
|
+
for chunk in stdout_generator:
|
|
38
|
+
yaml_output.write(chunk)
|
|
39
|
+
|
|
40
|
+
yaml_output.seek(0)
|
|
41
|
+
|
|
42
|
+
self.__scan_result = yaml.load(
|
|
43
|
+
yaml_output,
|
|
44
|
+
Loader=yaml.FullLoader
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def summary(self):
|
|
49
|
+
summary = self.__scan_result.get('SUM')
|
|
50
|
+
if not summary:
|
|
51
|
+
raise SourceCodeScannerException(
|
|
52
|
+
'Unexpected error retrienving source code summary metrics'
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
return summary
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def total_source_code_lines(self):
|
|
59
|
+
return self.summary.get('code')
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def command(self):
|
|
63
|
+
return [
|
|
64
|
+
'--no-cocomo',
|
|
65
|
+
'--no-complexity',
|
|
66
|
+
'--format',
|
|
67
|
+
'cloc-yaml'
|
|
68
|
+
]
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import docker
|
|
2
|
+
from contextlib import suppress
|
|
3
|
+
import tempfile
|
|
4
|
+
from uuid import uuid4
|
|
5
|
+
|
|
6
|
+
from convisoappsec.flow.util import SourceCodeCompressor
|
|
7
|
+
from .exceptions import SourceCodeScannerException
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SourceCodeScanner(object):
|
|
11
|
+
SUCCESS_EXIT_CODE = 0
|
|
12
|
+
'''
|
|
13
|
+
hooks:
|
|
14
|
+
def _pre_pull(self):
|
|
15
|
+
:return: void
|
|
16
|
+
|
|
17
|
+
def _capture_stdout(self, stdout_bytes)
|
|
18
|
+
:param stdout_bytes: chunks generated by stdout
|
|
19
|
+
:paramtype stdout_bytes: bytes
|
|
20
|
+
:return: void
|
|
21
|
+
_pre_scan
|
|
22
|
+
_scan_stdout
|
|
23
|
+
_post_scan
|
|
24
|
+
'''
|
|
25
|
+
|
|
26
|
+
def __init__(self, source_code_dir, create_source_code_volume = True):
|
|
27
|
+
uuid = str(uuid4())
|
|
28
|
+
self.docker = docker.from_env(version="auto")
|
|
29
|
+
self.__container_name = "source_code_scanner_{0}".format(
|
|
30
|
+
uuid
|
|
31
|
+
)
|
|
32
|
+
self.__source_code_dir = source_code_dir
|
|
33
|
+
self.__create_source_code_volume = create_source_code_volume
|
|
34
|
+
|
|
35
|
+
if self.__create_source_code_volume:
|
|
36
|
+
self.__source_code_volume_name = "source_code_scanner_src_{0}".format(
|
|
37
|
+
uuid
|
|
38
|
+
)
|
|
39
|
+
else:
|
|
40
|
+
self.__source_code_volume_name = None
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def repository(self):
|
|
44
|
+
raise Exception('Not implemented yet!')
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def tag(self):
|
|
48
|
+
raise Exception('Not implemented yet!')
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def command(self):
|
|
52
|
+
raise Exception('Not implemented yet!')
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def container_source_dir(self):
|
|
56
|
+
raise Exception('Not implemented yet!')
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def image(self):
|
|
60
|
+
return "{repository}:{tag}".format(
|
|
61
|
+
repository=self.repository,
|
|
62
|
+
tag=self.tag,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def volumes(self):
|
|
67
|
+
if not self.__create_source_code_volume:
|
|
68
|
+
return {}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
self.__source_code_volume_name: {
|
|
72
|
+
'bind': self.container_source_dir,
|
|
73
|
+
'mode': 'rw',
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
def __get_container(self):
|
|
78
|
+
return self.docker.containers.get(
|
|
79
|
+
self.__container_name
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def __get_source_code_volume(self):
|
|
83
|
+
return self.docker.volumes.get(
|
|
84
|
+
self.__source_code_volume_name
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def __container(self):
|
|
89
|
+
try:
|
|
90
|
+
return self.__get_container()
|
|
91
|
+
except docker.errors.NotFound:
|
|
92
|
+
return self.__create_container()
|
|
93
|
+
|
|
94
|
+
def __create_container(self):
|
|
95
|
+
return self.docker.containers.create(
|
|
96
|
+
self.image,
|
|
97
|
+
name=self.__container_name,
|
|
98
|
+
volumes=self.volumes,
|
|
99
|
+
detach=True,
|
|
100
|
+
command=self.command,
|
|
101
|
+
working_dir=self.container_source_dir if self.container_source_dir != '/code' else '/code'
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
def __pull_image(self):
|
|
105
|
+
if self.has_pre_pull:
|
|
106
|
+
self._pre_pull()
|
|
107
|
+
|
|
108
|
+
self.docker.images.pull(self.repository, self.tag)
|
|
109
|
+
|
|
110
|
+
def __load_source_code(self):
|
|
111
|
+
container = self.__container
|
|
112
|
+
|
|
113
|
+
with tempfile.TemporaryFile() as fileobj:
|
|
114
|
+
compressor = SourceCodeCompressor(
|
|
115
|
+
self.__source_code_dir
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
compressor.write_to(fileobj)
|
|
119
|
+
fileobj.seek(0)
|
|
120
|
+
|
|
121
|
+
container.put_archive(
|
|
122
|
+
self.container_source_dir,
|
|
123
|
+
fileobj
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
def scan(self):
|
|
127
|
+
self.__pull_image()
|
|
128
|
+
self.__load_source_code()
|
|
129
|
+
container = self.__container
|
|
130
|
+
|
|
131
|
+
container.start()
|
|
132
|
+
|
|
133
|
+
if self.has_read_scan_stderr:
|
|
134
|
+
self._read_scan_stderr(
|
|
135
|
+
container.logs(
|
|
136
|
+
stream=True, stdout=False, stderr=True
|
|
137
|
+
)
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
if self.has_read_scan_stdout:
|
|
141
|
+
self._read_scan_stdout(
|
|
142
|
+
container.logs(
|
|
143
|
+
stream=True, stdout=True, stderr=False
|
|
144
|
+
)
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
wait_result = container.wait()
|
|
148
|
+
status_code = wait_result.get('StatusCode')
|
|
149
|
+
|
|
150
|
+
if not status_code == self.SUCCESS_EXIT_CODE:
|
|
151
|
+
raise SourceCodeScannerException(
|
|
152
|
+
'Source code scanning fail'
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
def __has_method(self, method_name):
|
|
156
|
+
return hasattr(self, method_name)
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
def has_read_scan_stdout(self):
|
|
160
|
+
return self.__has_method('_read_scan_stdout')
|
|
161
|
+
|
|
162
|
+
@property
|
|
163
|
+
def has_read_scan_stderr(self):
|
|
164
|
+
return self.__has_method('_read_scan_stderr')
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def has_pre_pull(self):
|
|
168
|
+
return self.__has_method('_pre_pull')
|
|
169
|
+
|
|
170
|
+
def __del__(self):
|
|
171
|
+
with suppress(Exception):
|
|
172
|
+
container = self.__get_container()
|
|
173
|
+
container.remove()
|
|
174
|
+
|
|
175
|
+
with suppress(Exception):
|
|
176
|
+
source_code_volume = self.__get_source_code_volume()
|
|
177
|
+
source_code_volume.remove()
|