socketsecurity 2.0.55__tar.gz → 2.1.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.
Files changed (80) hide show
  1. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/PKG-INFO +16 -14
  2. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/README.md +14 -12
  3. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/pyproject.toml +2 -6
  4. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/__init__.py +1 -1
  5. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/config.py +15 -0
  6. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/__init__.py +81 -26
  7. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/socket_config.py +3 -3
  8. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/socketcli.py +2 -0
  9. socketsecurity-2.0.55/socketsecurity/core/issues.py +0 -2101
  10. socketsecurity-2.0.55/socketsecurity/core/licenses.py +0 -21574
  11. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/CODEOWNERS +0 -0
  12. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/PULL_REQUEST_TEMPLATE/bug-fix.md +0 -0
  13. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/PULL_REQUEST_TEMPLATE/feature.md +0 -0
  14. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/PULL_REQUEST_TEMPLATE/improvement.md +0 -0
  15. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  16. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/workflows/docker-stable.yml +0 -0
  17. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/workflows/pr-preview.yml +0 -0
  18. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/workflows/release.yml +0 -0
  19. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/workflows/version-check.yml +0 -0
  20. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.gitignore +0 -0
  21. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.hooks/sync_version.py +0 -0
  22. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.pre-commit-config.yaml +0 -0
  23. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.python-version +0 -0
  24. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/Dockerfile +0 -0
  25. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/LICENSE +0 -0
  26. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/Makefile +0 -0
  27. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/Pipfile.lock +0 -0
  28. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/docs/README.md +0 -0
  29. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/pytest.ini +0 -0
  30. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/requirements-dev.lock +0 -0
  31. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/requirements.lock +0 -0
  32. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/scripts/build_container.sh +0 -0
  33. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/scripts/deploy-test-docker.sh +0 -0
  34. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/scripts/deploy-test-pypi.sh +0 -0
  35. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/scripts/run.sh +0 -0
  36. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/classes.py +0 -0
  37. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/cli_client.py +0 -0
  38. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/exceptions.py +0 -0
  39. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/git_interface.py +0 -0
  40. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/logging.py +0 -0
  41. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/messages.py +0 -0
  42. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/scm/__init__.py +0 -0
  43. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/scm/base.py +0 -0
  44. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/scm/client.py +0 -0
  45. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/scm/github.py +0 -0
  46. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/scm/gitlab.py +0 -0
  47. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/scm_comments.py +0 -0
  48. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/utils.py +0 -0
  49. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/output.py +0 -0
  50. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/plugins/__init__.py +0 -0
  51. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/plugins/base.py +0 -0
  52. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/plugins/jira.py +0 -0
  53. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/plugins/manager.py +0 -0
  54. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/plugins/slack.py +0 -0
  55. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/plugins/teams.py +0 -0
  56. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/plugins/webhook.py +0 -0
  57. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/__init__.py +0 -0
  58. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/core/conftest.py +0 -0
  59. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/core/create_diff_input.json +0 -0
  60. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/core/test_diff_generation.py +0 -0
  61. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/core/test_package_and_alerts.py +0 -0
  62. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/core/test_sdk_methods.py +0 -0
  63. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/core/test_supporting_methods.py +0 -0
  64. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/create_response.json +0 -0
  65. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/diff/stream_diff.json +0 -0
  66. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/diff/stream_diff_full.json +0 -0
  67. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/head_scan/metadata.json +0 -0
  68. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/head_scan/stream_scan.json +0 -0
  69. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/head_scan/stream_scan_full.json +0 -0
  70. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/new_scan/metadata.json +0 -0
  71. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/new_scan/stream_scan.json +0 -0
  72. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/repos/repo_info_error.json +0 -0
  73. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/repos/repo_info_no_head.json +0 -0
  74. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/repos/repo_info_success.json +0 -0
  75. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/settings/security-policy.json +0 -0
  76. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/unit/__init__.py +0 -0
  77. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/unit/test_cli_config.py +0 -0
  78. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/unit/test_client.py +0 -0
  79. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/unit/test_config.py +0 -0
  80. {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/unit/test_output.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: socketsecurity
3
- Version: 2.0.55
3
+ Version: 2.1.0
4
4
  Summary: Socket Security CLI for CI/CD
5
5
  Project-URL: Homepage, https://socket.dev
6
6
  Author-email: Douglas Coburn <douglas@socket.dev>
@@ -39,7 +39,7 @@ Requires-Dist: packaging
39
39
  Requires-Dist: prettytable
40
40
  Requires-Dist: python-dotenv
41
41
  Requires-Dist: requests
42
- Requires-Dist: socket-sdk-python>=2.0.21
42
+ Requires-Dist: socket-sdk-python<3,>=2.1.2
43
43
  Provides-Extra: dev
44
44
  Requires-Dist: hatch; extra == 'dev'
45
45
  Requires-Dist: pip-tools>=7.4.0; extra == 'dev'
@@ -79,13 +79,14 @@ If you don't want to provide the Socket API Token every time then you can use th
79
79
  | --api-token | False | | Socket Security API token (can also be set via SOCKET_SECURITY_API_KEY env var) |
80
80
 
81
81
  #### Repository
82
- | Parameter | Required | Default | Description |
83
- |:--------------|:---------|:--------|:------------------------------------------------------------------------|
84
- | --repo | False | | Repository name in owner/repo format |
85
- | --integration | False | api | Integration type (api, github, gitlab) |
86
- | --owner | False | | Name of the integration owner, defaults to the socket organization slug |
87
- | --branch | False | "" | Branch name |
88
- | --committers | False | | Committer(s) to filter by |
82
+ | Parameter | Required | Default | Description |
83
+ |:-----------------|:---------|:--------|:------------------------------------------------------------------------|
84
+ | --repo | False | | Repository name in owner/repo format |
85
+ | --integration | False | api | Integration type (api, github, gitlab) |
86
+ | --owner | False | | Name of the integration owner, defaults to the socket organization slug |
87
+ | --branch | False | "" | Branch name |
88
+ | --committers | False | | Committer(s) to filter by |
89
+ | --repo-is-public | False | False | If set, flags a new repository creation as public. Defaults to false. |
89
90
 
90
91
  #### Pull Request and Commit
91
92
  | Parameter | Required | Default | Description |
@@ -95,11 +96,12 @@ If you don't want to provide the Socket API Token every time then you can use th
95
96
  | --commit-sha | False | "" | Commit SHA |
96
97
 
97
98
  #### Path and File
98
- | Parameter | Required | Default | Description |
99
- |:--------------|:---------|:--------|:-------------------------------------|
100
- | --target-path | False | ./ | Target path for analysis |
101
- | --sbom-file | False | | SBOM file path |
102
- | --files | False | [] | Files to analyze (JSON array string) |
99
+ | Parameter | Required | Default | Description |
100
+ |:-------------------|:---------|:--------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
101
+ | --target-path | False | ./ | Target path for analysis |
102
+ | --sbom-file | False | | SBOM file path |
103
+ | --files | False | [] | Files to analyze (JSON array string) |
104
+ | --exclude-patterns | False | [] | List of patterns to exclude from analysis (JSON array string). You can get supported files form the [Supported Files API](https://docs.socket.dev/reference/getsupportedfiles) |
103
105
 
104
106
  #### Branch and Scan Configuration
105
107
  | Parameter | Required | Default | Description |
@@ -23,13 +23,14 @@ If you don't want to provide the Socket API Token every time then you can use th
23
23
  | --api-token | False | | Socket Security API token (can also be set via SOCKET_SECURITY_API_KEY env var) |
24
24
 
25
25
  #### Repository
26
- | Parameter | Required | Default | Description |
27
- |:--------------|:---------|:--------|:------------------------------------------------------------------------|
28
- | --repo | False | | Repository name in owner/repo format |
29
- | --integration | False | api | Integration type (api, github, gitlab) |
30
- | --owner | False | | Name of the integration owner, defaults to the socket organization slug |
31
- | --branch | False | "" | Branch name |
32
- | --committers | False | | Committer(s) to filter by |
26
+ | Parameter | Required | Default | Description |
27
+ |:-----------------|:---------|:--------|:------------------------------------------------------------------------|
28
+ | --repo | False | | Repository name in owner/repo format |
29
+ | --integration | False | api | Integration type (api, github, gitlab) |
30
+ | --owner | False | | Name of the integration owner, defaults to the socket organization slug |
31
+ | --branch | False | "" | Branch name |
32
+ | --committers | False | | Committer(s) to filter by |
33
+ | --repo-is-public | False | False | If set, flags a new repository creation as public. Defaults to false. |
33
34
 
34
35
  #### Pull Request and Commit
35
36
  | Parameter | Required | Default | Description |
@@ -39,11 +40,12 @@ If you don't want to provide the Socket API Token every time then you can use th
39
40
  | --commit-sha | False | "" | Commit SHA |
40
41
 
41
42
  #### Path and File
42
- | Parameter | Required | Default | Description |
43
- |:--------------|:---------|:--------|:-------------------------------------|
44
- | --target-path | False | ./ | Target path for analysis |
45
- | --sbom-file | False | | SBOM file path |
46
- | --files | False | [] | Files to analyze (JSON array string) |
43
+ | Parameter | Required | Default | Description |
44
+ |:-------------------|:---------|:--------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
45
+ | --target-path | False | ./ | Target path for analysis |
46
+ | --sbom-file | False | | SBOM file path |
47
+ | --files | False | [] | Files to analyze (JSON array string) |
48
+ | --exclude-patterns | False | [] | List of patterns to exclude from analysis (JSON array string). You can get supported files form the [Supported Files API](https://docs.socket.dev/reference/getsupportedfiles) |
47
49
 
48
50
  #### Branch and Scan Configuration
49
51
  | Parameter | Required | Default | Description |
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "socketsecurity"
9
- version = "2.0.55"
9
+ version = "2.1.0"
10
10
  requires-python = ">= 3.10"
11
11
  license = {"file" = "LICENSE"}
12
12
  dependencies = [
@@ -16,7 +16,7 @@ dependencies = [
16
16
  'GitPython',
17
17
  'packaging',
18
18
  'python-dotenv',
19
- 'socket-sdk-python>=2.0.21'
19
+ 'socket-sdk-python>=2.1.2,<3'
20
20
  ]
21
21
  readme = "README.md"
22
22
  description = "Socket Security CLI for CI/CD"
@@ -63,10 +63,6 @@ include = [
63
63
  "socketsecurity/**/*.py",
64
64
  "socketsecurity/**/__init__.py"
65
65
  ]
66
- omit = [
67
- "socketsecurity/core/issues.py", # Large data file
68
- "socketsecurity/core/licenses.py" # Large data file
69
- ]
70
66
 
71
67
  [tool.coverage.report]
72
68
  exclude_lines = [
@@ -1,2 +1,2 @@
1
1
  __author__ = 'socket.dev'
2
- __version__ = '2.0.55'
2
+ __version__ = '2.1.0'
@@ -1,4 +1,5 @@
1
1
  import argparse
2
+ import logging
2
3
  import os
3
4
  from dataclasses import asdict, dataclass, field
4
5
  from typing import List, Optional
@@ -51,6 +52,7 @@ class CliConfig:
51
52
  exclude_license_details: bool = False
52
53
  include_module_folders: bool = False
53
54
  repo_is_public: bool = False
55
+ excluded_ecosystems: list[str] = field(default_factory=lambda: [])
54
56
  version: str = __version__
55
57
  jira_plugin: PluginConfig = field(default_factory=PluginConfig)
56
58
  slack_plugin: PluginConfig = field(default_factory=PluginConfig)
@@ -96,8 +98,14 @@ class CliConfig:
96
98
  'exclude_license_details': args.exclude_license_details,
97
99
  'include_module_folders': args.include_module_folders,
98
100
  'repo_is_public': args.repo_is_public,
101
+ "excluded_ecosystems": args.excluded_ecosystems,
99
102
  'version': __version__
100
103
  }
104
+ try:
105
+ config_args["excluded_ecosystems"] = json.loads(config_args["excluded_ecosystems"].replace("'", '"'))
106
+ except json.JSONDecodeError:
107
+ logging.error(f"Unable to parse excluded_ecosystems: {config_args['excluded_ecosystems']}")
108
+ exit(1)
101
109
  config_args.update({
102
110
  "jira_plugin": PluginConfig(
103
111
  enabled=os.getenv("SOCKET_JIRA_ENABLED", "false").lower() == "true",
@@ -252,6 +260,13 @@ def create_argument_parser() -> argparse.ArgumentParser:
252
260
  help="Files to analyze (JSON array string)"
253
261
  )
254
262
 
263
+ path_group.add_argument(
264
+ "--excluded-ecosystems",
265
+ default="[]",
266
+ dest="excluded_ecosystems",
267
+ help="List of ecosystems to exclude from analysis (JSON array string)"
268
+ )
269
+
255
270
  # Branch and Scan Configuration
256
271
  config_group = parser.add_argument_group('Branch and Scan Configuration')
257
272
  config_group.add_argument(
@@ -2,10 +2,12 @@ import logging
2
2
  import os
3
3
  import sys
4
4
  import time
5
+ import io
5
6
  from dataclasses import asdict
6
7
  from glob import glob
8
+ from io import BytesIO
7
9
  from pathlib import PurePath
8
- from typing import BinaryIO, Dict, List, Tuple, Set
10
+ from typing import BinaryIO, Dict, List, Tuple, Set, Union
9
11
  import re
10
12
  from socketdev import socketdev
11
13
  from socketdev.exceptions import APIFailure
@@ -24,7 +26,6 @@ from socketsecurity.core.classes import (
24
26
  Purl
25
27
  )
26
28
  from socketsecurity.core.exceptions import APIResourceNotFound
27
- from socketsecurity.core.licenses import Licenses
28
29
  from .socket_config import SocketConfig
29
30
  from .utils import socket_globs
30
31
  import importlib
@@ -184,6 +185,8 @@ class Core:
184
185
  patterns = fallback_patterns
185
186
 
186
187
  for ecosystem in patterns:
188
+ if ecosystem in self.config.excluded_ecosystems:
189
+ continue
187
190
  ecosystem_patterns = patterns[ecosystem]
188
191
  for file_name in ecosystem_patterns:
189
192
  original_pattern = ecosystem_patterns[file_name]["pattern"]
@@ -276,6 +279,14 @@ class Core:
276
279
  """
277
280
  return ''.join(f'[{char.lower()}{char.upper()}]' if char.isalpha() else char for char in input_string)
278
281
 
282
+ @staticmethod
283
+ def empty_head_scan_file() -> list[tuple[str, tuple[str, Union[BinaryIO, BytesIO]]]]:
284
+ # Create an empty file for when no head full scan so that the diff endpoint can always be used
285
+ empty_file_obj = io.BytesIO(b"")
286
+ empty_filename = "initial_head_scan"
287
+ empty_full_scan_file = [(empty_filename, (empty_filename, empty_file_obj))]
288
+ return empty_full_scan_file
289
+
279
290
  @staticmethod
280
291
  def load_files_for_sending(files: List[str], workspace: str) -> List[Tuple[str, Tuple[str, BinaryIO]]]:
281
292
  """
@@ -309,7 +320,7 @@ class Core:
309
320
 
310
321
  return send_files
311
322
 
312
- def create_full_scan(self, files: List[str], params: FullScanParams, has_head_scan: bool = False) -> FullScan:
323
+ def create_full_scan(self, files: list[tuple[str, tuple[str, BytesIO]]], params: FullScanParams) -> FullScan:
313
324
  """
314
325
  Creates a new full scan via the Socket API.
315
326
 
@@ -329,16 +340,60 @@ class Core:
329
340
  raise Exception(f"Error creating full scan: {res.message}, status: {res.status}")
330
341
 
331
342
  full_scan = FullScan(**asdict(res.data))
332
- if not has_head_scan:
333
- full_scan.sbom_artifacts = self.get_sbom_data(full_scan.id)
334
- full_scan.packages = self.create_packages_dict(full_scan.sbom_artifacts)
335
-
336
343
  create_full_end = time.time()
337
344
  total_time = create_full_end - create_full_start
338
345
  log.debug(f"New Full Scan created in {total_time:.2f} seconds")
339
346
 
340
347
  return full_scan
341
348
 
349
+ def check_full_scans_status(self, head_full_scan_id: str, new_full_scan_id: str) -> bool:
350
+ is_ready = False
351
+ current_timeout = self.config.timeout
352
+ self.sdk.set_timeout(0.5)
353
+ try:
354
+ self.sdk.fullscans.stream(self.config.org_slug, head_full_scan_id)
355
+ except Exception:
356
+ log.debug(f"Queued up full scan for processing ({head_full_scan_id})")
357
+
358
+ try:
359
+ self.sdk.fullscans.stream(self.config.org_slug, new_full_scan_id)
360
+ except Exception:
361
+ log.debug(f"Queued up full scan for processing ({new_full_scan_id})")
362
+ self.sdk.set_timeout(current_timeout)
363
+ start_check = time.time()
364
+ head_is_ready = False
365
+ new_is_ready = False
366
+ while not is_ready:
367
+ head_full_scan_metadata = self.sdk.fullscans.metadata(self.config.org_slug, head_full_scan_id)
368
+ if head_full_scan_metadata:
369
+ head_state = head_full_scan_metadata.get("scan_state")
370
+ else:
371
+ head_state = None
372
+ new_full_scan_metadata = self.sdk.fullscans.metadata(self.config.org_slug, new_full_scan_id)
373
+ if new_full_scan_metadata:
374
+ new_state = new_full_scan_metadata.get("scan_state")
375
+ else:
376
+ new_state = None
377
+ if head_state and head_state == "resolve":
378
+ head_is_ready = True
379
+ if new_state and new_state == "resolve":
380
+ new_is_ready = True
381
+ if head_is_ready and new_is_ready:
382
+ is_ready = True
383
+ current_time = time.time()
384
+ if current_time - start_check >= self.config.timeout:
385
+ log.debug(
386
+ f"Timeout reached while waiting for full scans to be ready "
387
+ f"({head_full_scan_id}, {new_full_scan_id})"
388
+ )
389
+ break
390
+ total_time = time.time() - start_check
391
+ if is_ready:
392
+ log.info(f"Full scans are ready in {total_time:.2f} seconds")
393
+ else:
394
+ log.warning(f"Full scans are not ready yet ({head_full_scan_id}, {new_full_scan_id})")
395
+ return is_ready
396
+
342
397
  def get_full_scan(self, full_scan_id: str) -> FullScan:
343
398
  """
344
399
  Get a FullScan object for an existing full scan including sbom_artifacts and packages.
@@ -401,14 +456,9 @@ class Core:
401
456
  return ""
402
457
 
403
458
  license_raw = package.license
404
- all_licenses = Licenses()
405
- license_str = Licenses.make_python_safe(license_raw)
406
-
407
- if license_str is not None and hasattr(all_licenses, license_str):
408
- license_obj = getattr(all_licenses, license_str)
409
- return license_obj.licenseText
410
-
411
- return ""
459
+ data = self.sdk.licensemetadata.post([license_raw], {'includetext': 'true'})
460
+ license_str = data.data[0].license if data and len(data) == 1 else ""
461
+ return license_str
412
462
 
413
463
  def get_repo_info(self, repo_slug: str, default_branch: str = "socket-default-branch") -> RepositoryInfo:
414
464
  """
@@ -483,7 +533,7 @@ class Core:
483
533
  pkg.url += f"/{pkg.name}/overview/{pkg.version}"
484
534
  return pkg
485
535
 
486
- def get_added_and_removed_packages(self, head_full_scan_id: str, new_full_scan: FullScan) -> Tuple[Dict[str, Package], Dict[str, Package]]:
536
+ def get_added_and_removed_packages(self, head_full_scan_id: str, new_full_scan_id: str) -> Tuple[Dict[str, Package], Dict[str, Package]]:
487
537
  """
488
538
  Get packages that were added and removed between scans.
489
539
 
@@ -494,14 +544,11 @@ class Core:
494
544
  Returns:
495
545
  Tuple of (added_packages, removed_packages) dictionaries
496
546
  """
497
- if head_full_scan_id is None:
498
- log.info(f"No head scan found. New scan ID: {new_full_scan.id}")
499
- return new_full_scan.packages, {}
500
547
 
501
- log.info(f"Comparing scans - Head scan ID: {head_full_scan_id}, New scan ID: {new_full_scan.id}")
548
+ log.info(f"Comparing scans - Head scan ID: {head_full_scan_id}, New scan ID: {new_full_scan_id}")
502
549
  diff_start = time.time()
503
550
  try:
504
- diff_report = self.sdk.fullscans.stream_diff(self.config.org_slug, head_full_scan_id, new_full_scan.id, use_types=True).data
551
+ diff_report = self.sdk.fullscans.stream_diff(self.config.org_slug, head_full_scan_id, new_full_scan_id, use_types=True).data
505
552
  except APIFailure as e:
506
553
  log.error(f"API Error: {e}")
507
554
  sys.exit(1)
@@ -570,22 +617,27 @@ class Core:
570
617
  # Find manifest files
571
618
  files = self.find_files(path)
572
619
  files_for_sending = self.load_files_for_sending(files, path)
573
- has_head_scan = False
574
620
  if not files:
575
621
  return Diff(id="no_diff_id")
576
622
 
577
623
  try:
578
624
  # Get head scan ID
579
625
  head_full_scan_id = self.get_head_scan_for_repo(params.repo)
580
- if head_full_scan_id is not None:
581
- has_head_scan = True
582
626
  except APIResourceNotFound:
583
627
  head_full_scan_id = None
584
628
 
629
+ if head_full_scan_id is None:
630
+ tmp_params = params
631
+ tmp_params.tmp = True
632
+ tmp_params.set_as_pending_head = False
633
+ tmp_params.make_default_branch = False
634
+ head_full_scan = self.create_full_scan(Core.empty_head_scan_file(), params)
635
+ head_full_scan_id = head_full_scan.id
636
+
585
637
  # Create new scan
586
638
  try:
587
639
  new_scan_start = time.time()
588
- new_full_scan = self.create_full_scan(files_for_sending, params, has_head_scan)
640
+ new_full_scan = self.create_full_scan(files_for_sending, params)
589
641
  new_full_scan.sbom_artifacts = self.get_sbom_data(new_full_scan.id)
590
642
  new_scan_end = time.time()
591
643
  log.info(f"Total time to create new full scan: {new_scan_end - new_scan_start:.2f}")
@@ -598,7 +650,10 @@ class Core:
598
650
  log.error(f"Stack trace:\n{traceback.format_exc()}")
599
651
  raise
600
652
 
601
- added_packages, removed_packages = self.get_added_and_removed_packages(head_full_scan_id, new_full_scan)
653
+ scans_ready = self.check_full_scans_status(head_full_scan_id, new_full_scan.id)
654
+ if scans_ready is False:
655
+ log.error(f"Full scans did not complete within {self.config.timeout} seconds")
656
+ added_packages, removed_packages = self.get_added_and_removed_packages(head_full_scan_id, new_full_scan.id)
602
657
 
603
658
  diff = self.create_diff_report(added_packages, removed_packages)
604
659
 
@@ -1,10 +1,10 @@
1
1
  from dataclasses import dataclass, field
2
2
  from typing import Dict, Optional
3
3
  from urllib.parse import urlparse
4
- from typing import Set
4
+ from typing import Set, List
5
5
  import os
6
6
 
7
- from socketsecurity.core.issues import AllIssues
7
+ from socketdev.core.issues import AllIssues
8
8
  from socketsecurity import __version__
9
9
 
10
10
 
@@ -29,6 +29,7 @@ class SocketConfig:
29
29
  repo_visibility: Optional[str] = 'private'
30
30
  all_issues: Optional['AllIssues'] = None
31
31
  excluded_dirs: Set[str] = field(default_factory=lambda: default_exclude_dirs)
32
+ excluded_ecosystems: List[str] = field(default_factory=lambda: [])
32
33
  version: str = __version__
33
34
 
34
35
  def __post_init__(self):
@@ -47,7 +48,6 @@ class SocketConfig:
47
48
 
48
49
  # Initialize AllIssues if None
49
50
  if self.all_issues is None:
50
- from socketsecurity.core.issues import AllIssues
51
51
  self.all_issues = AllIssues()
52
52
 
53
53
  @staticmethod
@@ -150,6 +150,8 @@ def main_code():
150
150
  org_slug = core.config.org_slug
151
151
  if config.repo_is_public:
152
152
  core.config.repo_visibility = "public"
153
+ if config.excluded_ecosystems and len(config.excluded_ecosystems) > 0:
154
+ core.config.excluded_ecosystems = config.excluded_ecosystems
153
155
  integration_type = config.integration_type
154
156
  integration_org_slug = config.integration_org_slug or org_slug
155
157
  try: