socketsecurity 0.0.98__tar.gz → 1.0.0__tar.gz
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.
- {socketsecurity-0.0.98/socketsecurity.egg-info → socketsecurity-1.0.0}/PKG-INFO +1 -1
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/__init__.py +1 -1
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/__init__.py +131 -127
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/classes.py +12 -1
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/messages.py +26 -8
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/socketcli.py +38 -14
- {socketsecurity-0.0.98 → socketsecurity-1.0.0/socketsecurity.egg-info}/PKG-INFO +1 -1
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/LICENSE +0 -0
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/README.md +0 -0
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/pyproject.toml +0 -0
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/setup.cfg +0 -0
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/exceptions.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/git_interface.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/github.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/gitlab.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/issues.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/licenses.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/scm_comments.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity.egg-info/SOURCES.txt +0 -0
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity.egg-info/dependency_links.txt +0 -0
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity.egg-info/entry_points.txt +0 -0
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity.egg-info/requires.txt +0 -0
- {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity.egg-info/top_level.txt +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
__author__ = 'socket.dev'
|
|
2
|
-
__version__ = '0.0
|
|
2
|
+
__version__ = '1.0.0'
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from pathlib import PurePath
|
|
3
|
+
|
|
2
4
|
import requests
|
|
3
5
|
from urllib.parse import urlencode
|
|
4
6
|
import base64
|
|
@@ -46,6 +48,74 @@ security_policy = {}
|
|
|
46
48
|
log = logging.getLogger("socketdev")
|
|
47
49
|
log.addHandler(logging.NullHandler())
|
|
48
50
|
|
|
51
|
+
socket_globs = {
|
|
52
|
+
"npm": {
|
|
53
|
+
"package.json": {
|
|
54
|
+
"pattern": "package.json"
|
|
55
|
+
},
|
|
56
|
+
"package-lock.json": {
|
|
57
|
+
"pattern": "package-lock.json"
|
|
58
|
+
},
|
|
59
|
+
"npm-shrinkwrap.json": {
|
|
60
|
+
"pattern": "npm-shrinkwrap.json"
|
|
61
|
+
},
|
|
62
|
+
"yarn.lock": {
|
|
63
|
+
"pattern": "yarn.lock"
|
|
64
|
+
},
|
|
65
|
+
"pnpm-lock.yaml": {
|
|
66
|
+
"pattern": "pnpm-lock.yaml"
|
|
67
|
+
},
|
|
68
|
+
"pnpm-lock.yml": {
|
|
69
|
+
"pattern": "pnpm-lock.yml"
|
|
70
|
+
},
|
|
71
|
+
"pnpm-workspace.yaml": {
|
|
72
|
+
"pattern": "pnpm-workspace.yaml"
|
|
73
|
+
},
|
|
74
|
+
"pnpm-workspace.yml": {
|
|
75
|
+
"pattern": "pnpm-workspace.yml"
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"pypi": {
|
|
79
|
+
"pipfile": {
|
|
80
|
+
"pattern": "pipfile"
|
|
81
|
+
},
|
|
82
|
+
"pyproject.toml": {
|
|
83
|
+
"pattern": "pyproject.toml"
|
|
84
|
+
},
|
|
85
|
+
"requirements.txt": {
|
|
86
|
+
"pattern": "*requirements.txt"
|
|
87
|
+
},
|
|
88
|
+
"requirements": {
|
|
89
|
+
"pattern": "requirements/*.txt"
|
|
90
|
+
},
|
|
91
|
+
"requirements-*.txt": {
|
|
92
|
+
"pattern": "requirements-*.txt"
|
|
93
|
+
},
|
|
94
|
+
"requirements_*.txt": {
|
|
95
|
+
"pattern": "requirements_*.txt"
|
|
96
|
+
},
|
|
97
|
+
"requirements.frozen": {
|
|
98
|
+
"pattern": "requirements.frozen"
|
|
99
|
+
},
|
|
100
|
+
"setup.py": {
|
|
101
|
+
"pattern": "setup.py"
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"golang": {
|
|
105
|
+
"go.mod": {
|
|
106
|
+
"pattern": "go.mod"
|
|
107
|
+
},
|
|
108
|
+
"go.sum": {
|
|
109
|
+
"pattern": "go.sum"
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"java": {
|
|
113
|
+
"pom.xml": {
|
|
114
|
+
"pattern": "pom.xml"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
49
119
|
|
|
50
120
|
def encode_key(token: str) -> None:
|
|
51
121
|
"""
|
|
@@ -287,125 +357,61 @@ class Core:
|
|
|
287
357
|
return manifest_files
|
|
288
358
|
|
|
289
359
|
@staticmethod
|
|
290
|
-
def create_sbom_output(diff: Diff) ->
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
"manifestFiles": manifest_files,
|
|
301
|
-
"score": package.score,
|
|
302
|
-
"size": package.size,
|
|
303
|
-
"ecosystem": package.type,
|
|
304
|
-
"alerts": package.alerts,
|
|
305
|
-
"direct": package.direct,
|
|
306
|
-
"name": package.name,
|
|
307
|
-
"version": package.version,
|
|
308
|
-
"author": package.author,
|
|
309
|
-
"url": package.url
|
|
310
|
-
}
|
|
311
|
-
sbom.append(item)
|
|
360
|
+
def create_sbom_output(diff: Diff) -> dict:
|
|
361
|
+
base_path = f"orgs/{org_slug}/export/cdx"
|
|
362
|
+
path = f"{base_path}/{diff.id}"
|
|
363
|
+
result = do_request(path=path)
|
|
364
|
+
try:
|
|
365
|
+
sbom = result.json()
|
|
366
|
+
except Exception as error:
|
|
367
|
+
log.error(f"Unable to get CycloneDX Output for {diff.id}")
|
|
368
|
+
log.error(error)
|
|
369
|
+
sbom = {}
|
|
312
370
|
return sbom
|
|
313
371
|
|
|
314
372
|
@staticmethod
|
|
315
|
-
def
|
|
373
|
+
def match_supported_files(path: str, files: list) -> list:
|
|
374
|
+
matched = []
|
|
375
|
+
for ecosystem in socket_globs:
|
|
376
|
+
patterns = socket_globs[ecosystem]
|
|
377
|
+
for file_name in patterns:
|
|
378
|
+
pattern = patterns[file_name]["pattern"]
|
|
379
|
+
# path_pattern = f"**/{pattern}"
|
|
380
|
+
for file in files:
|
|
381
|
+
if "\\" in file:
|
|
382
|
+
file = file.replace("\\", "/")
|
|
383
|
+
if PurePath(file).match(pattern):
|
|
384
|
+
matched.append(file)
|
|
385
|
+
return matched
|
|
386
|
+
|
|
387
|
+
@staticmethod
|
|
388
|
+
def find_files(path: str, files: list = None) -> list:
|
|
316
389
|
"""
|
|
317
390
|
Globs the path for supported manifest files.
|
|
318
391
|
Note: Might move the source to a JSON file
|
|
319
392
|
:param path: Str - path to where the manifest files are located
|
|
320
|
-
:param
|
|
393
|
+
:param files: override finding the manifest files using the glob matcher
|
|
321
394
|
:return:
|
|
322
395
|
"""
|
|
323
|
-
socket_globs = {
|
|
324
|
-
"npm": {
|
|
325
|
-
"package.json": {
|
|
326
|
-
"pattern": "package.json"
|
|
327
|
-
},
|
|
328
|
-
"package-lock.json": {
|
|
329
|
-
"pattern": "package-lock.json"
|
|
330
|
-
},
|
|
331
|
-
"npm-shrinkwrap.json": {
|
|
332
|
-
"pattern": "npm-shrinkwrap.json"
|
|
333
|
-
},
|
|
334
|
-
"yarn.lock": {
|
|
335
|
-
"pattern": "yarn.lock"
|
|
336
|
-
},
|
|
337
|
-
"pnpm-lock.yaml": {
|
|
338
|
-
"pattern": "pnpm-lock.yaml"
|
|
339
|
-
},
|
|
340
|
-
"pnpm-lock.yml": {
|
|
341
|
-
"pattern": "pnpm-lock.yml"
|
|
342
|
-
},
|
|
343
|
-
"pnpm-workspace.yaml": {
|
|
344
|
-
"pattern": "pnpm-workspace.yaml"
|
|
345
|
-
},
|
|
346
|
-
"pnpm-workspace.yml": {
|
|
347
|
-
"pattern": "pnpm-workspace.yml"
|
|
348
|
-
}
|
|
349
|
-
},
|
|
350
|
-
"pypi": {
|
|
351
|
-
"pipfile": {
|
|
352
|
-
"pattern": "pipfile"
|
|
353
|
-
},
|
|
354
|
-
"pyproject.toml": {
|
|
355
|
-
"pattern": "pyproject.toml"
|
|
356
|
-
},
|
|
357
|
-
"requirements.txt": {
|
|
358
|
-
"pattern": "*requirements.txt"
|
|
359
|
-
},
|
|
360
|
-
"requirements": {
|
|
361
|
-
"pattern": "requirements/*.txt"
|
|
362
|
-
},
|
|
363
|
-
"requirements-*.txt": {
|
|
364
|
-
"pattern": "requirements-*.txt"
|
|
365
|
-
},
|
|
366
|
-
"requirements_*.txt": {
|
|
367
|
-
"pattern": "requirements_*.txt"
|
|
368
|
-
},
|
|
369
|
-
"requirements.frozen": {
|
|
370
|
-
"pattern": "requirements.frozen"
|
|
371
|
-
},
|
|
372
|
-
"setup.py": {
|
|
373
|
-
"pattern": "setup.py"
|
|
374
|
-
}
|
|
375
|
-
},
|
|
376
|
-
"golang": {
|
|
377
|
-
"go.mod": {
|
|
378
|
-
"pattern": "go.mod"
|
|
379
|
-
},
|
|
380
|
-
"go.sum": {
|
|
381
|
-
"pattern": "go.sum"
|
|
382
|
-
}
|
|
383
|
-
},
|
|
384
|
-
"java": {
|
|
385
|
-
"pom.xml": {
|
|
386
|
-
"pattern": "pom.xml"
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
396
|
all_files = []
|
|
391
397
|
for ecosystem in socket_globs:
|
|
392
398
|
patterns = socket_globs[ecosystem]
|
|
393
399
|
for file_name in patterns:
|
|
394
400
|
pattern = patterns[file_name]["pattern"]
|
|
395
401
|
file_path = f"{path}/**/{pattern}"
|
|
396
|
-
files
|
|
402
|
+
if files is None or len(files) == 0:
|
|
403
|
+
files = glob(file_path, recursive=True)
|
|
404
|
+
else:
|
|
405
|
+
files = Core.match_supported_files(path, files)
|
|
397
406
|
for file in files:
|
|
398
|
-
if "/" in file:
|
|
399
|
-
_, base_name = file.rsplit("/", 1)
|
|
400
|
-
else:
|
|
401
|
-
base_name = file
|
|
402
|
-
if new_files is not None and len(new_files) > 0 and base_name not in new_files:
|
|
403
|
-
continue
|
|
404
407
|
if platform.system() == "Windows":
|
|
405
408
|
file = file.replace("\\", "/")
|
|
409
|
+
if path not in file:
|
|
410
|
+
file = f"{path}/{file}"
|
|
406
411
|
found_path, file_name = file.rsplit("/", 1)
|
|
407
412
|
details = (found_path, file_name)
|
|
408
|
-
all_files
|
|
413
|
+
if details not in all_files:
|
|
414
|
+
all_files.append(details)
|
|
409
415
|
return all_files
|
|
410
416
|
|
|
411
417
|
@staticmethod
|
|
@@ -480,7 +486,13 @@ class Core:
|
|
|
480
486
|
return full_scan
|
|
481
487
|
|
|
482
488
|
@staticmethod
|
|
483
|
-
def create_new_diff(
|
|
489
|
+
def create_new_diff(
|
|
490
|
+
path: str,
|
|
491
|
+
params: FullScanParams,
|
|
492
|
+
workspace: str,
|
|
493
|
+
new_files: list = None,
|
|
494
|
+
no_change: bool = False
|
|
495
|
+
) -> Diff:
|
|
484
496
|
"""
|
|
485
497
|
1. Get the head full scan. If it isn't present because this repo doesn't exist yet return an Empty full scan.
|
|
486
498
|
2. Create a new Full scan for the current run
|
|
@@ -490,9 +502,14 @@ class Core:
|
|
|
490
502
|
:param params: FullScanParams - Query params for the Full Scan endpoint
|
|
491
503
|
:param workspace: str - Path for workspace
|
|
492
504
|
:param new_files:
|
|
505
|
+
:param no_change:
|
|
493
506
|
:return:
|
|
494
507
|
"""
|
|
508
|
+
if no_change:
|
|
509
|
+
return Diff()
|
|
495
510
|
files = Core.find_files(path, new_files)
|
|
511
|
+
if files is None or len(files) == 0:
|
|
512
|
+
return Diff()
|
|
496
513
|
try:
|
|
497
514
|
head_full_scan_id = Core.get_head_scan_for_repo(params.repo)
|
|
498
515
|
if head_full_scan_id is None or head_full_scan_id == "":
|
|
@@ -505,17 +522,15 @@ class Core:
|
|
|
505
522
|
log.info(f"Total time to get head full-scan {total_head_time: .2f}")
|
|
506
523
|
except APIResourceNotFound:
|
|
507
524
|
head_full_scan = []
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
else:
|
|
518
|
-
diff_report = Diff()
|
|
525
|
+
new_scan_start = time.time()
|
|
526
|
+
new_full_scan = Core.create_full_scan(files, params, workspace)
|
|
527
|
+
new_full_scan.packages = Core.create_sbom_dict(new_full_scan.sbom_artifacts)
|
|
528
|
+
new_scan_end = time.time()
|
|
529
|
+
total_new_time = new_scan_end - new_scan_start
|
|
530
|
+
log.info(f"Total time to get new full-scan {total_new_time: .2f}")
|
|
531
|
+
diff_report = Core.compare_sboms(new_full_scan.sbom_artifacts, head_full_scan)
|
|
532
|
+
diff_report.packages = new_full_scan.packages
|
|
533
|
+
diff_report.id = new_full_scan.id
|
|
519
534
|
return diff_report
|
|
520
535
|
|
|
521
536
|
@staticmethod
|
|
@@ -622,30 +637,16 @@ class Core:
|
|
|
622
637
|
if alert_key not in head_scan_alerts:
|
|
623
638
|
new_alerts = new_scan_alerts[alert_key]
|
|
624
639
|
for alert in new_alerts:
|
|
625
|
-
if
|
|
640
|
+
if alert.error or alert.warn:
|
|
626
641
|
alerts.append(alert)
|
|
627
642
|
else:
|
|
628
643
|
new_alerts = new_scan_alerts[alert_key]
|
|
629
644
|
head_alerts = head_scan_alerts[alert_key]
|
|
630
645
|
for alert in new_alerts:
|
|
631
|
-
if alert not in head_alerts and
|
|
646
|
+
if alert not in head_alerts and (alert.error or alert.warn):
|
|
632
647
|
alerts.append(alert)
|
|
633
648
|
return alerts
|
|
634
649
|
|
|
635
|
-
@staticmethod
|
|
636
|
-
def is_error(alert: Alert):
|
|
637
|
-
"""
|
|
638
|
-
Compare the current alert against the Security Policy to determine if it should be included. Can be overridden
|
|
639
|
-
with all_new_alerts Global setting if desired to return all alerts and not just the error category from the
|
|
640
|
-
security policy.
|
|
641
|
-
:param alert:
|
|
642
|
-
:return:
|
|
643
|
-
"""
|
|
644
|
-
if all_new_alerts or (alert.type in security_policy and security_policy[alert.type]['action'] == "error"):
|
|
645
|
-
return True
|
|
646
|
-
else:
|
|
647
|
-
return False
|
|
648
|
-
|
|
649
650
|
@staticmethod
|
|
650
651
|
def create_issue_alerts(package: Package, alerts: dict, packages: dict) -> dict:
|
|
651
652
|
"""
|
|
@@ -689,6 +690,9 @@ class Core:
|
|
|
689
690
|
purl=package.purl,
|
|
690
691
|
url=package.url
|
|
691
692
|
)
|
|
693
|
+
if alert.type in security_policy:
|
|
694
|
+
action = security_policy[alert.type]['action']
|
|
695
|
+
setattr(issue_alert, action, True)
|
|
692
696
|
if issue_alert.key not in alerts:
|
|
693
697
|
alerts[issue_alert.key] = [issue_alert]
|
|
694
698
|
else:
|
|
@@ -140,7 +140,10 @@ class Issue:
|
|
|
140
140
|
pkg_id: str
|
|
141
141
|
props: dict
|
|
142
142
|
key: str
|
|
143
|
-
|
|
143
|
+
error: bool
|
|
144
|
+
warn: bool
|
|
145
|
+
ignore: bool
|
|
146
|
+
monitor: bool
|
|
144
147
|
description: str
|
|
145
148
|
title: str
|
|
146
149
|
emoji: str
|
|
@@ -162,6 +165,14 @@ class Issue:
|
|
|
162
165
|
self.introduced_by = []
|
|
163
166
|
if not hasattr(self, "manifests"):
|
|
164
167
|
self.manifests = ""
|
|
168
|
+
if not hasattr(self, "error"):
|
|
169
|
+
self.error = False
|
|
170
|
+
if not hasattr(self, "warn"):
|
|
171
|
+
self.warn = False
|
|
172
|
+
if not hasattr(self, "monitor"):
|
|
173
|
+
self.monitor = False
|
|
174
|
+
if not hasattr(self, "ignore"):
|
|
175
|
+
self.ignore = False
|
|
165
176
|
|
|
166
177
|
def __str__(self):
|
|
167
178
|
return json.dumps(self.__dict__)
|
|
@@ -9,10 +9,13 @@ class Messages:
|
|
|
9
9
|
|
|
10
10
|
@staticmethod
|
|
11
11
|
def create_security_comment_json(diff: Diff) -> dict:
|
|
12
|
+
scan_failed = False
|
|
12
13
|
if len(diff.new_alerts) == 0:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
for alert in diff.new_alerts:
|
|
15
|
+
alert: Issue
|
|
16
|
+
if alert.error:
|
|
17
|
+
scan_failed = True
|
|
18
|
+
break
|
|
16
19
|
output = {
|
|
17
20
|
"scan_failed": scan_failed,
|
|
18
21
|
"new_alerts": []
|
|
@@ -22,7 +25,6 @@ class Messages:
|
|
|
22
25
|
output["new_alerts"].append(json.loads(str(alert)))
|
|
23
26
|
return output
|
|
24
27
|
|
|
25
|
-
|
|
26
28
|
@staticmethod
|
|
27
29
|
def security_comment_template(diff: Diff) -> str:
|
|
28
30
|
"""
|
|
@@ -130,7 +132,8 @@ class Messages:
|
|
|
130
132
|
"Alert",
|
|
131
133
|
"Package",
|
|
132
134
|
"Introduced by",
|
|
133
|
-
"Manifest File"
|
|
135
|
+
"Manifest File",
|
|
136
|
+
"CI"
|
|
134
137
|
]
|
|
135
138
|
num_of_alert_columns = len(alert_table)
|
|
136
139
|
next_steps = {}
|
|
@@ -147,11 +150,16 @@ class Messages:
|
|
|
147
150
|
ignore_commands.append(ignore)
|
|
148
151
|
manifest_str, sources = Messages.create_sources(alert, "console")
|
|
149
152
|
purl_url = f"[{alert.purl}]({alert.url})"
|
|
153
|
+
if alert.error:
|
|
154
|
+
emoji = ':no_entry_sign:'
|
|
155
|
+
else:
|
|
156
|
+
emoji = ':warning:'
|
|
150
157
|
row = [
|
|
151
158
|
alert.title,
|
|
152
159
|
purl_url,
|
|
153
160
|
", ".join(sources),
|
|
154
|
-
manifest_str
|
|
161
|
+
manifest_str,
|
|
162
|
+
emoji
|
|
155
163
|
]
|
|
156
164
|
if row not in alert_table:
|
|
157
165
|
alert_table.extend(row)
|
|
@@ -262,17 +270,27 @@ class Messages:
|
|
|
262
270
|
"Alert",
|
|
263
271
|
"Package",
|
|
264
272
|
"Introduced by",
|
|
265
|
-
"Manifest File"
|
|
273
|
+
"Manifest File",
|
|
274
|
+
"CI Status"
|
|
266
275
|
]
|
|
267
276
|
)
|
|
268
277
|
for alert in diff.new_alerts:
|
|
269
278
|
alert: Issue
|
|
270
279
|
manifest_str, sources = Messages.create_sources(alert, "console")
|
|
280
|
+
if alert.error:
|
|
281
|
+
state = "block"
|
|
282
|
+
elif alert.warn:
|
|
283
|
+
state = "warn"
|
|
284
|
+
elif alert.monitor:
|
|
285
|
+
state = "monitor"
|
|
286
|
+
else:
|
|
287
|
+
state = "ignore"
|
|
271
288
|
row = [
|
|
272
289
|
alert.title,
|
|
273
290
|
alert.url,
|
|
274
291
|
", ".join(sources),
|
|
275
|
-
manifest_str
|
|
292
|
+
manifest_str,
|
|
293
|
+
state
|
|
276
294
|
]
|
|
277
295
|
alert_table.add_row(row)
|
|
278
296
|
return alert_table
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import argparse
|
|
2
2
|
import json
|
|
3
3
|
from socketsecurity.core import Core, __version__
|
|
4
|
-
from socketsecurity.core.classes import FullScanParams, Diff, Package
|
|
4
|
+
from socketsecurity.core.classes import FullScanParams, Diff, Package, Alert
|
|
5
5
|
from socketsecurity.core.messages import Messages
|
|
6
6
|
from socketsecurity.core.scm_comments import Comments
|
|
7
7
|
from socketsecurity.core.git_interface import Git
|
|
@@ -143,23 +143,42 @@ parser.add_argument(
|
|
|
143
143
|
)
|
|
144
144
|
|
|
145
145
|
|
|
146
|
-
def output_console_comments(diff_report) -> None:
|
|
146
|
+
def output_console_comments(diff_report: Diff, sbom_file_name: str = None) -> None:
|
|
147
147
|
console_security_comment = Messages.create_console_security_alert_table(diff_report)
|
|
148
|
-
|
|
148
|
+
save_sbom_file(diff_report, sbom_file_name)
|
|
149
|
+
if not report_pass(diff_report):
|
|
149
150
|
log.info("Security issues detected by Socket Security")
|
|
150
|
-
|
|
151
|
+
msg = f"\n{console_security_comment}"
|
|
152
|
+
log.info(msg)
|
|
151
153
|
sys.exit(1)
|
|
152
154
|
else:
|
|
153
155
|
log.info("No New Security issues detected by Socket Security")
|
|
154
156
|
|
|
155
157
|
|
|
156
|
-
def output_console_json(diff_report) -> None:
|
|
158
|
+
def output_console_json(diff_report: Diff, sbom_file_name: str = None) -> None:
|
|
157
159
|
console_security_comment = Messages.create_security_comment_json(diff_report)
|
|
160
|
+
save_sbom_file(diff_report, sbom_file_name)
|
|
158
161
|
print(json.dumps(console_security_comment))
|
|
159
|
-
if
|
|
162
|
+
if not report_pass(diff_report):
|
|
160
163
|
sys.exit(1)
|
|
161
164
|
|
|
162
165
|
|
|
166
|
+
def report_pass(diff_report: Diff) -> bool:
|
|
167
|
+
report_passed = True
|
|
168
|
+
if len(diff_report.new_alerts) > 0:
|
|
169
|
+
for alert in diff_report.new_alerts:
|
|
170
|
+
alert: Alert
|
|
171
|
+
if report_passed and alert.error:
|
|
172
|
+
report_passed = False
|
|
173
|
+
break
|
|
174
|
+
return report_passed
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def save_sbom_file(diff_report: Diff, sbom_file_name: str = None):
|
|
178
|
+
if diff_report is not None and sbom_file_name is not None:
|
|
179
|
+
Core.save_file(sbom_file_name, json.dumps(Core.create_sbom_output(diff_report)))
|
|
180
|
+
|
|
181
|
+
|
|
163
182
|
def cli():
|
|
164
183
|
try:
|
|
165
184
|
main_code()
|
|
@@ -200,6 +219,7 @@ def main_code():
|
|
|
200
219
|
api_token = os.getenv("SOCKET_SECURITY_API_KEY") or arguments.api_token
|
|
201
220
|
try:
|
|
202
221
|
files = json.loads(files)
|
|
222
|
+
is_repo = True
|
|
203
223
|
except Exception as error:
|
|
204
224
|
log.error(f"Unable to parse {files}")
|
|
205
225
|
log.error(error)
|
|
@@ -221,7 +241,9 @@ def main_code():
|
|
|
221
241
|
commit_message = git_repo.commit_message
|
|
222
242
|
if len(files) == 0 and not ignore_commit_files:
|
|
223
243
|
files = git_repo.changed_files
|
|
244
|
+
is_repo = True
|
|
224
245
|
except InvalidGitRepositoryError:
|
|
246
|
+
is_repo = False
|
|
225
247
|
pass
|
|
226
248
|
# git_repo = None
|
|
227
249
|
if repo is None:
|
|
@@ -241,6 +263,10 @@ def main_code():
|
|
|
241
263
|
if scm is not None:
|
|
242
264
|
default_branch = scm.is_default_branch
|
|
243
265
|
|
|
266
|
+
if is_repo and files is not None and len(files) == 0 and not ignore_commit_files:
|
|
267
|
+
no_change = True
|
|
268
|
+
else:
|
|
269
|
+
no_change = False
|
|
244
270
|
base_api_url = os.getenv("BASE_API_URL") or None
|
|
245
271
|
core = Core(token=api_token, request_timeout=6000, base_api_url=base_api_url)
|
|
246
272
|
set_as_pending_head = False
|
|
@@ -266,7 +292,7 @@ def main_code():
|
|
|
266
292
|
elif scm is not None and scm.check_event_type() != "comment":
|
|
267
293
|
log.info("Push initiated flow")
|
|
268
294
|
diff: Diff
|
|
269
|
-
diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files)
|
|
295
|
+
diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files, no_change=no_change)
|
|
270
296
|
if scm.check_event_type() == "diff":
|
|
271
297
|
log.info("Starting comment logic for PR/MR event")
|
|
272
298
|
log.debug(f"Getting comments for Repo {scm.repository} for PR {scm.pr_number}")
|
|
@@ -297,17 +323,17 @@ def main_code():
|
|
|
297
323
|
log.info("Not a PR/MR event no comment needed")
|
|
298
324
|
if enable_json:
|
|
299
325
|
log.debug("Outputting JSON Results")
|
|
300
|
-
output_console_json(diff)
|
|
326
|
+
output_console_json(diff, sbom_file)
|
|
301
327
|
else:
|
|
302
|
-
output_console_comments(diff)
|
|
328
|
+
output_console_comments(diff, sbom_file)
|
|
303
329
|
else:
|
|
304
330
|
log.info("API Mode")
|
|
305
331
|
diff: Diff
|
|
306
|
-
diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files)
|
|
332
|
+
diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files, no_change=no_change)
|
|
307
333
|
if enable_json:
|
|
308
|
-
output_console_json(diff)
|
|
334
|
+
output_console_json(diff, sbom_file)
|
|
309
335
|
else:
|
|
310
|
-
output_console_comments(diff)
|
|
336
|
+
output_console_comments(diff, sbom_file)
|
|
311
337
|
if diff is not None and license_mode:
|
|
312
338
|
all_packages = {}
|
|
313
339
|
for package_id in diff.packages:
|
|
@@ -325,8 +351,6 @@ def main_code():
|
|
|
325
351
|
}
|
|
326
352
|
all_packages[package_id] = output
|
|
327
353
|
core.save_file(license_file, json.dumps(all_packages))
|
|
328
|
-
if diff is not None and sbom_file is not None:
|
|
329
|
-
core.save_file(sbom_file, json.dumps(core.create_sbom_output(diff)))
|
|
330
354
|
|
|
331
355
|
|
|
332
356
|
if __name__ == '__main__':
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|