socketsecurity 2.0.7__tar.gz → 2.0.8__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 (32) hide show
  1. {socketsecurity-2.0.7/socketsecurity.egg-info → socketsecurity-2.0.8}/PKG-INFO +3 -2
  2. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/pyproject.toml +2 -1
  3. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/__init__.py +1 -1
  4. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/__init__.py +102 -104
  5. {socketsecurity-2.0.7 → socketsecurity-2.0.8/socketsecurity.egg-info}/PKG-INFO +3 -2
  6. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity.egg-info/requires.txt +2 -1
  7. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/LICENSE +0 -0
  8. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/README.md +0 -0
  9. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/setup.cfg +0 -0
  10. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/config.py +0 -0
  11. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/classes.py +0 -0
  12. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/cli_client.py +0 -0
  13. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/exceptions.py +0 -0
  14. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/git_interface.py +0 -0
  15. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/issues.py +0 -0
  16. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/licenses.py +0 -0
  17. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/logging.py +0 -0
  18. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/messages.py +0 -0
  19. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/scm/__init__.py +0 -0
  20. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/scm/base.py +0 -0
  21. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/scm/client.py +0 -0
  22. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/scm/github.py +0 -0
  23. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/scm/gitlab.py +0 -0
  24. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/scm_comments.py +0 -0
  25. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/socket_config.py +0 -0
  26. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/core/utils.py +0 -0
  27. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/output.py +0 -0
  28. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity/socketcli.py +0 -0
  29. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity.egg-info/SOURCES.txt +0 -0
  30. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity.egg-info/dependency_links.txt +0 -0
  31. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity.egg-info/entry_points.txt +0 -0
  32. {socketsecurity-2.0.7 → socketsecurity-2.0.8}/socketsecurity.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: socketsecurity
3
- Version: 2.0.7
3
+ Version: 2.0.8
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>
@@ -19,7 +19,7 @@ Requires-Dist: prettytable
19
19
  Requires-Dist: GitPython
20
20
  Requires-Dist: packaging
21
21
  Requires-Dist: python-dotenv
22
- Requires-Dist: socket-sdk-python>=2.0.7
22
+ Requires-Dist: socket-sdk-python>=2.0.8
23
23
  Provides-Extra: test
24
24
  Requires-Dist: pytest>=7.4.0; extra == "test"
25
25
  Requires-Dist: pytest-cov>=4.1.0; extra == "test"
@@ -28,6 +28,7 @@ Requires-Dist: pytest-asyncio>=0.23.0; extra == "test"
28
28
  Requires-Dist: pytest-watch>=4.2.0; extra == "test"
29
29
  Provides-Extra: dev
30
30
  Requires-Dist: ruff>=0.3.0; extra == "dev"
31
+ Requires-Dist: twine; extra == "dev"
31
32
  Requires-Dist: pip-tools>=7.4.0; extra == "dev"
32
33
 
33
34
  # Socket Security CLI
@@ -13,7 +13,7 @@ dependencies = [
13
13
  'GitPython',
14
14
  'packaging',
15
15
  'python-dotenv',
16
- 'socket-sdk-python>=2.0.7'
16
+ 'socket-sdk-python>=2.0.8'
17
17
  ]
18
18
  readme = "README.md"
19
19
  description = "Socket Security CLI for CI/CD"
@@ -41,6 +41,7 @@ test = [
41
41
  ]
42
42
  dev = [
43
43
  "ruff>=0.3.0",
44
+ "twine", # for building
44
45
  "pip-tools>=7.4.0", # for pip-compile
45
46
  ]
46
47
 
@@ -1,2 +1,2 @@
1
1
  __author__ = 'socket.dev'
2
- __version__ = '2.0.7'
2
+ __version__ = '2.0.8'
@@ -1,15 +1,14 @@
1
1
  import logging
2
- import time
3
2
  import sys
3
+ import time
4
4
  from dataclasses import asdict
5
5
  from glob import glob
6
6
  from pathlib import PurePath
7
7
  from typing import BinaryIO, Dict, List, Tuple
8
+
8
9
  from socketdev import socketdev
