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.
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/PKG-INFO +16 -14
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/README.md +14 -12
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/pyproject.toml +2 -6
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/__init__.py +1 -1
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/config.py +15 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/__init__.py +81 -26
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/socket_config.py +3 -3
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/socketcli.py +2 -0
- socketsecurity-2.0.55/socketsecurity/core/issues.py +0 -2101
- socketsecurity-2.0.55/socketsecurity/core/licenses.py +0 -21574
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/CODEOWNERS +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/PULL_REQUEST_TEMPLATE/bug-fix.md +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/PULL_REQUEST_TEMPLATE/feature.md +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/PULL_REQUEST_TEMPLATE/improvement.md +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/workflows/docker-stable.yml +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/workflows/pr-preview.yml +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/workflows/release.yml +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.github/workflows/version-check.yml +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.gitignore +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.hooks/sync_version.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.pre-commit-config.yaml +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/.python-version +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/Dockerfile +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/LICENSE +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/Makefile +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/Pipfile.lock +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/docs/README.md +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/pytest.ini +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/requirements-dev.lock +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/requirements.lock +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/scripts/build_container.sh +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/scripts/deploy-test-docker.sh +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/scripts/deploy-test-pypi.sh +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/scripts/run.sh +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/classes.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/cli_client.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/exceptions.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/git_interface.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/logging.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/messages.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/scm/__init__.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/scm/base.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/scm/client.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/scm/github.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/scm/gitlab.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/scm_comments.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/core/utils.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/output.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/plugins/__init__.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/plugins/base.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/plugins/jira.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/plugins/manager.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/plugins/slack.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/plugins/teams.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/socketsecurity/plugins/webhook.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/__init__.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/core/conftest.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/core/create_diff_input.json +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/core/test_diff_generation.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/core/test_package_and_alerts.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/core/test_sdk_methods.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/core/test_supporting_methods.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/create_response.json +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/diff/stream_diff.json +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/diff/stream_diff_full.json +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/head_scan/metadata.json +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/head_scan/stream_scan.json +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/head_scan/stream_scan_full.json +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/new_scan/metadata.json +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/fullscans/new_scan/stream_scan.json +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/repos/repo_info_error.json +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/repos/repo_info_no_head.json +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/repos/repo_info_success.json +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/data/settings/security-policy.json +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/unit/__init__.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/unit/test_cli_config.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/unit/test_client.py +0 -0
- {socketsecurity-2.0.55 → socketsecurity-2.1.0}/tests/unit/test_config.py +0 -0
- {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
|
|
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
|
|
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
|
|
83
|
-
|
|
84
|
-
| --repo
|
|
85
|
-
| --integration
|
|
86
|
-
| --owner
|
|
87
|
-
| --branch
|
|
88
|
-
| --committers
|
|
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
|
|
99
|
-
|
|
100
|
-
| --target-path
|
|
101
|
-
| --sbom-file
|
|
102
|
-
| --files
|
|
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
|
|
27
|
-
|
|
28
|
-
| --repo
|
|
29
|
-
| --integration
|
|
30
|
-
| --owner
|
|
31
|
-
| --branch
|
|
32
|
-
| --committers
|
|
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
|
|
43
|
-
|
|
44
|
-
| --target-path
|
|
45
|
-
| --sbom-file
|
|
46
|
-
| --files
|
|
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
|
|
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.
|
|
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
|
|
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:
|
|
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
|
-
|
|
405
|
-
license_str =
|
|
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,
|
|
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: {
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
|
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:
|