socketsecurity 1.0.32__tar.gz → 1.0.34__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.
Files changed (25) hide show
  1. {socketsecurity-1.0.32/socketsecurity.egg-info → socketsecurity-1.0.34}/PKG-INFO +9 -5
  2. socketsecurity-1.0.34/pyproject.toml +130 -0
  3. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity/__init__.py +1 -1
  4. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity/core/__init__.py +118 -116
  5. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity/core/github.py +25 -28
  6. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity/socketcli.py +18 -7
  7. {socketsecurity-1.0.32 → socketsecurity-1.0.34/socketsecurity.egg-info}/PKG-INFO +9 -5
  8. socketsecurity-1.0.34/socketsecurity.egg-info/requires.txt +11 -0
  9. socketsecurity-1.0.32/pyproject.toml +0 -48
  10. socketsecurity-1.0.32/socketsecurity.egg-info/requires.txt +0 -6
  11. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/LICENSE +0 -0
  12. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/README.md +0 -0
  13. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/setup.cfg +0 -0
  14. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity/core/classes.py +0 -0
  15. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity/core/exceptions.py +0 -0
  16. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity/core/git_interface.py +0 -0
  17. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity/core/gitlab.py +0 -0
  18. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity/core/issues.py +0 -0
  19. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity/core/licenses.py +0 -0
  20. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity/core/messages.py +0 -0
  21. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity/core/scm_comments.py +0 -0
  22. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity.egg-info/SOURCES.txt +0 -0
  23. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity.egg-info/dependency_links.txt +0 -0
  24. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity.egg-info/entry_points.txt +0 -0
  25. {socketsecurity-1.0.32 → socketsecurity-1.0.34}/socketsecurity.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: socketsecurity
3
- Version: 1.0.32
3
+ Version: 1.0.34
4
4
  Summary: Socket Security CLI for CI/CD
5
5
  Author-email: Douglas Coburn <douglas@socket.dev>
6
6
  Maintainer-email: Douglas Coburn <douglas@socket.dev>
@@ -15,12 +15,16 @@ Classifier: Programming Language :: Python :: 3.12
15
15
  Requires-Python: >=3.9
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
- Requires-Dist: requests
19
- Requires-Dist: mdutils
18
+ Requires-Dist: requests>=2.32.0
19
+ Requires-Dist: mdutils~=1.6.0
20
20
  Requires-Dist: prettytable
21
21
  Requires-Dist: argparse
22
- Requires-Dist: GitPython
23
- Requires-Dist: packaging
22
+ Requires-Dist: GitPython>=3.1.43
23
+ Requires-Dist: packaging>=24.1
24
+ Requires-Dist: python-dotenv>=1.0.1
25
+ Requires-Dist: socket-sdk-python>=1.0.14
26
+ Provides-Extra: dev
27
+ Requires-Dist: ruff>=0.3.0; extra == "dev"
24
28
 
25
29
  # Socket Security CLI
26
30
 