9
- from socketdev.fullscans import (
10
- FullScanParams,
11
- SocketArtifact
12
- )
10
+ from socketdev.exceptions import APIFailure
11
+ from socketdev.fullscans import FullScanParams, SocketArtifact
13
12
  from socketdev.org import Organization
14
13
  from socketdev.repos import RepositoryInfo
15
14
  from socketdev.settings import SecurityPolicyRule
@@ -23,10 +22,7 @@ from socketsecurity.core.classes import (
23
22
  Package,
24
23
  Purl,
25
24
  )
26
- from socketsecurity.core.exceptions import (
27
- APIResourceNotFound
28
- )
29
- from socketdev.exceptions import APIFailure
25
+ from socketsecurity.core.exceptions import APIResourceNotFound
30
26
  from socketsecurity.core.licenses import Licenses
31
27
 
32
28
  from .socket_config import SocketConfig
@@ -43,11 +39,11 @@ log = logging.getLogger("socketdev")
43
39
 
44
40
  class Core:
45
41
  """Main class for interacting with Socket Security API and processing scan results."""
46
-
42
+
47
43
  ALERT_TYPE_TO_CAPABILITY = {
48
44
  "envVars": "Environment Variables",
49
45
  "networkAccess": "Network Access",
50
- "filesystemAccess": "File System Access",
46
+ "filesystemAccess": "File System Access",
51
47
  "shellAccess": "Shell Access",
52
48
  "usesEval": "Uses Eval",
53
49
  "unsafe": "Unsafe"
@@ -77,7 +73,7 @@ class Core:
77
73
 
78
74
  def get_org_id_slug(self) -> Tuple[str, str]:
79
75
  """Gets the Org ID and Org Slug for the API Token."""
80
- response = self.sdk.org.get()
76
+ response = self.sdk.org.get(use_types=True)
81
77
  organizations: Dict[str, Organization] = response.get("organizations", {})
82
78
 
83
79
  if len(organizations) == 1:
@@ -87,33 +83,33 @@ class Core:
87
83
 
88
84
  def get_sbom_data(self, full_scan_id: str) -> Dict[str, SocketArtifact]:
89
85
  """Returns the list of SBOM artifacts for a full scan."""
90
- response = self.sdk.fullscans.stream(self.config.org_slug, full_scan_id)
86
+ response = self.sdk.fullscans.stream(self.config.org_slug, full_scan_id, use_types=True)
91
87
  if not response.success:
92
88
  log.debug(f"Failed to get SBOM data for full-scan {full_scan_id}")
93
89
  log.debug(response.message)
94
90
  return {}
95
91
 
96
92
  return response.artifacts
97
-
93
+
98
94
  def get_sbom_data_list(self, artifacts_dict: Dict[str, SocketArtifact]) -> list[SocketArtifact]:
99
95
  """Converts artifacts dictionary to a list."""
100
96
  return list(artifacts_dict.values())
101
97
 
102
98
  def get_security_policy(self) -> Dict[str, SecurityPolicyRule]:
103
99
  """Gets the organization's security policy."""
104
- response = self.sdk.settings.get(self.config.org_slug)
105
-
100
+ response = self.sdk.settings.get(self.config.org_slug, use_types=True)
101
+
106
102
  if not response.success:
107
103
  log.error(f"Failed to get security policy: {response.status}")
108
104
  log.error(response.message)
109
105
  raise Exception(f"Failed to get security policy: {response.status}, message: {response.message}")
110
-
106
+
111
107
  return response.securityPolicyRules
112
108
 
113
109
  def create_sbom_output(self, diff: Diff) -> dict:
114
110
  """Creates CycloneDX output for a given diff."""
115
111
  try:
116
- result = self.sdk.export.cdx_bom(self.config.org_slug, diff.id)
112
+ result = self.sdk.export.cdx_bom(self.config.org_slug, diff.id, use_types=True)
117
113
  if not result.success:
118
114
  log.error(f"Failed to get CycloneDX Output for full-scan {diff.id}")
119
115
  log.error(result.message)
@@ -121,7 +117,7 @@ class Core:
121
117
 
122
118
  result.pop("success", None)
123
119
  return result
124
- except Exception as error:
120
+ except Exception:
125
121
  log.error(f"Unable to get CycloneDX Output for {diff.id}")
126
122
  log.error(result.get("message", "No error message provided"))
127
123
  return {}
@@ -130,17 +126,17 @@ class Core:
130
126
  def find_files(path: str) -> List[str]:
131
127
  """
132
128
  Finds supported manifest files in the given path.
133
-
129
+
134
130
  Args:
135
131
  path: Path to search for manifest files
136
-
132
+
137
133
  Returns:
138
134
  List of found manifest file paths
139
135
  """
140
136
  log.debug("Starting Find Files")
141
137
  start_time = time.time()
142
138
  files = set()
143
-
139
+
144
140
  for ecosystem in socket_globs:
145
141
  patterns = socket_globs[ecosystem]
146
142
  for file_name in patterns:
@@ -165,18 +161,18 @@ class Core:
165
161
  else:
166
162
  log.debug(f"{len(files_list)} Files found ({total_time:.2f}s): {', '.join(files_list)}")
167
163
  return list(files)
168
-
164
+
169
165
  @staticmethod
170
166
  def to_case_insensitive_regex(input_string: str) -> str:
171
167
  """
172
168
  Converts a string into a case-insensitive regex pattern.
173
-
169
+
174
170
  Args:
175
171
  input_string: String to convert
176
-
172
+
177
173
  Returns:
178
174
  Case-insensitive regex pattern
179
-
175
+
180
176
  Example:
181
177
  "pipfile" -> "[Pp][Ii][Pp][Ff][Ii][Ll][Ee]"
182
178
  """
@@ -186,52 +182,52 @@ class Core:
186
182
  def load_files_for_sending(files: List[str], workspace: str) -> List[Tuple[str, Tuple[str, BinaryIO]]]:
187
183
  """
188
184
  Prepares files for sending to the Socket API.
189
-
185
+
190
186
  Args:
191
187
  files: List of file paths from find_files()
192
188
  workspace: Base directory path to make paths relative to
193
-
189
+
194
190
  Returns:
195
191
  List of tuples formatted for requests multipart upload:
196
192
  [(field_name, (filename, file_object)), ...]
197
193
  """
198
194
  send_files = []
199
-
195
+
200
196
  for file_path in files:
201
197
  if "/" in file_path:
202
198
  _, name = file_path.rsplit("/", 1)
203
199
  else:
204
200
  name = file_path
205
-
201
+
206
202
  if file_path.startswith(workspace):
207
203
  key = file_path[len(workspace):]
208
204
  else:
209
205
  key = file_path
210
-
206
+
211
207
  key = key.lstrip("/")
212
208
  key = key.lstrip("./")
213
-
209
+
214
210
  f = open(file_path, 'rb')
215
211
  payload = (key, (name, f))
216
212
  send_files.append(payload)
217
-
213
+
218
214
  return send_files
219
215
 
220
216
  def create_full_scan(self, files: List[str], params: FullScanParams, has_head_scan: bool = False) -> FullScan:
221
217
  """
222
218
  Creates a new full scan via the Socket API.
223
-
219
+
224
220
  Args:
225
221
  files: List of files to scan
226
222
  params: Parameters for the full scan
227
-
223
+
228
224
  Returns:
229
225
  FullScan object with scan results
230
226
  """
231
227
  log.debug("Creating new full scan")
232
228
  create_full_start = time.time()
233
229
 
234
- res = self.sdk.fullscans.post(files, params)
230
+ res = self.sdk.fullscans.post(files, params, use_types=True)
235
231
  if not res.success:
236
232
  log.error(f"Error creating full scan: {res.message}, status: {res.status}")
237
233
  raise Exception(f"Error creating full scan: {res.message}, status: {res.status}")
@@ -245,20 +241,20 @@ class Core:
245
241
  create_full_end = time.time()
246
242
  total_time = create_full_end - create_full_start
247
243
  log.debug(f"New Full Scan created in {total_time:.2f} seconds")
248
-
244
+
249
245
  return full_scan
250
246
 
251
247
  def get_full_scan(self, full_scan_id: str) -> FullScan:
252
248
  """
253
249
  Get a FullScan object for an existing full scan including sbom_artifacts and packages.
254
-
250
+
255
251
  Args:
256
252
  full_scan_id: The ID of the full scan to get
257
-
253
+
258
254
  Returns:
259
255
  The FullScan object with populated artifacts and packages
260
256
  """
261
- full_scan_metadata = self.sdk.fullscans.metadata(self.config.org_slug, full_scan_id)
257
+ full_scan_metadata = self.sdk.fullscans.metadata(self.config.org_slug, full_scan_id, use_types=True)
262
258
  full_scan = FullScan(**asdict(full_scan_metadata.data))
263
259
  full_scan_artifacts_dict = self.get_sbom_data(full_scan_id)
264
260
  full_scan.sbom_artifacts = self.get_sbom_data_list(full_scan_artifacts_dict)
@@ -268,10 +264,10 @@ class Core:
268
264
  def create_packages_dict(self, sbom_artifacts: list[SocketArtifact]) -> dict[str, Package]:
269
265
  """
270
266
  Creates a dictionary of Package objects from SBOM artifacts.
271
-
267
+
272
268
  Args:
273
269
  sbom_artifacts: List of SBOM artifacts from the scan
274
-
270
+
275
271
  Returns:
276
272
  Dictionary mapping package IDs to Package objects
277
273
  """
@@ -289,51 +285,51 @@ class Core:
289
285
  top_level_count[top_id] = 1
290
286
  else:
291
287
  top_level_count[top_id] += 1
292
-
288
+
293
289
  for package_id, package in packages.items():
294
290
  package.transitives = top_level_count.get(package_id, 0)
295
291
 
296
292
  return packages
297
-
293
+
298
294
  def get_package_license_text(self, package: Package) -> str:
299
295
  """
300
296
  Gets the license text for a package if available.
301
-
297
+
302
298
  Args:
303
299
  package: Package object to get license text for
304
-
300
+
305
301
  Returns:
306
302
  License text if found, empty string otherwise
307
303
  """
308
304
  if package.license is None:
309
305
  return ""
310
-
306
+
311
307
  license_raw = package.license
312
308
  all_licenses = Licenses()
313
309
  license_str = Licenses.make_python_safe(license_raw)
314
-
310
+
315
311
  if license_str is not None and hasattr(all_licenses, license_str):
316
312
  license_obj = getattr(all_licenses, license_str)
317
313
  return license_obj.licenseText
318
-
314
+
319
315
  return ""
320
316
 
321
317
  def get_repo_info(self, repo_slug: str, default_branch: str = "socket-default-branch") -> RepositoryInfo:
322
318
  """
323
319
  Gets repository information from the Socket API.
324
-
320
+
325
321
  Args:
326
322
  repo_slug: Repository slug to get info for
327
323
  default_branch: Default branch string to use if the repo doesn't exist
328
-
324
+
329
325
  Returns:
330
326
  RepositoryInfo object
331
-
327
+
332
328
  Raises:
333
329
  Exception: If API request fails
334
330
  """
335
331
  try:
336
- response = self.sdk.repos.repo(self.config.org_slug, repo_slug)
332
+ response = self.sdk.repos.repo(self.config.org_slug, repo_slug, use_types=True)
337
333
  if not response.success:
338
334
  log.error(f"Failed to get repository: {response.status}")
339
335
  log.error(response.message)
@@ -354,10 +350,10 @@ class Core:
354
350
  def get_head_scan_for_repo(self, repo_slug: str) -> str:
355
351
  """
356
352
  Gets the head scan ID for a repository.
357
-
353
+
358
354
  Args:
359
355
  repo_slug: Repository slug to get head scan for
360
-
356
+
361
357
  Returns:
362
358
  Head scan ID if it exists, None otherwise
363
359
  """
@@ -377,24 +373,34 @@ class Core:
377
373
  def get_added_and_removed_packages(self, head_full_scan_id: str, new_full_scan: FullScan) -> Tuple[Dict[str, Package], Dict[str, Package]]:
378
374
  """
379
375
  Get packages that were added and removed between scans.
380
-
376
+
381
377
  Args:
382
378
  head_full_scan: Previous scan (may be None if first scan)
383
379
  head_full_scan_id: New scan just created
384
-
380
+
385
381
  Returns:
386
382
  Tuple of (added_packages, removed_packages) dictionaries
387
383
  """
388
384
  if head_full_scan_id is None:
389
385
  log.info(f"No head scan found. New scan ID: {new_full_scan.id}")
390
386
  return new_full_scan.packages, {}
391
-
387
+
392
388
  log.info(f"Comparing scans - Head scan ID: {head_full_scan_id}, New scan ID: {new_full_scan.id}")
393
389
  diff_start = time.time()
394
- diff_report = self.sdk.fullscans.stream_diff(self.config.org_slug, head_full_scan_id, new_full_scan.id).data
390
+ try:
391
+ diff_report = self.sdk.fullscans.stream_diff(self.config.org_slug, head_full_scan_id, new_full_scan.id, use_types=True).data
392
+ except APIFailure as e:
393
+ log.error(f"API Error: {e}")
394
+ sys.exit(1)
395
+ except Exception as e:
396
+ import traceback
397
+ log.error(f"Error getting diff report: {str(e)}")
398
+ log.error(f"Stack trace:\n{traceback.format_exc()}")
399
+ raise
400
+
395
401
  diff_end = time.time()
396
402
  log.info(f"Diff Report Gathered in {diff_end - diff_start:.2f} seconds")
397
- log.info(f"Diff report artifact counts:")
403
+ log.info("Diff report artifact counts:")
398
404
  log.info(f"Added: {len(diff_report.artifacts.added)}")
399
405
  log.info(f"Removed: {len(diff_report.artifacts.removed)}")
400
406
  log.info(f"Unchanged: {len(diff_report.artifacts.unchanged)}")
@@ -442,7 +448,6 @@ class Core:
442
448
  Args:
443
449
  path: Path to look for manifest files
444
450
  params: Query params for the Full Scan endpoint
445
-
446
451
  no_change: If True, return empty diff
447
452
  """
448
453
  log.debug(f"starting create_new_diff with no_change: {no_change}")
@@ -464,7 +469,7 @@ class Core:
464
469
  head_full_scan_id = None
465
470
  has_head_scan = False
466
471
 
467
- # Create new scan
472
+ # Create new scan
468
473
  try:
469
474
  new_scan_start = time.time()
470
475
  new_full_scan = self.create_full_scan(files_for_sending, params, has_head_scan)
@@ -474,17 +479,12 @@ class Core:
474
479
  log.error(f"API Error: {e}")
475
480
  sys.exit(1)
476
481
  except Exception as e:
477
- log.error(f"Unexpected error while creating new scan: {e}")
478
- sys.exit(1)
482
+ import traceback
483
+ log.error(f"Error creating new full scan: {str(e)}")
484
+ log.error(f"Stack trace:\n{traceback.format_exc()}")
485
+ raise
479
486
 
480
- try:
481
- added_packages, removed_packages = self.get_added_and_removed_packages(head_full_scan_id, new_full_scan)
482
- except APIFailure as e:
483
- log.error(f"API Error: {e}")
484
- sys.exit(1)
485
- except Exception as e:
486
- log.error(f"Unexpected error while comparing packages: {e}")
487
- sys.exit(1)
487
+ added_packages, removed_packages = self.get_added_and_removed_packages(head_full_scan_id, new_full_scan)
488
488
 
489
489
  diff = self.create_diff_report(added_packages, removed_packages)
490
490
 
@@ -495,7 +495,7 @@ class Core:
495
495
  if not params.include_license_details:
496
496
  report_url += "?include_license_details=false"
497
497
  diff.report_url = report_url
498
-
498
+
499
499
  if head_full_scan_id is not None:
500
500
  diff.diff_url = f"{base_socket}/{self.config.org_slug}/diff/{diff.id}/{head_full_scan_id}"
501
501
  else:
@@ -504,25 +504,25 @@ class Core:
504
504
  return diff
505
505
 
506
506
  def create_diff_report(
507
- self,
508
- added_packages: Dict[str, Package],
507
+ self,
508
+ added_packages: Dict[str, Package],
509
509
  removed_packages: Dict[str, Package],
510
510
  direct_only: bool = True
511
511
  ) -> Diff:
512
512
  """
513
513
  Creates a diff report comparing two sets of packages.
514
-
514
+
515
515
  Takes packages that were added and removed between two scans and:
516
516
  1. Records new/removed packages (direct only by default)
517
517
  2. Collects alerts from both sets of packages
518
518
  3. Determines new capabilities introduced
519
-
519
+
520
520
  Args:
521
521
  added_packages: Dict of packages added in new scan
522
522
  removed_packages: Dict of packages removed in new scan
523
523
  direct_only: If True, only direct dependencies are included in new/removed lists
524
524
  (but alerts are still processed for all packages)
525
-
525
+
526
526
  Returns:
527
527
  Diff object containing the comparison results
528
528
  """
@@ -577,11 +577,11 @@ class Core:
577
577
  def create_purl(package_id: str, packages: dict[str, Package]) -> Purl:
578
578
  """
579
579
  Creates the extended PURL data for package identification and tracking.
580
-
580
+
581
581
  Args:
582
582
  package_id: Package ID to create PURL data for
583
583
  packages: Dictionary of all packages for transitive dependency lookup
584
-
584
+
585
585
  Returns:
586
586
  Purl object containing package metadata and dependency information
587
587
  """
@@ -606,14 +606,14 @@ class Core:
606
606
  def get_source_data(package: Package, packages: dict) -> list:
607
607
  """
608
608
  Determines how a package was introduced into the dependency tree.
609
-
609
+
610
610
  For direct dependencies, records the manifest file.
611
611
  For transitive dependencies, records the top-level package that introduced it.
612
-
612
+
613
613
  Args:
614
614
  package: Package to analyze
615
615
  packages: Dictionary of all packages for ancestor lookup
616
-
616
+
617
617
  Returns:
618
618
  List of tuples containing (source, manifest_file) information
619
619
  """
@@ -648,7 +648,7 @@ class Core:
648
648
  def add_purl_capabilities(diff: Diff) -> None:
649
649
  """
650
650
  Adds capability information to each package in the diff's new_packages list.
651
-
651
+
652
652
  Args:
653
653
  diff: Diff object to update with capability information
654
654
  """
@@ -662,18 +662,18 @@ class Core:
662
662
  new_packages.append(new_purl)
663
663
  else:
664
664
  new_packages.append(purl)
665
-
665
+
666
666
  diff.new_packages = new_packages
667
667
 
668
668
  def add_package_alerts_to_collection(self, package: Package, alerts_collection: dict, packages: dict) -> dict:
669
669
  """
670
670
  Processes alerts from a package and adds them to a shared alerts collection.
671
-
671
+
672
672
  Args:
673
673
  package: Package to process alerts from
674
674
  alerts_collection: Dictionary to store processed alerts
675
675
  packages: Dictionary of all packages for dependency lookup
676
-
676
+
677
677
  Returns:
678
678
  Updated alerts collection dictionary
679
679
  """
@@ -723,11 +723,11 @@ class Core:
723
723
  def save_file(file_name: str, content: str) -> None:
724
724
  """
725
725
  Saves content to a file, raising an error if the save fails.
726
-
726
+
727
727
  Args:
728
728
  file_name: Path to save the file
729
729
  content: Content to write to the file
730
-
730
+
731
731
  Raises:
732
732
  IOError: If file cannot be written
733
733
  """
@@ -742,10 +742,10 @@ class Core:
742
742
  def has_manifest_files(files: list) -> bool:
743
743
  """
744
744
  Checks if any files in the list are supported manifest files.
745
-
745
+
746
746
  Args:
747
747
  files: List of file paths to check
748
-
748
+
749
749
  Returns:
750
750
  True if any files match manifest patterns, False otherwise
751
751
  """
@@ -764,41 +764,41 @@ class Core:
764
764
  def get_capabilities_for_added_packages(added_packages: Dict[str, Package]) -> Dict[str, List[str]]:
765
765
  """
766
766
  Maps added packages to their capabilities based on their alerts.
767
-
767
+
768
768
  Args:
769
769
  added_packages: Dictionary of packages added in new scan
770
-
770
+
771
771
  Returns:
772
772
  Dictionary mapping package IDs to their capability lists
773
773
  """
774
774
  capabilities: Dict[str, List[str]] = {}
775
-
775
+
776
776
  for package_id, package in added_packages.items():
777
777
  for alert in package.alerts:
778
778
  if alert["type"] in Core.ALERT_TYPE_TO_CAPABILITY:
779
779
  value = Core.ALERT_TYPE_TO_CAPABILITY[alert["type"]]
780
-
780
+
781
781
  if package_id not in capabilities:
782
782
  capabilities[package_id] = [value]
783
783
  elif value not in capabilities[package_id]:
784
784
  capabilities[package_id].append(value)
785
-
785
+
786
786
  return capabilities
787
787
 
788
788
  @staticmethod
789
789
  def get_new_alerts(
790
- added_package_alerts: Dict[str, List[Issue]],
790
+ added_package_alerts: Dict[str, List[Issue]],
791
791
  removed_package_alerts: Dict[str, List[Issue]],
792
792
  ignore_readded: bool = True
793
793
  ) -> List[Issue]:
794
794
  """
795
795
  Find alerts that are new or changed between added and removed packages.
796
-
796
+
797
797
  Args:
798
798
  added_package_alerts: Dictionary of alerts from packages that were added
799
799
  removed_package_alerts: Dictionary of alerts from packages that were removed
800
800
  ignore_readded: If True, don't report alerts that were both removed and added
801
-
801
+
802
802
  Returns:
803
803
  List of newly found alerts
804
804
  """
@@ -810,7 +810,7 @@ class Core:
810
810
  new_alerts = added_package_alerts[alert_key]
811
811
  for alert in new_alerts:
812
812
  alert_str = f"{alert.purl},{alert.manifests},{alert.type}"
813
-
813
+
814
814
  if alert.error or alert.warn:
815
815
  if alert_str not in consolidated_alerts:
816
816
  alerts.append(alert)
@@ -818,10 +818,10 @@ class Core:
818
818
  else:
819
819
  new_alerts = added_package_alerts[alert_key]
820
820
  removed_alerts = removed_package_alerts[alert_key]
821
-
821
+
822
822
  for alert in new_alerts:
823
823
  alert_str = f"{alert.purl},{alert.manifests},{alert.type}"
824
-
824
+
825
825
  # Only add if:
826
826
  # 1. Alert isn't in removed packages (or we're not ignoring readded alerts)
827
827
  # 2. We haven't already recorded this alert
@@ -832,5 +832,3 @@ class Core:
832
832
  consolidated_alerts.add(alert_str)
833
833
 
834
834
  return alerts
835
-
836
-
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: socketsecurity
3
- Version: 2.0.7
3
+ Version: 2.0.8
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>
@@ -19,7 +19,7 @@ Requires-Dist: prettytable
19
19
  Requires-Dist: GitPython
20
20
  Requires-Dist: packaging
21
21
  Requires-Dist: python-dotenv
22
- Requires-Dist: socket-sdk-python>=2.0.7
22
+ Requires-Dist: socket-sdk-python>=2.0.8
23
23
  Provides-Extra: test
24
24
  Requires-Dist: pytest>=7.4.0; extra == "test"
25
25
  Requires-Dist: pytest-cov>=4.1.0; extra == "test"
@@ -28,6 +28,7 @@ Requires-Dist: pytest-asyncio>=0.23.0; extra == "test"
28
28
  Requires-Dist: pytest-watch>=4.2.0; extra == "test"
29
29
  Provides-Extra: dev
30
30
  Requires-Dist: ruff>=0.3.0; extra == "dev"
31
+ Requires-Dist: twine; extra == "dev"
31
32
  Requires-Dist: pip-tools>=7.4.0; extra == "dev"
32
33
 
33
34
  # Socket Security CLI
@@ -4,10 +4,11 @@ prettytable
4
4
  GitPython
5
5
  packaging
6
6
  python-dotenv
7
- socket-sdk-python>=2.0.7
7
+ socket-sdk-python>=2.0.8
8
8
 
9
9
  [dev]
10
10
  ruff>=0.3.0
11
+ twine
11
12
  pip-tools>=7.4.0
12
13
 
13
14
  [test]
File without changes
File without changes
File without changes