socketsecurity 2.0.56__tar.gz → 2.1.2__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.56 → socketsecurity-2.1.2}/PKG-INFO +8 -8
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/README.md +6 -6
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/pyproject.toml +2 -6
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/__init__.py +1 -1
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/core/__init__.py +88 -29
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/core/socket_config.py +1 -2
- socketsecurity-2.0.56/socketsecurity/core/issues.py +0 -2101
- socketsecurity-2.0.56/socketsecurity/core/licenses.py +0 -21574
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/.github/CODEOWNERS +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/.github/PULL_REQUEST_TEMPLATE/bug-fix.md +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/.github/PULL_REQUEST_TEMPLATE/feature.md +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/.github/PULL_REQUEST_TEMPLATE/improvement.md +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/.github/workflows/docker-stable.yml +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/.github/workflows/pr-preview.yml +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/.github/workflows/release.yml +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/.github/workflows/version-check.yml +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/.gitignore +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/.hooks/sync_version.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/.pre-commit-config.yaml +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/.python-version +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/Dockerfile +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/LICENSE +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/Makefile +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/Pipfile.lock +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/docs/README.md +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/pytest.ini +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/requirements-dev.lock +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/requirements.lock +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/scripts/build_container.sh +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/scripts/deploy-test-docker.sh +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/scripts/deploy-test-pypi.sh +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/scripts/run.sh +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/config.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/core/classes.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/core/cli_client.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/core/exceptions.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/core/git_interface.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/core/logging.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/core/messages.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/core/scm/__init__.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/core/scm/base.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/core/scm/client.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/core/scm/github.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/core/scm/gitlab.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/core/scm_comments.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/core/utils.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/output.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/plugins/__init__.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/plugins/base.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/plugins/jira.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/plugins/manager.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/plugins/slack.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/plugins/teams.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/plugins/webhook.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/socketsecurity/socketcli.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/__init__.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/core/conftest.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/core/create_diff_input.json +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/core/test_diff_generation.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/core/test_package_and_alerts.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/core/test_sdk_methods.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/core/test_supporting_methods.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/data/fullscans/create_response.json +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/data/fullscans/diff/stream_diff.json +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/data/fullscans/diff/stream_diff_full.json +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/data/fullscans/head_scan/metadata.json +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/data/fullscans/head_scan/stream_scan.json +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/data/fullscans/head_scan/stream_scan_full.json +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/data/fullscans/new_scan/metadata.json +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/data/fullscans/new_scan/stream_scan.json +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/data/repos/repo_info_error.json +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/data/repos/repo_info_no_head.json +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/data/repos/repo_info_success.json +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/data/settings/security-policy.json +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/unit/__init__.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/unit/test_cli_config.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/unit/test_client.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/unit/test_config.py +0 -0
- {socketsecurity-2.0.56 → socketsecurity-2.1.2}/tests/unit/test_output.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: socketsecurity
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.2
|
|
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'
|
|
@@ -96,12 +96,12 @@ If you don't want to provide the Socket API Token every time then you can use th
|
|
|
96
96
|
| --commit-sha | False | "" | Commit SHA |
|
|
97
97
|
|
|
98
98
|
#### Path and File
|
|
99
|
-
| Parameter
|
|
100
|
-
|
|
101
|
-
| --target-path
|
|
102
|
-
| --sbom-file
|
|
103
|
-
| --files
|
|
104
|
-
| --
|
|
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
|
+
| --excluded-ecosystems | False | [] | List of ecosystems to exclude from analysis (JSON array string). You can get supported files from the [Supported Files API](https://docs.socket.dev/reference/getsupportedfiles) |
|
|
105
105
|
|
|
106
106
|
#### Branch and Scan Configuration
|
|
107
107
|
| Parameter | Required | Default | Description |
|
|
@@ -40,12 +40,12 @@ If you don't want to provide the Socket API Token every time then you can use th
|
|
|
40
40
|
| --commit-sha | False | "" | Commit SHA |
|
|
41
41
|
|
|
42
42
|
#### Path and File
|
|
43
|
-
| Parameter
|
|
44
|
-
|
|
45
|
-
| --target-path
|
|
46
|
-
| --sbom-file
|
|
47
|
-
| --files
|
|
48
|
-
| --
|
|
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
|
+
| --excluded-ecosystems | False | [] | List of ecosystems to exclude from analysis (JSON array string). You can get supported files from the [Supported Files API](https://docs.socket.dev/reference/getsupportedfiles) |
|
|
49
49
|
|
|
50
50
|
#### Branch and Scan Configuration
|
|
51
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.
|
|
9
|
+
version = "2.1.2"
|
|
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.
|
|
2
|
+
__version__ = '2.1.2'
|
|
@@ -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
|
|
@@ -13,7 +15,7 @@ from socketdev.fullscans import FullScanParams, SocketArtifact
|
|
|
13
15
|
from socketdev.org import Organization
|
|
14
16
|
from socketdev.repos import RepositoryInfo
|
|
15
17
|
from socketdev.settings import SecurityPolicyRule
|
|
16
|
-
|
|
18
|
+
import copy
|
|
17
19
|
from socketsecurity import __version__
|
|
18
20
|
from socketsecurity.core.classes import (
|
|
19
21
|
Alert,
|
|
@@ -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
|
|
@@ -186,6 +187,7 @@ class Core:
|
|
|
186
187
|
for ecosystem in patterns:
|
|
187
188
|
if ecosystem in self.config.excluded_ecosystems:
|
|
188
189
|
continue
|
|
190
|
+
log.info(f'Scanning ecosystem: {ecosystem}')
|
|
189
191
|
ecosystem_patterns = patterns[ecosystem]
|
|
190
192
|
for file_name in ecosystem_patterns:
|
|
191
193
|
original_pattern = ecosystem_patterns[file_name]["pattern"]
|
|
@@ -208,7 +210,7 @@ class Core:
|
|
|
208
210
|
glob_end = time.time()
|
|
209
211
|
log.debug(f"Globbing took {glob_end - glob_start:.4f} seconds")
|
|
210
212
|
|
|
211
|
-
log.
|
|
213
|
+
log.info(f"Total files found: {len(files)}")
|
|
212
214
|
return sorted(files)
|
|
213
215
|
|
|
214
216
|
def get_supported_patterns(self) -> Dict:
|
|
@@ -278,6 +280,14 @@ class Core:
|
|
|
278
280
|
"""
|
|
279
281
|
return ''.join(f'[{char.lower()}{char.upper()}]' if char.isalpha() else char for char in input_string)
|
|
280
282
|
|
|
283
|
+
@staticmethod
|
|
284
|
+
def empty_head_scan_file() -> list[tuple[str, tuple[str, Union[BinaryIO, BytesIO]]]]:
|
|
285
|
+
# Create an empty file for when no head full scan so that the diff endpoint can always be used
|
|
286
|
+
empty_file_obj = io.BytesIO(b"")
|
|
287
|
+
empty_filename = "initial_head_scan"
|
|
288
|
+
empty_full_scan_file = [(empty_filename, (empty_filename, empty_file_obj))]
|
|
289
|
+
return empty_full_scan_file
|
|
290
|
+
|
|
281
291
|
@staticmethod
|
|
282
292
|
def load_files_for_sending(files: List[str], workspace: str) -> List[Tuple[str, Tuple[str, BinaryIO]]]:
|
|
283
293
|
"""
|
|
@@ -311,7 +321,7 @@ class Core:
|
|
|
311
321
|
|
|
312
322
|
return send_files
|
|
313
323
|
|
|
314
|
-
def create_full_scan(self, files:
|
|
324
|
+
def create_full_scan(self, files: list[tuple[str, tuple[str, BytesIO]]], params: FullScanParams) -> FullScan:
|
|
315
325
|
"""
|
|
316
326
|
Creates a new full scan via the Socket API.
|
|
317
327
|
|
|
@@ -322,7 +332,7 @@ class Core:
|
|
|
322
332
|
Returns:
|
|
323
333
|
FullScan object with scan results
|
|
324
334
|
"""
|
|
325
|
-
log.
|
|
335
|
+
log.info("Creating new full scan")
|
|
326
336
|
create_full_start = time.time()
|
|
327
337
|
|
|
328
338
|
res = self.sdk.fullscans.post(files, params, use_types=True)
|
|
@@ -331,16 +341,60 @@ class Core:
|
|
|
331
341
|
raise Exception(f"Error creating full scan: {res.message}, status: {res.status}")
|
|
332
342
|
|
|
333
343
|
full_scan = FullScan(**asdict(res.data))
|
|
334
|
-
if not has_head_scan:
|
|
335
|
-
full_scan.sbom_artifacts = self.get_sbom_data(full_scan.id)
|
|
336
|
-
full_scan.packages = self.create_packages_dict(full_scan.sbom_artifacts)
|
|
337
|
-
|
|
338
344
|
create_full_end = time.time()
|
|
339
345
|
total_time = create_full_end - create_full_start
|
|
340
346
|
log.debug(f"New Full Scan created in {total_time:.2f} seconds")
|
|
341
347
|
|
|
342
348
|
return full_scan
|
|
343
349
|
|
|
350
|
+
def check_full_scans_status(self, head_full_scan_id: str, new_full_scan_id: str) -> bool:
|
|
351
|
+
is_ready = False
|
|
352
|
+
current_timeout = self.config.timeout
|
|
353
|
+
self.sdk.set_timeout(0.5)
|
|
354
|
+
try:
|
|
355
|
+
self.sdk.fullscans.stream(self.config.org_slug, head_full_scan_id)
|
|
356
|
+
except Exception:
|
|
357
|
+
log.debug(f"Queued up full scan for processing ({head_full_scan_id})")
|
|
358
|
+
|
|
359
|
+
try:
|
|
360
|
+
self.sdk.fullscans.stream(self.config.org_slug, new_full_scan_id)
|
|
361
|
+
except Exception:
|
|
362
|
+
log.debug(f"Queued up full scan for processing ({new_full_scan_id})")
|
|
363
|
+
self.sdk.set_timeout(current_timeout)
|
|
364
|
+
start_check = time.time()
|
|
365
|
+
head_is_ready = False
|
|
366
|
+
new_is_ready = False
|
|
367
|
+
while not is_ready:
|
|
368
|
+
head_full_scan_metadata = self.sdk.fullscans.metadata(self.config.org_slug, head_full_scan_id)
|
|
369
|
+
if head_full_scan_metadata:
|
|
370
|
+
head_state = head_full_scan_metadata.get("scan_state")
|
|
371
|
+
else:
|
|
372
|
+
head_state = None
|
|
373
|
+
new_full_scan_metadata = self.sdk.fullscans.metadata(self.config.org_slug, new_full_scan_id)
|
|
374
|
+
if new_full_scan_metadata:
|
|
375
|
+
new_state = new_full_scan_metadata.get("scan_state")
|
|
376
|
+
else:
|
|
377
|
+
new_state = None
|
|
378
|
+
if head_state and head_state == "resolve":
|
|
379
|
+
head_is_ready = True
|
|
380
|
+
if new_state and new_state == "resolve":
|
|
381
|
+
new_is_ready = True
|
|
382
|
+
if head_is_ready and new_is_ready:
|
|
383
|
+
is_ready = True
|
|
384
|
+
current_time = time.time()
|
|
385
|
+
if current_time - start_check >= self.config.timeout:
|
|
386
|
+
log.debug(
|
|
387
|
+
f"Timeout reached while waiting for full scans to be ready "
|
|
388
|
+
f"({head_full_scan_id}, {new_full_scan_id})"
|
|
389
|
+
)
|
|
390
|
+
break
|
|
391
|
+
total_time = time.time() - start_check
|
|
392
|
+
if is_ready:
|
|
393
|
+
log.info(f"Full scans are ready in {total_time:.2f} seconds")
|
|
394
|
+
else:
|
|
395
|
+
log.warning(f"Full scans are not ready yet ({head_full_scan_id}, {new_full_scan_id})")
|
|
396
|
+
return is_ready
|
|
397
|
+
|
|
344
398
|
def get_full_scan(self, full_scan_id: str) -> FullScan:
|
|
345
399
|
"""
|
|
346
400
|
Get a FullScan object for an existing full scan including sbom_artifacts and packages.
|
|
@@ -403,14 +457,9 @@ class Core:
|
|
|
403
457
|
return ""
|
|
404
458
|
|
|
405
459
|
license_raw = package.license
|
|
406
|
-
|
|
407
|
-
license_str =
|
|
408
|
-
|
|
409
|
-
if license_str is not None and hasattr(all_licenses, license_str):
|
|
410
|
-
license_obj = getattr(all_licenses, license_str)
|
|
411
|
-
return license_obj.licenseText
|
|
412
|
-
|
|
413
|
-
return ""
|
|
460
|
+
data = self.sdk.licensemetadata.post([license_raw], {'includetext': 'true'})
|
|
461
|
+
license_str = data.data[0].license if data and len(data) == 1 else ""
|
|
462
|
+
return license_str
|
|
414
463
|
|
|
415
464
|
def get_repo_info(self, repo_slug: str, default_branch: str = "socket-default-branch") -> RepositoryInfo:
|
|
416
465
|
"""
|
|
@@ -485,7 +534,7 @@ class Core:
|
|
|
485
534
|
pkg.url += f"/{pkg.name}/overview/{pkg.version}"
|
|
486
535
|
return pkg
|
|
487
536
|
|
|
488
|
-
def get_added_and_removed_packages(self, head_full_scan_id: str,
|
|
537
|
+
def get_added_and_removed_packages(self, head_full_scan_id: str, new_full_scan_id: str) -> Tuple[Dict[str, Package], Dict[str, Package]]:
|
|
489
538
|
"""
|
|
490
539
|
Get packages that were added and removed between scans.
|
|
491
540
|
|
|
@@ -496,14 +545,11 @@ class Core:
|
|
|
496
545
|
Returns:
|
|
497
546
|
Tuple of (added_packages, removed_packages) dictionaries
|
|
498
547
|
"""
|
|
499
|
-
if head_full_scan_id is None:
|
|
500
|
-
log.info(f"No head scan found. New scan ID: {new_full_scan.id}")
|
|
501
|
-
return new_full_scan.packages, {}
|
|
502
548
|
|
|
503
|
-
log.info(f"Comparing scans - Head scan ID: {head_full_scan_id}, New scan ID: {
|
|
549
|
+
log.info(f"Comparing scans - Head scan ID: {head_full_scan_id}, New scan ID: {new_full_scan_id}")
|
|
504
550
|
diff_start = time.time()
|
|
505
551
|
try:
|
|
506
|
-
diff_report = self.sdk.fullscans.stream_diff(self.config.org_slug, head_full_scan_id,
|
|
552
|
+
diff_report = self.sdk.fullscans.stream_diff(self.config.org_slug, head_full_scan_id, new_full_scan_id, use_types=True).data
|
|
507
553
|
except APIFailure as e:
|
|
508
554
|
log.error(f"API Error: {e}")
|
|
509
555
|
sys.exit(1)
|
|
@@ -572,22 +618,30 @@ class Core:
|
|
|
572
618
|
# Find manifest files
|
|
573
619
|
files = self.find_files(path)
|
|
574
620
|
files_for_sending = self.load_files_for_sending(files, path)
|
|
575
|
-
has_head_scan = False
|
|
576
621
|
if not files:
|
|
577
622
|
return Diff(id="no_diff_id")
|
|
578
623
|
|
|
579
624
|
try:
|
|
580
625
|
# Get head scan ID
|
|
581
626
|
head_full_scan_id = self.get_head_scan_for_repo(params.repo)
|
|
582
|
-
if head_full_scan_id is not None:
|
|
583
|
-
has_head_scan = True
|
|
584
627
|
except APIResourceNotFound:
|
|
585
628
|
head_full_scan_id = None
|
|
586
629
|
|
|
630
|
+
if head_full_scan_id is None:
|
|
631
|
+
new_params = copy.deepcopy(params.__dict__)
|
|
632
|
+
new_params.pop('include_license_details')
|
|
633
|
+
tmp_params = FullScanParams(**new_params)
|
|
634
|
+
tmp_params.include_license_details = params.include_license_details
|
|
635
|
+
tmp_params.tmp = True
|
|
636
|
+
tmp_params.set_as_pending_head = False
|
|
637
|
+
tmp_params.make_default_branch = False
|
|
638
|
+
head_full_scan = self.create_full_scan(Core.empty_head_scan_file(), tmp_params)
|
|
639
|
+
head_full_scan_id = head_full_scan.id
|
|
640
|
+
|
|
587
641
|
# Create new scan
|
|
588
642
|
try:
|
|
589
643
|
new_scan_start = time.time()
|
|
590
|
-
new_full_scan = self.create_full_scan(files_for_sending, params
|
|
644
|
+
new_full_scan = self.create_full_scan(files_for_sending, params)
|
|
591
645
|
new_full_scan.sbom_artifacts = self.get_sbom_data(new_full_scan.id)
|
|
592
646
|
new_scan_end = time.time()
|
|
593
647
|
log.info(f"Total time to create new full scan: {new_scan_end - new_scan_start:.2f}")
|
|
@@ -600,7 +654,10 @@ class Core:
|
|
|
600
654
|
log.error(f"Stack trace:\n{traceback.format_exc()}")
|
|
601
655
|
raise
|
|
602
656
|
|
|
603
|
-
|
|
657
|
+
scans_ready = self.check_full_scans_status(head_full_scan_id, new_full_scan.id)
|
|
658
|
+
if scans_ready is False:
|
|
659
|
+
log.error(f"Full scans did not complete within {self.config.timeout} seconds")
|
|
660
|
+
added_packages, removed_packages = self.get_added_and_removed_packages(head_full_scan_id, new_full_scan.id)
|
|
604
661
|
|
|
605
662
|
diff = self.create_diff_report(added_packages, removed_packages)
|
|
606
663
|
|
|
@@ -742,6 +799,8 @@ class Core:
|
|
|
742
799
|
introduced_by = []
|
|
743
800
|
if package.direct:
|
|
744
801
|
manifests = ""
|
|
802
|
+
if not hasattr(package, "manifestFiles"):
|
|
803
|
+
return introduced_by
|
|
745
804
|
for manifest_data in package.manifestFiles:
|
|
746
805
|
manifest_file = manifest_data.get("file")
|
|
747
806
|
manifests += f"{manifest_file};"
|
|
@@ -4,7 +4,7 @@ from urllib.parse import urlparse
|
|
|
4
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
|
|
|
@@ -48,7 +48,6 @@ class SocketConfig:
|
|
|
48
48
|
|
|
49
49
|
# Initialize AllIssues if None
|
|
50
50
|
if self.all_issues is None:
|
|
51
|
-
from socketsecurity.core.issues import AllIssues
|
|
52
51
|
self.all_issues = AllIssues()
|
|
53
52
|
|
|
54
53
|
@staticmethod
|