scanoss 1.43.1__tar.gz → 1.45.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.
- {scanoss-1.43.1 → scanoss-1.45.0}/PACKAGE.md +2 -2
- {scanoss-1.43.1/src/scanoss.egg-info → scanoss-1.45.0}/PKG-INFO +3 -3
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/__init__.py +1 -1
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/cli.py +55 -11
- scanoss-1.45.0/src/scanoss/data/build_date.txt +1 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/data/scanoss-settings-schema.json +94 -0
- scanoss-1.45.0/src/scanoss/scan_settings_builder.py +311 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/scanner.py +80 -13
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/scanoss_settings.py +96 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/scanossapi.py +102 -13
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/scanpostprocessor.py +12 -12
- {scanoss-1.43.1 → scanoss-1.45.0/src/scanoss.egg-info}/PKG-INFO +3 -3
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss.egg-info/SOURCES.txt +2 -0
- scanoss-1.45.0/tests/test_scan_settings_builder.py +362 -0
- scanoss-1.43.1/src/scanoss/data/build_date.txt +0 -1
- {scanoss-1.43.1 → scanoss-1.45.0}/LICENSE +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/README.md +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/pyproject.toml +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/setup.cfg +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/protoc_gen_swagger/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/protoc_gen_swagger/options/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/protoc_gen_swagger/options/annotations_pb2.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/protoc_gen_swagger/options/annotations_pb2.pyi +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/protoc_gen_swagger/options/annotations_pb2_grpc.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/protoc_gen_swagger/options/openapiv2_pb2.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/protoc_gen_swagger/options/openapiv2_pb2.pyi +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/protoc_gen_swagger/options/openapiv2_pb2_grpc.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/common/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/common/v2/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/common/v2/scanoss_common_pb2.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/common/v2/scanoss_common_pb2_grpc.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/components/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/components/v2/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/components/v2/scanoss_components_pb2.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/components/v2/scanoss_components_pb2_grpc.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/cryptography/v2/scanoss_cryptography_pb2.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/cryptography/v2/scanoss_cryptography_pb2_grpc.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/dependencies/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/dependencies/v2/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/dependencies/v2/scanoss_dependencies_pb2.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/dependencies/v2/scanoss_dependencies_pb2_grpc.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/geoprovenance/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/geoprovenance/v2/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2_grpc.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/licenses/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/licenses/v2/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/licenses/v2/scanoss_licenses_pb2.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/licenses/v2/scanoss_licenses_pb2_grpc.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/scanning/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/scanning/v2/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/scanning/v2/scanoss_scanning_pb2.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/scanning/v2/scanoss_scanning_pb2_grpc.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/semgrep/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/semgrep/v2/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/semgrep/v2/scanoss_semgrep_pb2.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/semgrep/v2/scanoss_semgrep_pb2_grpc.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/vulnerabilities/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/vulnerabilities/v2/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2_grpc.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/components.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/constants.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/cryptography.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/csvoutput.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/cyclonedx.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/data/osadl-copyleft.json +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/data/spdx-exceptions.json +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/data/spdx-licenses.json +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/delta.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/export/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/export/dependency_track.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/file_filters.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/filecount.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/gitlabqualityreport.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/header_filter.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/policy_check/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/policy_check/dependency_track/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/policy_check/dependency_track/project_violation.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/policy_check/policy_check.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/policy_check/scanoss/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/policy_check/scanoss/copyleft.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/policy_check/scanoss/undeclared_component.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/summary/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/summary/component_summary.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/summary/license_summary.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/summary/match_summary.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/utils/file_utils.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/utils/license_utils.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/utils/markdown_utils.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/inspection/utils/scan_result_processor.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/osadl.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/results.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/scancodedeps.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/scanners/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/scanners/container_scanner.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/scanners/folder_hasher.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/scanners/scanner_config.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/scanners/scanner_hfh.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/scanossbase.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/scanossgrpc.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/scantype.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/services/dependency_track_service.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/spdxlite.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/threadeddependencies.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/threadedscanning.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/utils/__init__.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/utils/abstract_presenter.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/utils/crc64.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/utils/file.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/utils/scanoss_scan_results_utils.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/utils/simhash.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss/winnowing.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss.egg-info/dependency_links.txt +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss.egg-info/entry_points.txt +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss.egg-info/requires.txt +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/src/scanoss.egg-info/top_level.txt +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/tests/test_csv_output.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/tests/test_file_filters.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/tests/test_headers_filter.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/tests/test_osadl.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/tests/test_policy_inspect.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/tests/test_scan_post_processor.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/tests/test_spdxlite.py +0 -0
- {scanoss-1.43.1 → scanoss-1.45.0}/tests/test_winnowing.py +0 -0
|
@@ -117,8 +117,8 @@ if __name__ == "__main__":
|
|
|
117
117
|
```
|
|
118
118
|
|
|
119
119
|
## Scanning URL and API Key
|
|
120
|
-
By Default, scanoss uses the API URL
|
|
121
|
-
This API does not require an API key.
|
|
120
|
+
By Default, scanoss uses the API base URL for SCANOSS OSS KB: https://api.osskb.org.
|
|
121
|
+
The `/scan/direct` endpoint is automatically appended. This API does not require an API key.
|
|
122
122
|
|
|
123
123
|
These values can be changed from the command line using:
|
|
124
124
|
```bash
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scanoss
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.45.0
|
|
4
4
|
Summary: Simple Python library to leverage the SCANOSS APIs
|
|
5
5
|
Home-page: https://scanoss.com
|
|
6
6
|
Author: SCANOSS
|
|
@@ -156,8 +156,8 @@ if __name__ == "__main__":
|
|
|
156
156
|
```
|
|
157
157
|
|
|
158
158
|
## Scanning URL and API Key
|
|
159
|
-
By Default, scanoss uses the API URL
|
|
160
|
-
This API does not require an API key.
|
|
159
|
+
By Default, scanoss uses the API base URL for SCANOSS OSS KB: https://api.osskb.org.
|
|
160
|
+
The `/scan/direct` endpoint is automatically appended. This API does not require an API key.
|
|
161
161
|
|
|
162
162
|
These values can be changed from the command line using:
|
|
163
163
|
```bash
|
|
@@ -190,6 +190,44 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
190
190
|
'--no-wfp-output', action='store_true',
|
|
191
191
|
help='DEPRECATED: Scans no longer generate scanner_output.wfp. Use "fingerprint -o" to create WFP files.'
|
|
192
192
|
)
|
|
193
|
+
p_scan.add_argument(
|
|
194
|
+
'--wfp-output', type=str, metavar='FILE',
|
|
195
|
+
help='Save fingerprints to specified file during scan'
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# Snippet tuning options
|
|
199
|
+
p_scan.add_argument(
|
|
200
|
+
'--min-snippet-hits',
|
|
201
|
+
type=int,
|
|
202
|
+
default=None,
|
|
203
|
+
help='Minimum snippet hits required. A value of 0 defers to server configuration (optional)',
|
|
204
|
+
)
|
|
205
|
+
p_scan.add_argument(
|
|
206
|
+
'--min-snippet-lines',
|
|
207
|
+
type=int,
|
|
208
|
+
default=None,
|
|
209
|
+
help='Minimum snippet lines required. A value of 0 defers to server configuration (optional)',
|
|
210
|
+
)
|
|
211
|
+
p_scan.add_argument(
|
|
212
|
+
'--ranking',
|
|
213
|
+
type=str,
|
|
214
|
+
choices=['unset' ,'true', 'false'],
|
|
215
|
+
default='unset',
|
|
216
|
+
help='Enable or disable ranking (optional - default: server configuration)',
|
|
217
|
+
)
|
|
218
|
+
p_scan.add_argument(
|
|
219
|
+
'--ranking-threshold',
|
|
220
|
+
type=int,
|
|
221
|
+
default=-1,
|
|
222
|
+
help='Ranking threshold value. Valid range: -1 to 10. A value of -1 defers to server configuration (optional)',
|
|
223
|
+
)
|
|
224
|
+
p_scan.add_argument(
|
|
225
|
+
'--honour-file-exts',
|
|
226
|
+
type=str,
|
|
227
|
+
choices=['unset','true', 'false'],
|
|
228
|
+
default='unset',
|
|
229
|
+
help='Honour file extensions during scanning. When not set, defers to server configuration (optional)',
|
|
230
|
+
)
|
|
193
231
|
|
|
194
232
|
# Sub-command: fingerprint
|
|
195
233
|
p_wfp = subparsers.add_parser(
|
|
@@ -1076,7 +1114,7 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
1076
1114
|
# Global Scan command options
|
|
1077
1115
|
for p in [p_scan, p_cs]:
|
|
1078
1116
|
p.add_argument(
|
|
1079
|
-
'--apiurl', type=str, help='SCANOSS API URL (optional - default: https://api.osskb.org
|
|
1117
|
+
'--apiurl', type=str, help='SCANOSS API base URL (optional - default: https://api.osskb.org)'
|
|
1080
1118
|
)
|
|
1081
1119
|
|
|
1082
1120
|
# Global Scan/Fingerprint filter options
|
|
@@ -1377,11 +1415,11 @@ def wfp(parser, args):
|
|
|
1377
1415
|
initialise_empty_file(args.output)
|
|
1378
1416
|
|
|
1379
1417
|
# Load scan settings
|
|
1380
|
-
|
|
1418
|
+
scanoss_settings = None
|
|
1381
1419
|
if not args.skip_settings_file:
|
|
1382
|
-
|
|
1420
|
+
scanoss_settings = ScanossSettings(debug=args.debug, trace=args.trace, quiet=args.quiet)
|
|
1383
1421
|
try:
|
|
1384
|
-
|
|
1422
|
+
scanoss_settings.load_json_file(args.settings, args.scan_dir)
|
|
1385
1423
|
except ScanossSettingsError as e:
|
|
1386
1424
|
print_stderr(f'Error: {e}')
|
|
1387
1425
|
sys.exit(1)
|
|
@@ -1403,7 +1441,7 @@ def wfp(parser, args):
|
|
|
1403
1441
|
skip_md5_ids=args.skip_md5,
|
|
1404
1442
|
strip_hpsm_ids=args.strip_hpsm,
|
|
1405
1443
|
strip_snippet_ids=args.strip_snippet,
|
|
1406
|
-
|
|
1444
|
+
scanoss_settings=scanoss_settings,
|
|
1407
1445
|
skip_headers=args.skip_headers,
|
|
1408
1446
|
skip_headers_limit=args.skip_headers_limit,
|
|
1409
1447
|
)
|
|
@@ -1487,20 +1525,20 @@ def scan(parser, args): # noqa: PLR0912, PLR0915
|
|
|
1487
1525
|
print_stderr('ERROR: Cannot specify both --settings and --skip-file-settings options.')
|
|
1488
1526
|
sys.exit(1)
|
|
1489
1527
|
# Figure out which settings (if any) to load before processing
|
|
1490
|
-
|
|
1528
|
+
scanoss_settings = None
|
|
1491
1529
|
if not args.skip_settings_file:
|
|
1492
|
-
|
|
1530
|
+
scanoss_settings = ScanossSettings(debug=args.debug, trace=args.trace, quiet=args.quiet)
|
|
1493
1531
|
try:
|
|
1494
1532
|
if args.identify:
|
|
1495
|
-
|
|
1533
|
+
scanoss_settings.load_json_file(args.identify, args.scan_dir).set_file_type('legacy').set_scan_type(
|
|
1496
1534
|
'identify'
|
|
1497
1535
|
)
|
|
1498
1536
|
elif args.ignore:
|
|
1499
|
-
|
|
1537
|
+
scanoss_settings.load_json_file(args.ignore, args.scan_dir).set_file_type('legacy').set_scan_type(
|
|
1500
1538
|
'blacklist'
|
|
1501
1539
|
)
|
|
1502
1540
|
else:
|
|
1503
|
-
|
|
1541
|
+
scanoss_settings.load_json_file(args.settings, args.scan_dir).set_file_type('new')
|
|
1504
1542
|
|
|
1505
1543
|
except ScanossSettingsError as e:
|
|
1506
1544
|
print_stderr(f'Error: {e}')
|
|
@@ -1596,11 +1634,17 @@ def scan(parser, args): # noqa: PLR0912, PLR0915
|
|
|
1596
1634
|
skip_md5_ids=args.skip_md5,
|
|
1597
1635
|
strip_hpsm_ids=args.strip_hpsm,
|
|
1598
1636
|
strip_snippet_ids=args.strip_snippet,
|
|
1599
|
-
|
|
1637
|
+
scanoss_settings=scanoss_settings,
|
|
1600
1638
|
req_headers=process_req_headers(args.header),
|
|
1601
1639
|
use_grpc=args.grpc,
|
|
1640
|
+
min_snippet_hits=args.min_snippet_hits,
|
|
1641
|
+
min_snippet_lines=args.min_snippet_lines,
|
|
1642
|
+
ranking=args.ranking,
|
|
1643
|
+
ranking_threshold=args.ranking_threshold,
|
|
1644
|
+
honour_file_exts=args.honour_file_exts,
|
|
1602
1645
|
skip_headers=args.skip_headers,
|
|
1603
1646
|
skip_headers_limit=args.skip_headers_limit,
|
|
1647
|
+
wfp_output=args.wfp_output,
|
|
1604
1648
|
)
|
|
1605
1649
|
if args.wfp:
|
|
1606
1650
|
if not scanner.is_file_or_snippet_scan():
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
date: 20260202142827, utime: 1770042507
|
|
@@ -139,6 +139,100 @@
|
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
+
},
|
|
143
|
+
"file_snippet": {
|
|
144
|
+
"type": "object",
|
|
145
|
+
"description": "File snippet scanning configuration",
|
|
146
|
+
"properties": {
|
|
147
|
+
"proxy": {
|
|
148
|
+
"type": "object",
|
|
149
|
+
"description": "Proxy configuration for file snippet requests",
|
|
150
|
+
"properties": {
|
|
151
|
+
"host": {
|
|
152
|
+
"type": "string",
|
|
153
|
+
"description": "Proxy host URL"
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
"http_config": {
|
|
158
|
+
"type": "object",
|
|
159
|
+
"description": "HTTP configuration for file snippet requests",
|
|
160
|
+
"properties": {
|
|
161
|
+
"base_uri": {
|
|
162
|
+
"type": "string",
|
|
163
|
+
"description": "Base URI for file snippet API requests"
|
|
164
|
+
},
|
|
165
|
+
"ignore_cert_errors": {
|
|
166
|
+
"type": "boolean",
|
|
167
|
+
"description": "Whether to ignore certificate errors"
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"ranking_enabled": {
|
|
172
|
+
"type": ["boolean", "null"],
|
|
173
|
+
"description": "Enable/disable ranking",
|
|
174
|
+
"default": null
|
|
175
|
+
},
|
|
176
|
+
"ranking_threshold": {
|
|
177
|
+
"type": ["integer", "null"],
|
|
178
|
+
"description": "Ranking threshold value. A value of -1 defers to server configuration",
|
|
179
|
+
"minimum": -1,
|
|
180
|
+
"maximum": 99,
|
|
181
|
+
"default": 0
|
|
182
|
+
},
|
|
183
|
+
"min_snippet_hits": {
|
|
184
|
+
"type": "integer",
|
|
185
|
+
"description": "Minimum snippet hits required",
|
|
186
|
+
"minimum": 0,
|
|
187
|
+
"default": 0
|
|
188
|
+
},
|
|
189
|
+
"min_snippet_lines": {
|
|
190
|
+
"type": "integer",
|
|
191
|
+
"description": "Minimum snippet lines required",
|
|
192
|
+
"minimum": 0,
|
|
193
|
+
"default": 0
|
|
194
|
+
},
|
|
195
|
+
"honour_file_exts": {
|
|
196
|
+
"type": ["boolean", "null"],
|
|
197
|
+
"description": "Ignores file extensions. When not set, defers to server configuration.",
|
|
198
|
+
"default": true
|
|
199
|
+
},
|
|
200
|
+
"dependency_analysis": {
|
|
201
|
+
"type": "boolean",
|
|
202
|
+
"description": "Enable dependency analysis"
|
|
203
|
+
},
|
|
204
|
+
"skip_headers": {
|
|
205
|
+
"type": "boolean",
|
|
206
|
+
"description": "Skip license headers, comments and imports at the beginning of files",
|
|
207
|
+
"default": false
|
|
208
|
+
},
|
|
209
|
+
"skip_headers_limit": {
|
|
210
|
+
"type": "integer",
|
|
211
|
+
"description": "Maximum number of lines to skip when filtering headers",
|
|
212
|
+
"default": 0
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
"hpfm": {
|
|
217
|
+
"type": "object",
|
|
218
|
+
"description": "HPFM (High Precision Folder Matching) configuration",
|
|
219
|
+
"properties": {
|
|
220
|
+
"ranking_enabled": {
|
|
221
|
+
"type": "boolean",
|
|
222
|
+
"description": "Enable ranking for HPFM"
|
|
223
|
+
},
|
|
224
|
+
"ranking_threshold": {
|
|
225
|
+
"type": ["integer", "null"],
|
|
226
|
+
"description": "Ranking threshold value. A value of -1 defers to server configuration",
|
|
227
|
+
"minimum": -1,
|
|
228
|
+
"maximum": 99,
|
|
229
|
+
"default": 0
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
"container": {
|
|
234
|
+
"type": "object",
|
|
235
|
+
"description": "Container scanning configuration"
|
|
142
236
|
}
|
|
143
237
|
}
|
|
144
238
|
},
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2025, SCANOSS
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
|
14
|
+
all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
THE SOFTWARE.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from typing import TYPE_CHECKING, Optional
|
|
26
|
+
|
|
27
|
+
from .scanossbase import ScanossBase
|
|
28
|
+
|
|
29
|
+
if TYPE_CHECKING:
|
|
30
|
+
from .scanoss_settings import ScanossSettings
|
|
31
|
+
|
|
32
|
+
MAX_RANKING_THRESHOLD = 10
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ScanSettingsBuilder(ScanossBase):
|
|
36
|
+
"""Builder class for merging CLI arguments with scanoss.json settings file values.
|
|
37
|
+
|
|
38
|
+
This class implements an API for merging scan configuration
|
|
39
|
+
from multiple sources with the following priority order:
|
|
40
|
+
1. settings.file_snippet section in scanoss.json (highest priority)
|
|
41
|
+
2. settings section in scanoss.json (middle priority)
|
|
42
|
+
3. CLI arguments (lowest priority - used as fallback)
|
|
43
|
+
|
|
44
|
+
Attributes:
|
|
45
|
+
proxy: Merged proxy host URL
|
|
46
|
+
url: Merged API base URL
|
|
47
|
+
ignore_cert_errors: Whether to ignore SSL certificate errors
|
|
48
|
+
min_snippet_hits: Minimum snippet hits required for matching
|
|
49
|
+
min_snippet_lines: Minimum snippet lines required for matching
|
|
50
|
+
honour_file_exts: Whether to honour file extensions during scanning
|
|
51
|
+
ranking: Whether ranking is enabled
|
|
52
|
+
ranking_threshold: Ranking threshold value
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(
|
|
56
|
+
self,
|
|
57
|
+
scanoss_settings: 'ScanossSettings | None',
|
|
58
|
+
debug: bool = False,
|
|
59
|
+
trace: bool = False,
|
|
60
|
+
quiet: bool = False,
|
|
61
|
+
):
|
|
62
|
+
"""Initialize the builder with optional scanoss settings.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
scanoss_settings: ScanossSettings instance loaded from scanoss.json,
|
|
66
|
+
or None if no settings file is available.
|
|
67
|
+
debug: Enable debug output
|
|
68
|
+
trace: Enable trace output
|
|
69
|
+
quiet: Enable quiet mode
|
|
70
|
+
"""
|
|
71
|
+
super().__init__(debug=debug, trace=trace, quiet=quiet)
|
|
72
|
+
self.scanoss_settings = scanoss_settings
|
|
73
|
+
# Merged values
|
|
74
|
+
self.proxy: Optional[str] = None
|
|
75
|
+
self.url: Optional[str] = None
|
|
76
|
+
self.ignore_cert_errors: bool = False
|
|
77
|
+
self.min_snippet_hits: Optional[int] = None
|
|
78
|
+
self.min_snippet_lines: Optional[int] = None
|
|
79
|
+
self.honour_file_exts: Optional[any] = None
|
|
80
|
+
self.ranking: Optional[any] = None
|
|
81
|
+
self.ranking_threshold: Optional[int] = None
|
|
82
|
+
|
|
83
|
+
def with_proxy(self, cli_value: str = None) -> 'ScanSettingsBuilder':
|
|
84
|
+
"""Set proxy host with priority: file_snippet.proxy.host > settings.proxy.host > CLI.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
cli_value: Proxy host from CLI argument (e.g., 'http://proxy:8080')
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Self for method chaining
|
|
91
|
+
"""
|
|
92
|
+
self.proxy = self._merge_with_priority(
|
|
93
|
+
cli_value,
|
|
94
|
+
self._get_proxy_host(self._get_file_snippet_proxy()),
|
|
95
|
+
self._get_proxy_host(self._get_root_proxy())
|
|
96
|
+
)
|
|
97
|
+
return self
|
|
98
|
+
|
|
99
|
+
def with_url(self, cli_value: str = None) -> 'ScanSettingsBuilder':
|
|
100
|
+
"""Set API base URL with priority: file_snippet.http_config.base_uri > settings.http_config.base_uri > CLI.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
cli_value: API base URL from CLI argument (e.g., 'https://api.scanoss.com')
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Self for method chaining
|
|
107
|
+
"""
|
|
108
|
+
self.url = self._merge_with_priority(
|
|
109
|
+
cli_value,
|
|
110
|
+
self._get_file_snippet_http_config_value('base_uri'),
|
|
111
|
+
self._get_http_config_value('base_uri')
|
|
112
|
+
)
|
|
113
|
+
return self
|
|
114
|
+
|
|
115
|
+
def with_ignore_cert_errors(self, cli_value: bool = False) -> 'ScanSettingsBuilder':
|
|
116
|
+
"""Set ignore_cert_errors with priority: CLI True > file_snippet > settings > False.
|
|
117
|
+
|
|
118
|
+
Note: CLI value only takes effect if True (flag present). False means
|
|
119
|
+
the flag was not provided, so settings file values are checked.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
cli_value: Whether to ignore SSL certificate errors from CLI flag
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
Self for method chaining
|
|
126
|
+
"""
|
|
127
|
+
result = self._merge_with_priority(
|
|
128
|
+
cli_value if cli_value else None,
|
|
129
|
+
self._get_file_snippet_http_config_value('ignore_cert_errors'),
|
|
130
|
+
self._get_http_config_value('ignore_cert_errors')
|
|
131
|
+
)
|
|
132
|
+
self.ignore_cert_errors = result if result is not None else False
|
|
133
|
+
return self
|
|
134
|
+
|
|
135
|
+
def with_min_snippet_hits(self, cli_value: int = None) -> 'ScanSettingsBuilder':
|
|
136
|
+
"""Set minimum snippet hits with priority: settings.file_snippet.min_snippet_hits > CLI.
|
|
137
|
+
|
|
138
|
+
Minimum allowed value is 0. Values below 0 will be clamped and logged.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
cli_value: Minimum snippet hits from CLI argument
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
Self for method chaining
|
|
145
|
+
"""
|
|
146
|
+
self.min_snippet_hits = self._merge_cli_with_settings(
|
|
147
|
+
cli_value,
|
|
148
|
+
self._get_file_snippet_setting('min_snippet_hits')
|
|
149
|
+
)
|
|
150
|
+
if self.min_snippet_hits is not None and self.min_snippet_hits < 0:
|
|
151
|
+
self.print_msg(
|
|
152
|
+
f'WARNING: min-snippet-hits value {self.min_snippet_hits} is below minimum allowed (0). '
|
|
153
|
+
f'Setting to 0.'
|
|
154
|
+
)
|
|
155
|
+
self.min_snippet_hits = 0
|
|
156
|
+
return self
|
|
157
|
+
|
|
158
|
+
def with_min_snippet_lines(self, cli_value: int = None) -> 'ScanSettingsBuilder':
|
|
159
|
+
"""Set minimum snippet lines with priority: settings.file_snippet.min_snippet_lines > CLI.
|
|
160
|
+
|
|
161
|
+
Minimum allowed value is 0. Values below 0 will be clamped and logged.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
cli_value: Minimum snippet lines from CLI argument
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
Self for method chaining
|
|
168
|
+
"""
|
|
169
|
+
self.min_snippet_lines = self._merge_cli_with_settings(
|
|
170
|
+
cli_value,
|
|
171
|
+
self._get_file_snippet_setting('min_snippet_lines')
|
|
172
|
+
)
|
|
173
|
+
if self.min_snippet_lines is not None and self.min_snippet_lines < 0:
|
|
174
|
+
self.print_msg(
|
|
175
|
+
f'WARNING: min-snippet-lines value {self.min_snippet_lines} is below minimum allowed (0). '
|
|
176
|
+
f'Setting to 0.'
|
|
177
|
+
)
|
|
178
|
+
self.min_snippet_lines = 0
|
|
179
|
+
return self
|
|
180
|
+
|
|
181
|
+
def with_honour_file_exts(self, cli_value: str = None) -> 'ScanSettingsBuilder':
|
|
182
|
+
"""Set honour_file_exts with priority: settings.file_snippet.honour_file_exts > CLI.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
cli_value: String 'true', 'false', or 'unset' from CLI argument
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
Self for method chaining
|
|
189
|
+
"""
|
|
190
|
+
self.honour_file_exts = self._merge_cli_with_settings(
|
|
191
|
+
cli_value,
|
|
192
|
+
self._get_file_snippet_setting('honour_file_exts')
|
|
193
|
+
)
|
|
194
|
+
## Convert to boolean
|
|
195
|
+
if self.honour_file_exts is not None and self.honour_file_exts!= 'unset':
|
|
196
|
+
self.honour_file_exts = self._str_to_bool(self.honour_file_exts)
|
|
197
|
+
return self
|
|
198
|
+
|
|
199
|
+
def with_ranking(self, cli_value: str = None) -> 'ScanSettingsBuilder':
|
|
200
|
+
"""Set ranking enabled with priority: settings.file_snippet.ranking_enabled > CLI.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
cli_value: String 'true', 'false', or 'unset' from CLI argument
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
Self for method chaining
|
|
207
|
+
"""
|
|
208
|
+
self.ranking = self._merge_cli_with_settings(
|
|
209
|
+
cli_value,
|
|
210
|
+
self._get_file_snippet_setting('ranking_enabled')
|
|
211
|
+
)
|
|
212
|
+
if self.ranking is not None and self.ranking != 'unset':
|
|
213
|
+
self.ranking = self._str_to_bool(self.ranking)
|
|
214
|
+
return self
|
|
215
|
+
|
|
216
|
+
def with_ranking_threshold(self, cli_value: int = None) -> 'ScanSettingsBuilder':
|
|
217
|
+
"""Set ranking threshold with priority: settings.file_snippet.ranking_threshold > CLI.
|
|
218
|
+
|
|
219
|
+
Valid range is -1 to 10. Values outside this range will be clamped and logged.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
cli_value: Ranking threshold from CLI argument
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
Self for method chaining
|
|
226
|
+
"""
|
|
227
|
+
self.ranking_threshold = self._merge_cli_with_settings(
|
|
228
|
+
cli_value,
|
|
229
|
+
self._get_file_snippet_setting('ranking_threshold')
|
|
230
|
+
)
|
|
231
|
+
if self.ranking_threshold is not None:
|
|
232
|
+
if self.ranking_threshold > MAX_RANKING_THRESHOLD:
|
|
233
|
+
self.print_msg(
|
|
234
|
+
f'WARNING: ranking-threshold value {self.ranking_threshold} exceeds maximum allowed '
|
|
235
|
+
f'({MAX_RANKING_THRESHOLD}). Setting to {MAX_RANKING_THRESHOLD}.'
|
|
236
|
+
)
|
|
237
|
+
self.ranking_threshold = MAX_RANKING_THRESHOLD
|
|
238
|
+
elif self.ranking_threshold < -1:
|
|
239
|
+
self.print_msg(
|
|
240
|
+
f'WARNING: ranking-threshold value {self.ranking_threshold} is below minimum allowed (-1). '
|
|
241
|
+
f'Setting to -1.'
|
|
242
|
+
)
|
|
243
|
+
self.ranking_threshold = -1
|
|
244
|
+
return self
|
|
245
|
+
|
|
246
|
+
# Private helper methods
|
|
247
|
+
@staticmethod
|
|
248
|
+
def _merge_with_priority(cli_value, file_snippet_value, root_value):
|
|
249
|
+
"""Merge with priority: file_snippet > root settings > CLI"""
|
|
250
|
+
if file_snippet_value is not None:
|
|
251
|
+
return file_snippet_value
|
|
252
|
+
if root_value is not None:
|
|
253
|
+
return root_value
|
|
254
|
+
return cli_value
|
|
255
|
+
|
|
256
|
+
@staticmethod
|
|
257
|
+
def _merge_cli_with_settings(cli_value, settings_value):
|
|
258
|
+
"""Merge CLI value with settings, with settings taking priority over CLI.
|
|
259
|
+
|
|
260
|
+
Returns settings_value if not None, otherwise falls back to cli_value.
|
|
261
|
+
"""
|
|
262
|
+
if settings_value is not None:
|
|
263
|
+
return settings_value
|
|
264
|
+
return cli_value
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
@staticmethod
|
|
268
|
+
def _str_to_bool(value: str) -> Optional[bool]:
|
|
269
|
+
"""Convert string 'true'/'false' to boolean."""
|
|
270
|
+
if value is None:
|
|
271
|
+
return None
|
|
272
|
+
if isinstance(value, bool):
|
|
273
|
+
return value
|
|
274
|
+
return value.lower() == 'true'
|
|
275
|
+
|
|
276
|
+
# Methods to extract values from scanoss_settings
|
|
277
|
+
def _get_file_snippet_setting(self, key: str):
|
|
278
|
+
"""Get a setting from the file_snippet section."""
|
|
279
|
+
if not self.scanoss_settings:
|
|
280
|
+
return None
|
|
281
|
+
return self.scanoss_settings.get_file_snippet_settings().get(key)
|
|
282
|
+
|
|
283
|
+
def _get_file_snippet_proxy(self):
|
|
284
|
+
"""Get proxy config from file_snippet section."""
|
|
285
|
+
return self.scanoss_settings.get_file_snippet_proxy() if self.scanoss_settings else None
|
|
286
|
+
|
|
287
|
+
def _get_root_proxy(self):
|
|
288
|
+
"""Get proxy config from root settings section."""
|
|
289
|
+
return self.scanoss_settings.get_proxy() if self.scanoss_settings else None
|
|
290
|
+
|
|
291
|
+
@staticmethod
|
|
292
|
+
def _get_proxy_host(proxy_config) -> Optional[str]:
|
|
293
|
+
"""Extract host from proxy configuration dict."""
|
|
294
|
+
if proxy_config is None:
|
|
295
|
+
return None
|
|
296
|
+
host = proxy_config.get('host')
|
|
297
|
+
return host if host else None
|
|
298
|
+
|
|
299
|
+
def _get_http_config_value(self, key: str):
|
|
300
|
+
"""Extract a value from http_config dict."""
|
|
301
|
+
if not self.scanoss_settings:
|
|
302
|
+
return None
|
|
303
|
+
config = self.scanoss_settings.get_http_config()
|
|
304
|
+
return config.get(key) if config else None
|
|
305
|
+
|
|
306
|
+
def _get_file_snippet_http_config_value(self, key: str):
|
|
307
|
+
"""Extract a value from file_snippet http_config dict."""
|
|
308
|
+
if not self.scanoss_settings:
|
|
309
|
+
return None
|
|
310
|
+
config = self.scanoss_settings.get_file_snippet_http_config()
|
|
311
|
+
return config.get(key) if config else None
|