@@ -0,0 +1,130 @@
1
+ [build-system]
2
+ requires = ["setuptools >= 61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "socketsecurity"
7
+ dynamic = ["version"]
8
+ requires-python = ">= 3.9"
9
+ dependencies = [
10
+ 'requests >= 2.32.0',
11
+ 'mdutils ~= 1.6.0',
12
+ 'prettytable',
13
+ 'argparse',
14
+ 'GitPython >= 3.1.43',
15
+ 'packaging >= 24.1',
16
+ 'python-dotenv >= 1.0.1',
17
+ 'socket-sdk-python >= 1.0.14'
18
+ ]
19
+
20
+
21
+ readme = "README.md"
22
+ description = "Socket Security CLI for CI/CD"
23
+ keywords = ["socketsecurity", "socket.dev", "sca", "oss", "security"]
24
+ authors = [
25
+ {name = "Douglas Coburn", email = "douglas@socket.dev"}
26
+ ]
27
+ maintainers = [
28
+ {name = "Douglas Coburn", email = "douglas@socket.dev"}
29
+ ]
30
+ classifiers = [
31
+ "Development Status :: 4 - Beta",
32
+ "Intended Audience :: Developers",
33
+ "Programming Language :: Python :: 3.9",
34
+ "Programming Language :: Python :: 3.10",
35
+ "Programming Language :: Python :: 3.11",
36
+ "Programming Language :: Python :: 3.12",
37
+ ]
38
+
39
+ # modern, faster linter and language server. install with `pip install -e ".[dev]"`
40
+ [project.optional-dependencies]
41
+ dev = [
42
+ "ruff>=0.3.0",
43
+ ]
44
+
45
+ [project.scripts]
46
+ socketcli = "socketsecurity.socketcli:cli"
47
+
48
+ [project.urls]
49
+ Homepage = "https://socket.dev"
50
+
51
+ [tool.setuptools.packages.find]
52
+ include = [
53
+ "socketsecurity",
54
+ "socketsecurity.core"
55
+ ]
56
+
57
+ [tool.setuptools.dynamic]
58
+ version = {attr = "socketsecurity.__version__"}
59
+
60
+ [tool.ruff]
61
+ # Exclude a variety of commonly ignored directories.
62
+ exclude = [
63
+ ".bzr",
64
+ ".direnv",
65
+ ".eggs",
66
+ ".git",
67
+ ".git-rewrite",
68
+ ".hg",
69
+ ".ipynb_checkpoints",
70
+ ".mypy_cache",
71
+ ".nox",
72
+ ".pants.d",
73
+ ".pyenv",
74
+ ".pytest_cache",
75
+ ".pytype",
76
+ ".ruff_cache",
77
+ ".svn",
78
+ ".tox",
79
+ ".venv",
80
+ ".vscode",
81
+ "__pypackages__",
82
+ "_build",
83
+ "buck-out",
84
+ "build",
85
+ "dist",
86
+ "node_modules",
87
+ "site-packages",
88
+ "venv",
89
+ ]
90
+
91
+ [tool.ruff.lint]
92
+ # Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
93
+ # Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
94
+ # McCabe complexity (`C901`) by default.
95
+ select = ["E4", "E7", "E9", "F"]
96
+ ignore = []
97
+
98
+ # Allow fix for all enabled rules (when `--fix`) is provided.
99
+ fixable = ["ALL"]
100
+ unfixable = []
101
+
102
+ # Allow unused variables when underscore-prefixed.
103
+ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
104
+
105
+ [tool.ruff.format]
106
+ # Like Black, use double quotes for strings.
107
+ quote-style = "double"
108
+
109
+ # Like Black, indent with spaces, rather than tabs.
110
+ indent-style = "space"
111
+
112
+ # Like Black, respect magic trailing commas.
113
+ skip-magic-trailing-comma = false
114
+
115
+ # Like Black, automatically detect the appropriate line ending.
116
+ line-ending = "auto"
117
+
118
+ # Enable auto-formatting of code examples in docstrings. Markdown,
119
+ # reStructuredText code/literal blocks and doctests are all supported.
120
+ #
121
+ # This is currently disabled by default, but it is planned for this
122
+ # to be opt-out in the future.
123
+ docstring-code-format = false
124
+
125
+ # Set the line length limit used when formatting code snippets in
126
+ # docstrings.
127
+ #
128
+ # This only has an effect when the `docstring-code-format` setting is
129
+ # enabled.
130
+ docstring-code-line-length = "dynamic"
@@ -1,2 +1,2 @@
1
1
  __author__ = 'socket.dev'
2
- __version__ = '1.0.32'
2
+ __version__ = '1.0.34'
@@ -2,9 +2,9 @@ import logging
2
2
  from pathlib import PurePath
3
3
 
4
4
  import requests
5
- from urllib.parse import urlencode
6
5
  import base64
7
6
  import json
7
+ from socketdev import socketdev
8
8
  from socketsecurity.core.exceptions import (
9
9
  APIFailure, APIKeyMissing, APIAccessDenied, APIInsufficientQuota, APIResourceNotFound, APICloudflareError
10
10
  )
@@ -12,7 +12,6 @@ from socketsecurity import __version__
12
12
  from socketsecurity.core.licenses import Licenses
13
13
  from socketsecurity.core.issues import AllIssues
14
14
  from socketsecurity.core.classes import (
15
- Report,
16
15
  Issue,
17
16
  Package,
18
17
  Alert,
@@ -226,34 +225,53 @@ def do_request(
226
225
 
227
226
 
228
227
  class Core:
229
- token: str
230
- base_api_url: str
231
- request_timeout: int
232
- reports: list
228
+ _sdk = None
229
+ _initialized = False
233
230
 
234
- def __init__(
235
- self,
231
+ def __init__(self):
232
+ raise NotImplementedError("Use Core.initialize() instead of instantiation")
233
+
234
+ @classmethod
235
+ def initialize(
236
+ cls,
236
237
  token: str,
237
238
  base_api_url: str = None,
238
239
  request_timeout: int = None,
239
240
  enable_all_alerts: bool = False,
240
241
  allow_unverified: bool = False
241
- ):
242
- global allow_unverified_ssl
242
+ ) -> None:
243
+ """Initialize the Core class and set up global configuration"""
244
+ if cls._initialized:
245
+ return
246
+
247
+ global allow_unverified_ssl, all_new_alerts
248
+
243
249
  allow_unverified_ssl = allow_unverified
244
- self.token = token + ":"
245
- encode_key(self.token)
246
- self.socket_date_format = "%Y-%m-%dT%H:%M:%S.%fZ"
247
- self.base_api_url = base_api_url
248
- if self.base_api_url is not None:
249
- Core.set_api_url(self.base_api_url)
250
- self.request_timeout = request_timeout
251
- if self.request_timeout is not None:
252
- Core.set_timeout(self.request_timeout)
250
+ cls._initialize_sdk(token)
251
+ encode_key(token + ":")
252
+
253
+ if base_api_url is not None:
254
+ cls.set_api_url(base_api_url)
255
+
256
+ if request_timeout is not None:
257
+ cls.set_timeout(request_timeout)
258
+
253
259
  if enable_all_alerts:
254
- global all_new_alerts
255
260
  all_new_alerts = True
256
- Core.set_org_vars()
261
+
262
+ cls._initialized = True
263
+ cls.set_org_vars()
264
+
265
+ @classmethod
266
+ def _initialize_sdk(cls, token: str) -> None:
267
+ if cls._sdk is None:
268
+ cls._sdk = socketdev(token=token)
269
+
270
+ @classmethod
271
+ def get_sdk(cls) -> socketdev:
272
+ if not cls._initialized:
273
+ raise RuntimeError("Core not initialized - call Core.initialize() first")
274
+ return cls._sdk
257
275
 
258
276
  @staticmethod
259
277
  def enable_debug_log(level: int):
@@ -297,39 +315,50 @@ class Core:
297
315
  def get_org_id_slug() -> (str, str):
298
316
  """
299
317
  Gets the Org ID and Org Slug for the API Token
300
- :return:
318
+ :return: Tuple of Org ID and Org Slug
301
319
  """
302
- path = "organizations"
303
- response = do_request(path)
304
- data = response.json()
305
- organizations = data.get("organizations")
306
320
  new_org_id = None
307
321
  new_org_slug = None
322
+
323
+ sdk = Core.get_sdk()
324
+ data = sdk.org.get()
325
+ organizations = data.get("organizations")
326
+
308
327
  if len(organizations) == 1:
309
328
  for key in organizations:
310
329
  new_org_id = key
311
330
  new_org_slug = organizations[key].get('slug')
331
+
312
332
  return new_org_id, new_org_slug
313
333
 
314
334
  @staticmethod
315
- def get_sbom_data(full_scan_id: str) -> list:
316
- path = f"orgs/{org_slug}/full-scans/{full_scan_id}"
317
- response = do_request(path)
318
- results = []
319
- try:
320
- data = response.json()
321
- results = data.get("sbom_artifacts") or []
322
- except Exception as error:
323
- log.debug("Failed with old style full-scan API using new format")
324
- log.debug(error)
325
- data = response.text
335
+ def get_sbom_data(full_scan_id: str) -> dict:
336
+ sdk = Core.get_sdk()
337
+ response_dict = sdk.fullscans.stream(org_slug, full_scan_id)
338
+
339
+ if not response_dict.get("success"):
340
+ results = []
341
+ data = response_dict.get("message")
326
342
  data.strip('"')
327
343
  data.strip()
344
+
328
345
  for line in data.split("\n"):
329
346
  if line != '"' and line != "" and line is not None:
330
347
  item = json.loads(line)
331
348
  results.append(item)
332
- return results
349
+
350
+ return results
351
+
352
+ keys_to_remove = ["success", "status"]
353
+ for key in keys_to_remove:
354
+ response_dict.pop(key, None)
355
+
356
+ for key in response_dict:
357
+ value = response_dict.get(key)
358
+ response_dict[key] = Package(**value)
359
+
360
+ return response_dict
361
+
333
362
 
334
363
  @staticmethod
335
364
  def get_security_policy() -> dict:
@@ -337,23 +366,21 @@ class Core:
337
366
  Get the Security policy and determine the effective Org security policy
338
367
  :return:
339
368
  """
340
- path = "settings"
341
- payload = [
342
- {
343
- "organization": org_id
344
- }
345
- ]
346
- response = do_request(path, payload=json.dumps(payload), method="POST")
347
- data = response.json()
369
+
370
+ sdk = Core.get_sdk()
371
+ data = sdk.settings.get(org_id)
372
+
348
373
  defaults = data.get("defaults")
349
374
  default_rules = defaults.get("issueRules")
350
375
  entries = data.get("entries")
351
376
  org_rules = {}
377
+
352
378
  for org_set in entries:
353
379
  settings = org_set.get("settings")
354
380
  if settings is not None:
355
381
  org_details = settings.get("organization")
356
382
  org_rules = org_details.get("issueRules")
383
+
357
384
  for default in default_rules:
358
385
  if default not in org_rules:
359
386
  action = default_rules[default]["action"]
@@ -362,10 +389,6 @@ class Core:
362
389
  }
363
390
  return org_rules
364
391
 
365
- # @staticmethod
366
- # def get_supported_file_types() -> dict:
367
- # path = "report/supported"
368
-
369
392
  @staticmethod
370
393
  def get_manifest_files(package: Package, packages: dict) -> str:
371
394
  if package.direct:
@@ -388,15 +411,16 @@ class Core:
388
411
 
389
412
  @staticmethod
390
413
  def create_sbom_output(diff: Diff) -> dict:
391
- base_path = f"orgs/{org_slug}/export/cdx"
392
- path = f"{base_path}/{diff.id}"
393
- result = do_request(path=path)
394
- try:
395
- sbom = result.json()
396
- except Exception as error:
414
+ sdk = Core.get_sdk()
415
+ sbom = sdk.export.cdx_bom(org_slug, diff.id)
416
+
417
+ if not sbom.get("success"):
397
418
  log.error(f"Unable to get CycloneDX Output for {diff.id}")
398
- log.error(error)
399
- sbom = {}
419
+ log.error(sbom.get("message"))
420
+ return {}
421
+
422
+ sbom.pop("success", None)
423
+
400
424
  return sbom
401
425
 
402
426
  @staticmethod
@@ -407,7 +431,7 @@ class Core:
407
431
  patterns = socket_globs[ecosystem]
408
432
  for file_name in patterns:
409
433
  pattern = patterns[file_name]["pattern"]
410
- # path_pattern = f"**/{pattern}"
434
+
411
435
  for file in files:
412
436
  if "\\" in file:
413
437
  file = file.replace("\\", "/")
@@ -425,11 +449,12 @@ class Core:
425
449
  :param path: Str - path to where the manifest files are located
426
450
  :return:
427
451
  """
428
- log.debug("Starting Find Files")
452
+
429
453
  start_time = time.time()
430
454
  files = set()
431
455
  for ecosystem in socket_globs:
432
456
  patterns = socket_globs[ecosystem]
457
+
433
458
  for file_name in patterns:
434
459
  pattern = patterns[file_name]["pattern"]
435
460
  file_path = f"{path}/**/{pattern}"
@@ -437,14 +462,15 @@ class Core:
437
462
  log.debug(f"Globbing {file_path}")
438
463
  glob_start = time.time()
439
464
  glob_files = glob(file_path, recursive=True)
465
+
440
466
  for glob_file in glob_files:
441
467
  if glob_file not in files:
442
468
  files.add(glob_file)
469
+
443
470
  glob_end = time.time()
444
471
  glob_total_time = glob_end - glob_start
445
472
  log.debug(f"Glob for pattern {file_path} took {glob_total_time:.2f} seconds")
446
473
 
447
- log.debug("Finished Find Files")
448
474
  end_time = time.time()
449
475
  total_time = end_time - start_time
450
476
  log.info(f"Found {len(files)} in {total_time:.2f} seconds")
@@ -461,7 +487,7 @@ class Core:
461
487
  """
462
488
  send_files = []
463
489
  create_full_start = time.time()
464
- log.debug("Creating new full scan")
490
+
465
491
  for file in files:
466
492
  if platform.system() == "Windows":
467
493
  file = file.replace("\\", "/")
@@ -485,10 +511,12 @@ class Core:
485
511
  )
486
512
  )
487
513
  send_files.append(payload)
488
- query_params = urlencode(params.__dict__)
489
- full_uri = f"{full_scan_path}?{query_params}"
490
- response = do_request(full_uri, method="POST", files=send_files)
491
- results = response.json()
514
+
515
+ sdk = Core.get_sdk()
516
+ params_dict = params.__dict__
517
+ params_dict["org_slug"] = org_slug
518
+ results = sdk.fullscans.post(files=files, params=params_dict)
519
+
492
520
  full_scan = FullScan(**results)
493
521
  full_scan.sbom_artifacts = Core.get_sbom_data(full_scan.id)
494
522
  create_full_end = time.time()
@@ -513,25 +541,12 @@ class Core:
513
541
  :param repo_slug: Str - Repo slug for the repository that is being diffed
514
542
  :return:
515
543
  """
516
- repo_path = f"{repository_path}/{repo_slug}"
517
- response = do_request(repo_path)
518
- results = response.json()
544
+
545
+ sdk = Core.get_sdk()
546
+ results = sdk.repos.repo(org_slug, repo_slug)
519
547
  repository = Repository(**results)
520
- return repository.head_full_scan_id
521
548
 
522
- @staticmethod
523
- def get_full_scan(full_scan_id: str) -> FullScan:
524
- """
525
- Get the specified full scan and return a FullScan object
526
- :param full_scan_id: str - ID of the full scan to pull
527
- :return:
528
- """
529
- full_scan_url = f"{full_scan_path}/{full_scan_id}"
530
- response = do_request(full_scan_url)
531
- results = response.json()
532
- full_scan = FullScan(**results)
533
- full_scan.sbom_artifacts = Core.get_sbom_data(full_scan.id)
534
- return full_scan
549
+ return repository.head_full_scan_id
535
550
 
536
551
  @staticmethod
537
552
  def create_new_diff(
@@ -555,11 +570,13 @@ class Core:
555
570
  diff = Diff()
556
571
  diff.id = "no_diff_id"
557
572
  return diff
573
+
558
574
  files = Core.find_files(path)
559
575
  if files is None or len(files) == 0:
560
576
  diff = Diff()
561
577
  diff.id = "no_diff_id"
562
578
  return diff
579
+
563
580
  try:
564
581
  head_full_scan_id = Core.get_head_scan_for_repo(params.repo)
565
582
  if head_full_scan_id is None or head_full_scan_id == "":
@@ -570,29 +587,35 @@ class Core:
570
587
  head_end = time.time()
571
588
  total_head_time = head_end - head_start
572
589
  log.info(f"Total time to get head full-scan {total_head_time: .2f}")
590
+
573
591
  except APIResourceNotFound:
574
592
  head_full_scan_id = None
575
593
  head_full_scan = []
594
+
576
595
  new_scan_start = time.time()
577
596
  new_full_scan = Core.create_full_scan(files, params, workspace)
578
- new_full_scan.packages = Core.create_sbom_dict(new_full_scan.sbom_artifacts)
597
+ new_full_scan.packages = new_full_scan.sbom_artifacts
579
598
  new_scan_end = time.time()
599
+
580
600
  total_new_time = new_scan_end - new_scan_start
581
601
  log.info(f"Total time to get new full-scan {total_new_time: .2f}")
602
+
582
603
  diff_report = Core.compare_sboms(new_full_scan.sbom_artifacts, head_full_scan)
583
604
  diff_report.packages = new_full_scan.packages
584
- # Set the diff ID and URLs
605
+
585
606
  base_socket = "https://socket.dev/dashboard/org"
586
607
  diff_report.id = new_full_scan.id
587
608
  diff_report.report_url = f"{base_socket}/{org_slug}/sbom/{diff_report.id}"
609
+
588
610
  if head_full_scan_id is not None:
589
611
  diff_report.diff_url = f"{base_socket}/{org_slug}/diff/{diff_report.id}/{head_full_scan_id}"
590
612
  else:
591
613
  diff_report.diff_url = diff_report.report_url
614
+
592
615
  return diff_report
593
616
 
594
617
  @staticmethod
595
- def compare_sboms(new_scan: list, head_scan: list) -> Diff:
618
+ def compare_sboms(new_scan: dict, head_scan: dict) -> Diff:
596
619
  """
597
620
  compare the SBOMs of the new full Scan and the head full scan. Return a Diff report with new packages,
598
621
  removed packages, and new alerts for the new full scan compared to the head.
@@ -600,28 +623,33 @@ class Core:
600
623
  :param head_scan: FullScan - Current head FullScan for the repository
601
624
  :return:
602
625
  """
603
- diff: Diff
604
- diff = Diff()
605
- new_packages = Core.create_sbom_dict(new_scan)
606
- head_packages = Core.create_sbom_dict(head_scan)
626
+ diff: Diff = Diff()
627
+ new_packages = new_scan
628
+ head_packages = head_scan
629
+
607
630
  new_scan_alerts = {}
608
631
  head_scan_alerts = {}
609
632
  consolidated = set()
633
+
610
634
  for package_id in new_packages:
611
635
  purl, package = Core.create_purl(package_id, new_packages)
612
636
  base_purl = f"{purl.ecosystem}/{purl.name}@{purl.version}"
637
+
613
638
  if package_id not in head_packages and package.direct and base_purl not in consolidated:
614
639
  diff.new_packages.append(purl)
615
640
  consolidated.add(base_purl)
616
641
  new_scan_alerts = Core.create_issue_alerts(package, new_scan_alerts, new_packages)
642
+
617
643
  for package_id in head_packages:
618
644
  purl, package = Core.create_purl(package_id, head_packages)
619
645
  if package_id not in new_packages and package.direct:
620
646
  diff.removed_packages.append(purl)
621
647
  head_scan_alerts = Core.create_issue_alerts(package, head_scan_alerts, head_packages)
648
+
622
649
  diff.new_alerts = Core.compare_issue_alerts(new_scan_alerts, head_scan_alerts, diff.new_alerts)
623
650
  diff.new_capabilities = Core.compare_capabilities(new_packages, head_packages)
624
651
  diff = Core.add_capabilities_to_purl(diff)
652
+
625
653
  return diff
626
654
 
627
655
  @staticmethod
@@ -827,32 +855,6 @@ class Core:
827
855
  )
828
856
  return purl, package
829
857
 
830
- @staticmethod
831
- def create_sbom_dict(sbom: list) -> dict:
832
- """
833
- Converts the SBOM Artifacts from the FulLScan into a Dictionary for parsing
834
- :param sbom: list - Raw artifacts for the SBOM
835
- :return:
836
- """
837
- packages = {}
838
- top_level_count = {}
839
- for item in sbom:
840
- package = Package(**item)
841
- if package.id in packages:
842
- print("Duplicate package?")
843
- else:
844
- package = Core.get_license_details(package)
845
- packages[package.id] = package
846
- for top_id in package.topLevelAncestors:
847
- if top_id not in top_level_count:
848
- top_level_count[top_id] = 1
849
- else:
850
- top_level_count[top_id] += 1
851
- if len(top_level_count) > 0:
852
- for package_id in top_level_count:
853
- packages[package_id].transitives = top_level_count[package_id]
854
- return packages
855
-
856
858
  @staticmethod
857
859
  def save_file(file_name: str, content: str) -> None:
858
860
  file = open(file_name, "w")
@@ -1,30 +1,29 @@
1
1
  import json
2
2
  import os
3
3
  from socketsecurity.core import log, do_request
4
- import requests
5
4
  from socketsecurity.core.classes import Comment
6
5
  from socketsecurity.core.scm_comments import Comments
7
6
  import sys
8
7
 
9
8
 
10
- global github_sha
11
- global github_api_url
12
- global github_ref_type
13
- global github_event_name
14
- global github_workspace
15
- global github_repository
16
- global github_ref_name
17
- global github_actor
18
- global default_branch
19
- global github_env
20
- global pr_number
21
- global pr_name
22
- global is_default_branch
23
- global commit_message
24
- global committer
25
- global gh_api_token
26
- global github_repository_owner
27
- global event_action
9
+ github_sha = None
10
+ github_api_url = None
11
+ github_ref_type = None
12
+ github_event_name = None
13
+ github_workspace = None
14
+ github_repository = None
15
+ github_ref_name = None
16
+ github_actor = None
17
+ default_branch = None
18
+ github_env = None
19
+ pr_number = None
20
+ pr_name = None
21
+ is_default_branch = False
22
+ commit_message = None
23
+ committer = None
24
+ gh_api_token = None
25
+ github_repository_owner = None
26
+ event_action = None
28
27
 
29
28
  github_variables = [
30
29
  "GITHUB_SHA",
@@ -47,16 +46,14 @@ github_variables = [
47
46
 
48
47
  for env in github_variables:
49
48
  var_name = env.lower()
50
- globals()[var_name] = os.getenv(env) or None
49
+ value = os.getenv(env)
50
+ globals()[var_name] = value
51
+
51
52
  if var_name == "default_branch":
52
- global is_default_branch
53
- if default_branch is None or default_branch.lower() == "false":
54
- is_default_branch = False
55
- else:
56
- is_default_branch = True
57
- if var_name != "gh_api_token":
58
- value = globals()[var_name] = os.getenv(env) or None
59
- log.debug(f"{env}={value}")
53
+ is_default_branch = bool(value and value.lower() != "false")
54
+
55
+ if var_name != "gh_api_token":
56
+ log.debug(f"{env}={value}")
60
57
 
61
58
  headers = {
62
59
  'Authorization': f"Bearer {gh_api_token}",
@@ -167,12 +167,15 @@ def output_console_comments(diff_report: Diff, sbom_file_name: str = None) -> No
167
167
  console_security_comment = Messages.create_console_security_alert_table(diff_report)
168
168
  save_sbom_file(diff_report, sbom_file_name)
169
169
  log.info(f"Socket Full Scan ID: {diff_report.id}")
170
+
170
171
  if len(diff_report.new_alerts) > 0:
171
172
  log.info("Security issues detected by Socket Security")
172
173
  msg = f"\n{console_security_comment}"
173
174
  log.info(msg)
175
+
174
176
  if not report_pass(diff_report) and not blocking_disabled:
175
177
  sys.exit(1)
178
+
176
179
  else:
177
180
  # Means only warning alerts with no blocked
178
181
  if not blocking_disabled:
@@ -188,7 +191,7 @@ def output_console_json(diff_report: Diff, sbom_file_name: str = None) -> None:
188
191
  print(json.dumps(console_security_comment))
189
192
  if not report_pass(diff_report) and not blocking_disabled:
190
193
  sys.exit(1)
191
- elif len(diff_report.new_alerts) > 0 and not blocking_disabled:
194
+ if len(diff_report.new_alerts) > 0 and not blocking_disabled:
192
195
  # Means only warning alerts with no blocked
193
196
  sys.exit(5)
194
197
 
@@ -252,6 +255,7 @@ def main_code():
252
255
  ignore_commit_files = arguments.ignore_commit_files
253
256
  disable_blocking = arguments.disable_blocking
254
257
  allow_unverified = arguments.allow_unverified
258
+
255
259
  if disable_blocking:
256
260
  global blocking_disabled
257
261
  blocking_disabled = True
@@ -308,13 +312,20 @@ def main_code():
308
312
  default_branch = scm.is_default_branch
309
313
 
310
314
  base_api_url = os.getenv("BASE_API_URL") or None
311
- core = Core(token=api_token, request_timeout=1200, base_api_url=base_api_url, allow_unverified=allow_unverified)
315
+
316
+ Core.initialize(
317
+ token=api_token,
318
+ request_timeout=1200,
319
+ base_api_url=base_api_url,
320
+ allow_unverified=allow_unverified
321
+ )
322
+
312
323
  no_change = True
313
324
  if ignore_commit_files:
314
325
  no_change = False
315
326
  elif is_repo and files is not None and len(files) > 0:
316
327
  log.info(files)
317
- no_change = core.match_supported_files(files)
328
+ no_change = Core.match_supported_files(files)
318
329
 
319
330
  set_as_pending_head = False
320
331
  if default_branch:
@@ -344,7 +355,7 @@ def main_code():
344
355
  log.info("No manifest files changes, skipping scan")
345
356
  # log.info("No dependency changes")
346
357
  elif scm.check_event_type() == "diff":
347
- diff = core.create_new_diff(target_path, params, workspace=target_path, no_change=no_change)
358
+ diff = Core.create_new_diff(target_path, params, workspace=target_path, no_change=no_change)
348
359
  log.info("Starting comment logic for PR/MR event")
349
360
  log.debug(f"Getting comments for Repo {scm.repository} for PR {scm.pr_number}")
350
361
  comments = scm.get_comments_for_pr(repo, str(pr_number))
@@ -388,7 +399,7 @@ def main_code():
388
399
  )
389
400
  else:
390
401
  log.info("Starting non-PR/MR flow")
391
- diff = core.create_new_diff(target_path, params, workspace=target_path, no_change=no_change)
402
+ diff = Core.create_new_diff(target_path, params, workspace=target_path, no_change=no_change)
392
403
  if enable_json:
393
404
  log.debug("Outputting JSON Results")
394
405
  output_console_json(diff, sbom_file)
@@ -397,7 +408,7 @@ def main_code():
397
408
  else:
398
409
  log.info("API Mode")
399
410
  diff: Diff
400
- diff = core.create_new_diff(target_path, params, workspace=target_path, no_change=no_change)
411
+ diff = Core.create_new_diff(target_path, params, workspace=target_path, no_change=no_change)
401
412
  if enable_json:
402
413
  output_console_json(diff, sbom_file)
403
414
  else:
@@ -418,7 +429,7 @@ def main_code():
418
429
  "license_text": package.license_text
419
430
  }
420
431
  all_packages[package_id] = output
421
- core.save_file(license_file, json.dumps(all_packages))
432
+ Core.save_file(license_file, json.dumps(all_packages))
422
433
 
423
434
 
424
435
  if __name__ == '__main__':
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: socketsecurity
3
- Version: 1.0.32
3
+ Version: 1.0.34
4
4
  Summary: Socket Security CLI for CI/CD
5
5
  Author-email: Douglas Coburn <douglas@socket.dev>
6
6
  Maintainer-email: Douglas Coburn <douglas@socket.dev>
@@ -15,12 +15,16 @@ Classifier: Programming Language :: Python :: 3.12
15
15
  Requires-Python: >=3.9
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
- Requires-Dist: requests
19
- Requires-Dist: mdutils
18
+ Requires-Dist: requests>=2.32.0
19
+ Requires-Dist: mdutils~=1.6.0
20
20
  Requires-Dist: prettytable
21
21
  Requires-Dist: argparse
22
- Requires-Dist: GitPython
23
- Requires-Dist: packaging
22
+ Requires-Dist: GitPython>=3.1.43
23
+ Requires-Dist: packaging>=24.1
24
+ Requires-Dist: python-dotenv>=1.0.1
25
+ Requires-Dist: socket-sdk-python>=1.0.14
26
+ Provides-Extra: dev
27
+ Requires-Dist: ruff>=0.3.0; extra == "dev"
24
28
 
25
29
  # Socket Security CLI
26
30
 
@@ -0,0 +1,11 @@
1
+ requests>=2.32.0
2
+ mdutils~=1.6.0
3
+ prettytable
4
+ argparse
5
+ GitPython>=3.1.43
6
+ packaging>=24.1
7
+ python-dotenv>=1.0.1
8
+ socket-sdk-python>=1.0.14
9
+
10
+ [dev]
11
+ ruff>=0.3.0
@@ -1,48 +0,0 @@
1
- [build-system]
2
- requires = ["setuptools >= 61.0"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [project]
6
- name = "socketsecurity"
7
- dynamic = ["version"]
8
- requires-python = ">= 3.9"
9
- dependencies = [
10
- 'requests',
11
- 'mdutils',
12
- 'prettytable',
13
- 'argparse',
14
- 'GitPython',
15
- 'packaging'
16
- ]
17
- readme = "README.md"
18
- description = "Socket Security CLI for CI/CD"
19
- keywords = ["socketsecurity", "socket.dev", "sca", "oss", "security"]
20
- authors = [
21
- {name = "Douglas Coburn", email = "douglas@socket.dev"}
22
- ]
23
- maintainers = [
24
- {name = "Douglas Coburn", email = "douglas@socket.dev"}
25
- ]
26
- classifiers = [
27
- "Development Status :: 4 - Beta",
28
- "Intended Audience :: Developers",
29
- "Programming Language :: Python :: 3.9",
30
- "Programming Language :: Python :: 3.10",
31
- "Programming Language :: Python :: 3.11",
32
- "Programming Language :: Python :: 3.12",
33
- ]
34
-
35
- [project.scripts]
36
- socketcli = "socketsecurity.socketcli:cli"
37
-
38
- [project.urls]
39
- Homepage = "https://socket.dev"
40
-
41
- [tool.setuptools.packages.find]
42
- include = [
43
- "socketsecurity",
44
- "socketsecurity.core"
45
- ]
46
-
47
- [tool.setuptools.dynamic]
48
- version = {attr = "socketsecurity.__version__"}
@@ -1,6 +0,0 @@
1
- requests
2
- mdutils
3
- prettytable
4
- argparse
5
- GitPython
6
- packaging
File without changes