socketsecurity 0.0.98__tar.gz → 0.0.99__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-0.0.99}/PKG-INFO +1 -1
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity/__init__.py +1 -1
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity/core/__init__.py +126 -111
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity/socketcli.py +21 -10
- {socketsecurity-0.0.98 → socketsecurity-0.0.99/socketsecurity.egg-info}/PKG-INFO +1 -1
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/LICENSE +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/README.md +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/pyproject.toml +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/setup.cfg +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity/core/classes.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity/core/exceptions.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity/core/git_interface.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity/core/github.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity/core/gitlab.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity/core/issues.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity/core/licenses.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity/core/messages.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity/core/scm_comments.py +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity.egg-info/SOURCES.txt +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity.egg-info/dependency_links.txt +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity.egg-info/entry_points.txt +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity.egg-info/requires.txt +0 -0
- {socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity.egg-info/top_level.txt +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
__author__ = 'socket.dev'
|
|
2
|
-
__version__ = '0.0.
|
|
2
|
+
__version__ = '0.0.99'
|
|
@@ -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
|
|
@@ -143,8 +143,9 @@ 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
|
+
save_sbom_file(diff_report, sbom_file_name)
|
|
148
149
|
if len(diff_report.new_alerts) > 0:
|
|
149
150
|
log.info("Security issues detected by Socket Security")
|
|
150
151
|
log.info(console_security_comment)
|
|
@@ -153,13 +154,18 @@ def output_console_comments(diff_report) -> None:
|
|
|
153
154
|
log.info("No New Security issues detected by Socket Security")
|
|
154
155
|
|
|
155
156
|
|
|
156
|
-
def output_console_json(diff_report) -> None:
|
|
157
|
+
def output_console_json(diff_report: Diff, sbom_file_name: str = None) -> None:
|
|
157
158
|
console_security_comment = Messages.create_security_comment_json(diff_report)
|
|
159
|
+
save_sbom_file(diff_report, sbom_file_name)
|
|
158
160
|
print(json.dumps(console_security_comment))
|
|
159
161
|
if len(diff_report.new_alerts) > 0:
|
|
160
162
|
sys.exit(1)
|
|
161
163
|
|
|
162
164
|
|
|
165
|
+
def save_sbom_file(diff_report: Diff, sbom_file_name: str = None):
|
|
166
|
+
if diff_report is not None and sbom_file_name is not None:
|
|
167
|
+
Core.save_file(sbom_file_name, json.dumps(Core.create_sbom_output(diff_report)))
|
|
168
|
+
|
|
163
169
|
def cli():
|
|
164
170
|
try:
|
|
165
171
|
main_code()
|
|
@@ -200,6 +206,7 @@ def main_code():
|
|
|
200
206
|
api_token = os.getenv("SOCKET_SECURITY_API_KEY") or arguments.api_token
|
|
201
207
|
try:
|
|
202
208
|
files = json.loads(files)
|
|
209
|
+
is_repo = True
|
|
203
210
|
except Exception as error:
|
|
204
211
|
log.error(f"Unable to parse {files}")
|
|
205
212
|
log.error(error)
|
|
@@ -221,7 +228,9 @@ def main_code():
|
|
|
221
228
|
commit_message = git_repo.commit_message
|
|
222
229
|
if len(files) == 0 and not ignore_commit_files:
|
|
223
230
|
files = git_repo.changed_files
|
|
231
|
+
is_repo = True
|
|
224
232
|
except InvalidGitRepositoryError:
|
|
233
|
+
is_repo = False
|
|
225
234
|
pass
|
|
226
235
|
# git_repo = None
|
|
227
236
|
if repo is None:
|
|
@@ -241,6 +250,10 @@ def main_code():
|
|
|
241
250
|
if scm is not None:
|
|
242
251
|
default_branch = scm.is_default_branch
|
|
243
252
|
|
|
253
|
+
if is_repo and files is not None and len(files) == 0 and not ignore_commit_files:
|
|
254
|
+
no_change = True
|
|
255
|
+
else:
|
|
256
|
+
no_change = False
|
|
244
257
|
base_api_url = os.getenv("BASE_API_URL") or None
|
|
245
258
|
core = Core(token=api_token, request_timeout=6000, base_api_url=base_api_url)
|
|
246
259
|
set_as_pending_head = False
|
|
@@ -266,7 +279,7 @@ def main_code():
|
|
|
266
279
|
elif scm is not None and scm.check_event_type() != "comment":
|
|
267
280
|
log.info("Push initiated flow")
|
|
268
281
|
diff: Diff
|
|
269
|
-
diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files)
|
|
282
|
+
diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files, no_change=no_change)
|
|
270
283
|
if scm.check_event_type() == "diff":
|
|
271
284
|
log.info("Starting comment logic for PR/MR event")
|
|
272
285
|
log.debug(f"Getting comments for Repo {scm.repository} for PR {scm.pr_number}")
|
|
@@ -297,17 +310,17 @@ def main_code():
|
|
|
297
310
|
log.info("Not a PR/MR event no comment needed")
|
|
298
311
|
if enable_json:
|
|
299
312
|
log.debug("Outputting JSON Results")
|
|
300
|
-
output_console_json(diff)
|
|
313
|
+
output_console_json(diff, sbom_file)
|
|
301
314
|
else:
|
|
302
|
-
output_console_comments(diff)
|
|
315
|
+
output_console_comments(diff, sbom_file)
|
|
303
316
|
else:
|
|
304
317
|
log.info("API Mode")
|
|
305
318
|
diff: Diff
|
|
306
|
-
diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files)
|
|
319
|
+
diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files, no_change=no_change)
|
|
307
320
|
if enable_json:
|
|
308
|
-
output_console_json(diff)
|
|
321
|
+
output_console_json(diff, sbom_file)
|
|
309
322
|
else:
|
|
310
|
-
output_console_comments(diff)
|
|
323
|
+
output_console_comments(diff, sbom_file)
|
|
311
324
|
if diff is not None and license_mode:
|
|
312
325
|
all_packages = {}
|
|
313
326
|
for package_id in diff.packages:
|
|
@@ -325,8 +338,6 @@ def main_code():
|
|
|
325
338
|
}
|
|
326
339
|
all_packages[package_id] = output
|
|
327
340
|
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
341
|
|
|
331
342
|
|
|
332
343
|
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
|
{socketsecurity-0.0.98 → socketsecurity-0.0.99}/socketsecurity.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|