socketsecurity 2.0.6__tar.gz → 2.0.7__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.6/socketsecurity.egg-info → socketsecurity-2.0.7}/PKG-INFO +4 -2
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/README.md +2 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/pyproject.toml +2 -2
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/__init__.py +1 -1
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/config.py +8 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/__init__.py +90 -58
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/classes.py +7 -1
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/scm/github.py +3 -1
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/utils.py +23 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/socketcli.py +9 -4
- {socketsecurity-2.0.6 → socketsecurity-2.0.7/socketsecurity.egg-info}/PKG-INFO +4 -2
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity.egg-info/requires.txt +1 -1
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/LICENSE +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/setup.cfg +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/cli_client.py +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/exceptions.py +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/git_interface.py +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/issues.py +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/licenses.py +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/logging.py +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/messages.py +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/scm/__init__.py +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/scm/base.py +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/scm/client.py +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/scm/gitlab.py +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/scm_comments.py +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/core/socket_config.py +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity/output.py +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity.egg-info/SOURCES.txt +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity.egg-info/dependency_links.txt +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/socketsecurity.egg-info/entry_points.txt +0 -0
- {socketsecurity-2.0.6 → socketsecurity-2.0.7}/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.
|
|
3
|
+
Version: 2.0.7
|
|
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.
|
|
22
|
+
Requires-Dist: socket-sdk-python>=2.0.7
|
|
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"
|
|
@@ -42,6 +42,7 @@ socketcli [-h] [--api-token API_TOKEN] [--repo REPO] [--integration {api,github,
|
|
|
42
42
|
[--target-path TARGET_PATH] [--sbom-file SBOM_FILE] [--files FILES] [--default-branch] [--pending-head]
|
|
43
43
|
[--generate-license] [--enable-debug] [--enable-json] [--enable-sarif] [--disable-overview] [--disable-security-issue]
|
|
44
44
|
[--allow-unverified] [--ignore-commit-files] [--disable-blocking] [--scm SCM] [--timeout TIMEOUT]
|
|
45
|
+
[--exclude-license-details]
|
|
45
46
|
````
|
|
46
47
|
|
|
47
48
|
If you don't want to provide the Socket API Token every time then you can use the environment variable `SOCKET_SECURITY_API_KEY`
|
|
@@ -90,6 +91,7 @@ If you don't want to provide the Socket API Token every time then you can use th
|
|
|
90
91
|
| --enable-json | False | False | Output in JSON format |
|
|
91
92
|
| --enable-sarif | False | False | Enable SARIF output of results instead of table or JSON format|
|
|
92
93
|
| --disable-overview | False | False | Disable overview output |
|
|
94
|
+
| --exclude-license-details | False | False | Exclude license details from the diff report (boosts performance for large repos) |
|
|
93
95
|
|
|
94
96
|
#### Security Configuration
|
|
95
97
|
| Parameter | Required | Default | Description |
|
|
@@ -10,6 +10,7 @@ socketcli [-h] [--api-token API_TOKEN] [--repo REPO] [--integration {api,github,
|
|
|
10
10
|
[--target-path TARGET_PATH] [--sbom-file SBOM_FILE] [--files FILES] [--default-branch] [--pending-head]
|
|
11
11
|
[--generate-license] [--enable-debug] [--enable-json] [--enable-sarif] [--disable-overview] [--disable-security-issue]
|
|
12
12
|
[--allow-unverified] [--ignore-commit-files] [--disable-blocking] [--scm SCM] [--timeout TIMEOUT]
|
|
13
|
+
[--exclude-license-details]
|
|
13
14
|
````
|
|
14
15
|
|
|
15
16
|
If you don't want to provide the Socket API Token every time then you can use the environment variable `SOCKET_SECURITY_API_KEY`
|
|
@@ -58,6 +59,7 @@ If you don't want to provide the Socket API Token every time then you can use th
|
|
|
58
59
|
| --enable-json | False | False | Output in JSON format |
|
|
59
60
|
| --enable-sarif | False | False | Enable SARIF output of results instead of table or JSON format|
|
|
60
61
|
| --disable-overview | False | False | Disable overview output |
|
|
62
|
+
| --exclude-license-details | False | False | Exclude license details from the diff report (boosts performance for large repos) |
|
|
61
63
|
|
|
62
64
|
#### Security Configuration
|
|
63
65
|
| Parameter | Required | Default | Description |
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
__author__ = 'socket.dev'
|
|
2
|
-
__version__ = '2.0.
|
|
2
|
+
__version__ = '2.0.7'
|
|
@@ -33,6 +33,7 @@ class CliConfig:
|
|
|
33
33
|
integration_org_slug: Optional[str] = None
|
|
34
34
|
pending_head: bool = False
|
|
35
35
|
timeout: Optional[int] = 1200
|
|
36
|
+
exclude_license_details: bool = False
|
|
36
37
|
@classmethod
|
|
37
38
|
def from_args(cls, args_list: Optional[List[str]] = None) -> 'CliConfig':
|
|
38
39
|
parser = create_argument_parser()
|
|
@@ -71,6 +72,7 @@ class CliConfig:
|
|
|
71
72
|
'integration_type': args.integration,
|
|
72
73
|
'pending_head': args.pending_head,
|
|
73
74
|
'timeout': args.timeout,
|
|
75
|
+
'exclude_license_details': args.exclude_license_details,
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
if args.owner:
|
|
@@ -283,6 +285,12 @@ def create_argument_parser() -> argparse.ArgumentParser:
|
|
|
283
285
|
action="store_true",
|
|
284
286
|
help=argparse.SUPPRESS
|
|
285
287
|
)
|
|
288
|
+
output_group.add_argument(
|
|
289
|
+
"--exclude-license-details",
|
|
290
|
+
dest="exclude_license_details",
|
|
291
|
+
action="store_true",
|
|
292
|
+
help="Exclude license details from the diff report (boosts performance for large repos)"
|
|
293
|
+
)
|
|
286
294
|
|
|
287
295
|
# Security Configuration
|
|
288
296
|
security_group = parser.add_argument_group('Security Configuration')
|
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
import base64
|
|
2
|
-
import json
|
|
3
1
|
import logging
|
|
4
2
|
import time
|
|
3
|
+
import sys
|
|
5
4
|
from dataclasses import asdict
|
|
6
5
|
from glob import glob
|
|
7
6
|
from pathlib import PurePath
|
|
8
|
-
from typing import BinaryIO, Dict, List,
|
|
9
|
-
|
|
7
|
+
from typing import BinaryIO, Dict, List, Tuple
|
|
10
8
|
from socketdev import socketdev
|
|
11
9
|
from socketdev.fullscans import (
|
|
12
10
|
FullScanParams,
|
|
13
|
-
SocketArtifact
|
|
14
|
-
DiffArtifact,
|
|
11
|
+
SocketArtifact
|
|
15
12
|
)
|
|
16
13
|
from socketdev.org import Organization
|
|
17
14
|
from socketdev.repos import RepositoryInfo
|
|
@@ -27,8 +24,9 @@ from socketsecurity.core.classes import (
|
|
|
27
24
|
Purl,
|
|
28
25
|
)
|
|
29
26
|
from socketsecurity.core.exceptions import (
|
|
30
|
-
APIResourceNotFound
|
|
27
|
+
APIResourceNotFound
|
|
31
28
|
)
|
|
29
|
+
from socketdev.exceptions import APIFailure
|
|
32
30
|
from socketsecurity.core.licenses import Licenses
|
|
33
31
|
|
|
34
32
|
from .socket_config import SocketConfig
|
|
@@ -148,7 +146,7 @@ class Core:
|
|
|
148
146
|
for file_name in patterns:
|
|
149
147
|
pattern = Core.to_case_insensitive_regex(patterns[file_name]["pattern"])
|
|
150
148
|
file_path = f"{path}/**/{pattern}"
|
|
151
|
-
log.debug(f"Globbing {file_path}")
|
|
149
|
+
#log.debug(f"Globbing {file_path}")
|
|
152
150
|
glob_start = time.time()
|
|
153
151
|
glob_files = glob(file_path, recursive=True)
|
|
154
152
|
for glob_file in glob_files:
|
|
@@ -156,13 +154,16 @@ class Core:
|
|
|
156
154
|
files.add(glob_file)
|
|
157
155
|
glob_end = time.time()
|
|
158
156
|
glob_total_time = glob_end - glob_start
|
|
159
|
-
log.debug(f"Glob for pattern {file_path} took {glob_total_time:.2f} seconds")
|
|
157
|
+
#log.debug(f"Glob for pattern {file_path} took {glob_total_time:.2f} seconds")
|
|
160
158
|
|
|
161
159
|
log.debug("Finished Find Files")
|
|
162
160
|
end_time = time.time()
|
|
163
161
|
total_time = end_time - start_time
|
|
164
|
-
|
|
165
|
-
|
|
162
|
+
files_list = list(files)
|
|
163
|
+
if len(files_list) > 5:
|
|
164
|
+
log.debug(f"{len(files_list)} Files found ({total_time:.2f}s): {', '.join(files_list[:5])}, ...")
|
|
165
|
+
else:
|
|
166
|
+
log.debug(f"{len(files_list)} Files found ({total_time:.2f}s): {', '.join(files_list)}")
|
|
166
167
|
return list(files)
|
|
167
168
|
|
|
168
169
|
@staticmethod
|
|
@@ -216,7 +217,7 @@ class Core:
|
|
|
216
217
|
|
|
217
218
|
return send_files
|
|
218
219
|
|
|
219
|
-
def create_full_scan(self, files: List[str], params: FullScanParams) -> FullScan:
|
|
220
|
+
def create_full_scan(self, files: List[str], params: FullScanParams, has_head_scan: bool = False) -> FullScan:
|
|
220
221
|
"""
|
|
221
222
|
Creates a new full scan via the Socket API.
|
|
222
223
|
|
|
@@ -236,10 +237,10 @@ class Core:
|
|
|
236
237
|
raise Exception(f"Error creating full scan: {res.message}, status: {res.status}")
|
|
237
238
|
|
|
238
239
|
full_scan = FullScan(**asdict(res.data))
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
240
|
+
if not has_head_scan:
|
|
241
|
+
full_scan_artifacts_dict = self.get_sbom_data(full_scan.id)
|
|
242
|
+
full_scan.sbom_artifacts = self.get_sbom_data_list(full_scan_artifacts_dict)
|
|
243
|
+
full_scan.packages = self.create_packages_dict(full_scan.sbom_artifacts)
|
|
243
244
|
|
|
244
245
|
create_full_end = time.time()
|
|
245
246
|
total_time = create_full_end - create_full_start
|
|
@@ -317,12 +318,13 @@ class Core:
|
|
|
317
318
|
|
|
318
319
|
return ""
|
|
319
320
|
|
|
320
|
-
def get_repo_info(self, repo_slug: str) -> RepositoryInfo:
|
|
321
|
+
def get_repo_info(self, repo_slug: str, default_branch: str = "socket-default-branch") -> RepositoryInfo:
|
|
321
322
|
"""
|
|
322
323
|
Gets repository information from the Socket API.
|
|
323
324
|
|
|
324
325
|
Args:
|
|
325
326
|
repo_slug: Repository slug to get info for
|
|
327
|
+
default_branch: Default branch string to use if the repo doesn't exist
|
|
326
328
|
|
|
327
329
|
Returns:
|
|
328
330
|
RepositoryInfo object
|
|
@@ -330,11 +332,23 @@ class Core:
|
|
|
330
332
|
Raises:
|
|
331
333
|
Exception: If API request fails
|
|
332
334
|
"""
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
335
|
+
try:
|
|
336
|
+
response = self.sdk.repos.repo(self.config.org_slug, repo_slug)
|
|
337
|
+
if not response.success:
|
|
338
|
+
log.error(f"Failed to get repository: {response.status}")
|
|
339
|
+
log.error(response.message)
|
|
340
|
+
# raise Exception(f"Failed to get repository info: {response.status}, message: {response.message}")
|
|
341
|
+
except APIFailure:
|
|
342
|
+
log.warning(f"Failed to get repository {repo_slug}, attempting to create it")
|
|
343
|
+
create_response = self.sdk.repos.post(self.config.org_slug, name=repo_slug, default_branch=default_branch)
|
|
344
|
+
if not create_response.success:
|
|
345
|
+
log.error(f"Failed to create repository: {create_response.status}")
|
|
346
|
+
log.error(create_response.message)
|
|
347
|
+
raise Exception(
|
|
348
|
+
f"Failed to create repository: {create_response.status}, message: {create_response.message}"
|
|
349
|
+
)
|
|
350
|
+
else:
|
|
351
|
+
return create_response.data
|
|
338
352
|
return response.data
|
|
339
353
|
|
|
340
354
|
def get_head_scan_for_repo(self, repo_slug: str) -> str:
|
|
@@ -350,24 +364,36 @@ class Core:
|
|
|
350
364
|
repo_info = self.get_repo_info(repo_slug)
|
|
351
365
|
return repo_info.head_full_scan_id if repo_info.head_full_scan_id else None
|
|
352
366
|
|
|
353
|
-
|
|
367
|
+
@staticmethod
|
|
368
|
+
def update_package_values(pkg: Package) -> Package:
|
|
369
|
+
pkg.purl = f"{pkg.name}@{pkg.version}"
|
|
370
|
+
pkg.url = f"https://socket.dev/{pkg.type}/package"
|
|
371
|
+
if pkg.namespace:
|
|
372
|
+
pkg.purl = f"{pkg.namespace}/{pkg.purl}"
|
|
373
|
+
pkg.url += f"/{pkg.namespace}"
|
|
374
|
+
pkg.url += f"/{pkg.name}/overview/{pkg.version}"
|
|
375
|
+
return pkg
|
|
376
|
+
|
|
377
|
+
def get_added_and_removed_packages(self, head_full_scan_id: str, new_full_scan: FullScan) -> Tuple[Dict[str, Package], Dict[str, Package]]:
|
|
354
378
|
"""
|
|
355
379
|
Get packages that were added and removed between scans.
|
|
356
380
|
|
|
357
381
|
Args:
|
|
358
382
|
head_full_scan: Previous scan (may be None if first scan)
|
|
359
|
-
|
|
383
|
+
head_full_scan_id: New scan just created
|
|
360
384
|
|
|
361
385
|
Returns:
|
|
362
386
|
Tuple of (added_packages, removed_packages) dictionaries
|
|
363
387
|
"""
|
|
364
|
-
if
|
|
388
|
+
if head_full_scan_id is None:
|
|
365
389
|
log.info(f"No head scan found. New scan ID: {new_full_scan.id}")
|
|
366
390
|
return new_full_scan.packages, {}
|
|
367
391
|
|
|
368
|
-
log.info(f"Comparing scans - Head scan ID: {
|
|
369
|
-
|
|
370
|
-
|
|
392
|
+
log.info(f"Comparing scans - Head scan ID: {head_full_scan_id}, New scan ID: {new_full_scan.id}")
|
|
393
|
+
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
|
|
395
|
+
diff_end = time.time()
|
|
396
|
+
log.info(f"Diff Report Gathered in {diff_end - diff_start:.2f} seconds")
|
|
371
397
|
log.info(f"Diff report artifact counts:")
|
|
372
398
|
log.info(f"Added: {len(diff_report.artifacts.added)}")
|
|
373
399
|
log.info(f"Removed: {len(diff_report.artifacts.removed)}")
|
|
@@ -384,32 +410,24 @@ class Core:
|
|
|
384
410
|
for artifact in added_artifacts:
|
|
385
411
|
try:
|
|
386
412
|
pkg = Package.from_diff_artifact(asdict(artifact))
|
|
413
|
+
pkg = Core.update_package_values(pkg)
|
|
387
414
|
added_packages[artifact.id] = pkg
|
|
388
415
|
except KeyError:
|
|
389
416
|
log.error(f"KeyError: Could not create package from added artifact {artifact.id}")
|
|
390
417
|
log.error(f"Artifact details - name: {artifact.name}, version: {artifact.version}")
|
|
391
|
-
|
|
392
|
-
if matches:
|
|
393
|
-
log.error(f"Found {len(matches)} packages with matching name/version:")
|
|
394
|
-
for m in matches:
|
|
395
|
-
log.error(f" ID: {m.id}, name: {m.name}, version: {m.version}")
|
|
396
|
-
else:
|
|
397
|
-
log.error("No matching packages found in new_full_scan")
|
|
418
|
+
log.error("No matching packages found in new_full_scan")
|
|
398
419
|
|
|
399
420
|
for artifact in removed_artifacts:
|
|
400
421
|
try:
|
|
401
422
|
pkg = Package.from_diff_artifact(asdict(artifact))
|
|
423
|
+
pkg = Core.update_package_values(pkg)
|
|
424
|
+
if pkg.namespace:
|
|
425
|
+
pkg.purl += f"{pkg.namespace}/{pkg.purl}"
|
|
402
426
|
removed_packages[artifact.id] = pkg
|
|
403
427
|
except KeyError:
|
|
404
428
|
log.error(f"KeyError: Could not create package from removed artifact {artifact.id}")
|
|
405
429
|
log.error(f"Artifact details - name: {artifact.name}, version: {artifact.version}")
|
|
406
|
-
|
|
407
|
-
if matches:
|
|
408
|
-
log.error(f"Found {len(matches)} packages with matching name/version:")
|
|
409
|
-
for m in matches:
|
|
410
|
-
log.error(f" ID: {m.id}, name: {m.name}, version: {m.version}")
|
|
411
|
-
else:
|
|
412
|
-
log.error("No matching packages found in head_full_scan")
|
|
430
|
+
log.error("No matching packages found in head_full_scan")
|
|
413
431
|
|
|
414
432
|
return added_packages, removed_packages
|
|
415
433
|
|
|
@@ -435,36 +453,49 @@ class Core:
|
|
|
435
453
|
files = self.find_files(path)
|
|
436
454
|
files_for_sending = self.load_files_for_sending(files, path)
|
|
437
455
|
|
|
438
|
-
log.debug(f"files: {files} found at path {path}")
|
|
439
456
|
if not files:
|
|
440
457
|
return Diff(id="no_diff_id")
|
|
441
458
|
|
|
442
|
-
head_full_scan_id = None
|
|
443
|
-
|
|
444
459
|
try:
|
|
445
460
|
# Get head scan ID
|
|
446
461
|
head_full_scan_id = self.get_head_scan_for_repo(params.repo)
|
|
462
|
+
has_head_scan = True
|
|
447
463
|
except APIResourceNotFound:
|
|
448
464
|
head_full_scan_id = None
|
|
465
|
+
has_head_scan = False
|
|
449
466
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
467
|
+
# Create new scan
|
|
468
|
+
try:
|
|
469
|
+
new_scan_start = time.time()
|
|
470
|
+
new_full_scan = self.create_full_scan(files_for_sending, params, has_head_scan)
|
|
471
|
+
new_scan_end = time.time()
|
|
472
|
+
log.info(f"Total time to create new full scan: {new_scan_end - new_scan_start:.2f}")
|
|
473
|
+
except APIFailure as e:
|
|
474
|
+
log.error(f"API Error: {e}")
|
|
475
|
+
sys.exit(1)
|
|
476
|
+
except Exception as e:
|
|
477
|
+
log.error(f"Unexpected error while creating new scan: {e}")
|
|
478
|
+
sys.exit(1)
|
|
460
479
|
|
|
461
|
-
|
|
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)
|
|
462
488
|
|
|
463
489
|
diff = self.create_diff_report(added_packages, removed_packages)
|
|
464
490
|
|
|
465
491
|
base_socket = "https://socket.dev/dashboard/org"
|
|
466
492
|
diff.id = new_full_scan.id
|
|
467
|
-
|
|
493
|
+
|
|
494
|
+
report_url = f"{base_socket}/{self.config.org_slug}/sbom/{diff.id}"
|
|
495
|
+
if not params.include_license_details:
|
|
496
|
+
report_url += "?include_license_details=false"
|
|
497
|
+
diff.report_url = report_url
|
|
498
|
+
|
|
468
499
|
if head_full_scan_id is not None:
|
|
469
500
|
diff.diff_url = f"{base_socket}/{self.config.org_slug}/diff/{diff.id}/{head_full_scan_id}"
|
|
470
501
|
else:
|
|
@@ -609,7 +640,8 @@ class Core:
|
|
|
609
640
|
source = (top_purl, manifests)
|
|
610
641
|
introduced_by.append(source)
|
|
611
642
|
else:
|
|
612
|
-
|
|
643
|
+
pass
|
|
644
|
+
# log.debug(f"Unable to get top level package info for {top_id}")
|
|
613
645
|
return introduced_by
|
|
614
646
|
|
|
615
647
|
@staticmethod
|
|
@@ -115,6 +115,7 @@ class Package(SocketArtifactLink):
|
|
|
115
115
|
author: List[str] = field(default_factory=list)
|
|
116
116
|
size: Optional[int] = None
|
|
117
117
|
license: Optional[str] = None
|
|
118
|
+
namespace: Optional[str] = None
|
|
118
119
|
|
|
119
120
|
# Package-specific fields
|
|
120
121
|
license_text: str = ""
|
|
@@ -122,6 +123,10 @@ class Package(SocketArtifactLink):
|
|
|
122
123
|
transitives: int = 0
|
|
123
124
|
url: str = ""
|
|
124
125
|
|
|
126
|
+
# Artifact-specific fields
|
|
127
|
+
licenseDetails: Optional[list] = None
|
|
128
|
+
|
|
129
|
+
|
|
125
130
|
@classmethod
|
|
126
131
|
def from_socket_artifact(cls, data: dict) -> "Package":
|
|
127
132
|
"""
|
|
@@ -187,7 +192,8 @@ class Package(SocketArtifactLink):
|
|
|
187
192
|
direct=ref.get("direct", False),
|
|
188
193
|
manifestFiles=ref.get("manifestFiles", []),
|
|
189
194
|
dependencies=ref.get("dependencies"),
|
|
190
|
-
artifact=ref.get("artifact")
|
|
195
|
+
artifact=ref.get("artifact"),
|
|
196
|
+
namespace=data.get('namespace', None)
|
|
191
197
|
)
|
|
192
198
|
|
|
193
199
|
class Issue:
|
|
@@ -54,7 +54,9 @@ class GithubConfig:
|
|
|
54
54
|
owner = repository.split('/')[0]
|
|
55
55
|
repository = repository.split('/')[1]
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
default_branch_env = os.getenv('DEFAULT_BRANCH')
|
|
58
|
+
# Consider the variable truthy if it exists and isn't explicitly 'false'
|
|
59
|
+
is_default = default_branch_env is not None and default_branch_env.lower() != 'false'
|
|
58
60
|
return cls(
|
|
59
61
|
sha=os.getenv('GITHUB_SHA', ''),
|
|
60
62
|
api_url=os.getenv('GITHUB_API_URL', ''),
|
|
@@ -81,5 +81,28 @@ socket_globs = {
|
|
|
81
81
|
"pom.xml": {
|
|
82
82
|
"pattern": "pom.xml"
|
|
83
83
|
}
|
|
84
|
+
},
|
|
85
|
+
".net": {
|
|
86
|
+
"proj": {
|
|
87
|
+
"pattern": "*.*proj"
|
|
88
|
+
},
|
|
89
|
+
"props": {
|
|
90
|
+
"pattern": "*.props"
|
|
91
|
+
},
|
|
92
|
+
"targets": {
|
|
93
|
+
"pattern": "*.targets"
|
|
94
|
+
},
|
|
95
|
+
"nuspec": {
|
|
96
|
+
"pattern": "*.nuspec"
|
|
97
|
+
},
|
|
98
|
+
"nugetConfig": {
|
|
99
|
+
"pattern": "nuget.config"
|
|
100
|
+
},
|
|
101
|
+
"packagesConfig": {
|
|
102
|
+
"pattern": "packages.config"
|
|
103
|
+
},
|
|
104
|
+
"packagesLock": {
|
|
105
|
+
"pattern": "packages.lock.json"
|
|
106
|
+
}
|
|
84
107
|
}
|
|
85
108
|
}
|
|
@@ -48,6 +48,13 @@ def main_code():
|
|
|
48
48
|
log.debug(f"config: {config.to_dict()}")
|
|
49
49
|
output_handler = OutputHandler(config)
|
|
50
50
|
|
|
51
|
+
# Validate API token
|
|
52
|
+
if not config.api_token:
|
|
53
|
+
log.info("Socket API Token not found. Please set it using either:\n"
|
|
54
|
+
"1. Command line: --api-token YOUR_TOKEN\n"
|
|
55
|
+
"2. Environment variable: SOCKET_SECURITY_API_KEY")
|
|
56
|
+
sys.exit(3)
|
|
57
|
+
|
|
51
58
|
sdk = socketdev(token=config.api_token)
|
|
52
59
|
log.debug("sdk loaded")
|
|
53
60
|
|
|
@@ -55,10 +62,6 @@ def main_code():
|
|
|
55
62
|
set_debug_mode(True)
|
|
56
63
|
log.debug("Debug logging enabled")
|
|
57
64
|
|
|
58
|
-
# Validate API token
|
|
59
|
-
if not config.api_token:
|
|
60
|
-
log.info("Unable to find Socket API Token")
|
|
61
|
-
sys.exit(3)
|
|
62
65
|
|
|
63
66
|
# Initialize Socket core components
|
|
64
67
|
socket_config = SocketConfig(
|
|
@@ -160,6 +163,8 @@ def main_code():
|
|
|
160
163
|
set_as_pending_head=True
|
|
161
164
|
)
|
|
162
165
|
|
|
166
|
+
params.include_license_details = not config.exclude_license_details
|
|
167
|
+
|
|
163
168
|
# Initialize diff
|
|
164
169
|
diff = Diff()
|
|
165
170
|
diff.id = "NO_DIFF_RAN"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: socketsecurity
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.7
|
|
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.
|
|
22
|
+
Requires-Dist: socket-sdk-python>=2.0.7
|
|
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"
|
|
@@ -42,6 +42,7 @@ socketcli [-h] [--api-token API_TOKEN] [--repo REPO] [--integration {api,github,
|
|
|
42
42
|
[--target-path TARGET_PATH] [--sbom-file SBOM_FILE] [--files FILES] [--default-branch] [--pending-head]
|
|
43
43
|
[--generate-license] [--enable-debug] [--enable-json] [--enable-sarif] [--disable-overview] [--disable-security-issue]
|
|
44
44
|
[--allow-unverified] [--ignore-commit-files] [--disable-blocking] [--scm SCM] [--timeout TIMEOUT]
|
|
45
|
+
[--exclude-license-details]
|
|
45
46
|
````
|
|
46
47
|
|
|
47
48
|
If you don't want to provide the Socket API Token every time then you can use the environment variable `SOCKET_SECURITY_API_KEY`
|
|
@@ -90,6 +91,7 @@ If you don't want to provide the Socket API Token every time then you can use th
|
|
|
90
91
|
| --enable-json | False | False | Output in JSON format |
|
|
91
92
|
| --enable-sarif | False | False | Enable SARIF output of results instead of table or JSON format|
|
|
92
93
|
| --disable-overview | False | False | Disable overview output |
|
|
94
|
+
| --exclude-license-details | False | False | Exclude license details from the diff report (boosts performance for large repos) |
|
|
93
95
|
|
|
94
96
|
#### Security Configuration
|
|
95
97
|
| Parameter | Required | Default | Description |
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|