Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Upcoming changes...

## [1.32.0] - 2025-08-29
### Added
- Switched vulnerability and dependency APIs to use REST by default

## [1.31.5] - 2025-08-27
### Added
- Added jira markdown option for DT
Expand Down Expand Up @@ -655,4 +659,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[1.31.2]: https://github.com/scanoss/scanoss.py/compare/v1.31.1...v1.31.2
[1.31.3]: https://github.com/scanoss/scanoss.py/compare/v1.31.2...v1.31.3
[1.31.4]: https://github.com/scanoss/scanoss.py/compare/v1.31.3...v1.31.4
[1.31.5]: https://github.com/scanoss/scanoss.py/compare/v1.31.4...v1.31.5
[1.31.5]: https://github.com/scanoss/scanoss.py/compare/v1.31.4...v1.31.5
[1.31.5]: https://github.com/scanoss/scanoss.py/compare/v1.31.5...v1.32.0
2 changes: 1 addition & 1 deletion src/scanoss/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@
THE SOFTWARE.
"""

__version__ = '1.31.5'
__version__ = '1.32.0'
7 changes: 6 additions & 1 deletion src/scanoss/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
help='Retrieve vulnerabilities for the given components',
)
c_vulns.set_defaults(func=comp_vulns)
c_vulns.add_argument('--grpc', action='store_true', help='Enable gRPC support')

# Component Sub-command: component semgrep
c_semgrep = comp_sub.add_parser(
Expand Down Expand Up @@ -964,7 +965,7 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
p.add_argument(
'--apiurl', type=str, help='SCANOSS API URL (optional - default: https://api.osskb.org/scan/direct)'
)
p.add_argument('--ignore-cert-errors', action='store_true', help='Ignore certificate errors')
p.add_argument('--grpc', action='store_true', help='Enable gRPC support')

# Global Scan/Fingerprint filter options
for p in [p_scan, p_wfp]:
Expand Down Expand Up @@ -1055,6 +1056,7 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
type=str,
help='Headers to be sent on request (e.g., -hdr "Name: Value") - can be used multiple times',
)
p.add_argument('--ignore-cert-errors', action='store_true', help='Ignore certificate errors')

# Syft options
for p in [p_cs, p_dep]:
Expand Down Expand Up @@ -1418,6 +1420,7 @@ def scan(parser, args): # noqa: PLR0912, PLR0915
strip_snippet_ids=args.strip_snippet,
scan_settings=scan_settings,
req_headers=process_req_headers(args.header),
use_grpc=args.grpc
)
if args.wfp:
if not scanner.is_file_or_snippet_scan():
Expand Down Expand Up @@ -2144,6 +2147,8 @@ def comp_vulns(parser, args):
pac=pac_file,
timeout=args.timeout,
req_headers=process_req_headers(args.header),
ignore_cert_errors=args.ignore_cert_errors,
use_grpc=args.grpc,
)
if not comps.get_vulnerabilities(args.input, args.purl, args.output):
sys.exit(1)
Expand Down
35 changes: 27 additions & 8 deletions src/scanoss/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ def __init__( # noqa: PLR0913, PLR0915
ca_cert: str = None,
pac: PACFile = None,
req_headers: dict = None,
ignore_cert_errors: bool = False,
use_grpc: bool = False,
):
"""
Handle all component style requests
Expand All @@ -66,6 +68,9 @@ def __init__( # noqa: PLR0913, PLR0915
:param grpc_proxy: Specific gRPC proxy (optional)
:param ca_cert: TLS client certificate (optional)
:param pac: Proxy Auto-Config file (optional)
:param req_headers: Additional headers to send with requests (optional)
:param ignore_cert_errors: Ignore TLS certificate errors (optional)
:param use_grpc: Use gRPC instead of HTTP (optional)
"""
super().__init__(debug, trace, quiet)
ver_details = Scanner.version_details()
Expand All @@ -82,14 +87,28 @@ def __init__( # noqa: PLR0913, PLR0915
grpc_proxy=grpc_proxy,
timeout=timeout,
req_headers=req_headers,
ignore_cert_errors=ignore_cert_errors,
use_grpc=use_grpc,
)

def load_purls(self, json_file: Optional[str] = None, purls: Optional[List[str]] = None) -> Optional[dict]:
def load_comps(self, json_file: Optional[str] = None, purls: Optional[List[str]] = None)-> Optional[dict]:
"""
Load the specified components and return a dictionary

:param json_file: JSON Components file (optional)
:param purls: list pf PURLs (optional)
:return: Components Request dictionary or None
"""
return self.load_purls(json_file, purls, 'components')

def load_purls(self, json_file: Optional[str] = None, purls: Optional[List[str]] = None, field:str = 'purls'
) -> Optional[dict]:
"""
Load the specified purls and return a dictionary

:param json_file: JSON PURL file (optional)
:param purls: list of PURLs (optional)
:param field: Name of the dictionary field to store the purls in (default: 'purls')
:return: PURL Request dictionary or None
"""
if json_file:
Expand All @@ -109,14 +128,14 @@ def load_purls(self, json_file: Optional[str] = None, purls: Optional[List[str]]
parsed_purls = []
for p in purls:
parsed_purls.append({'purl': p})
purl_request = {'purls': parsed_purls}
purl_request = {field: parsed_purls}
else:
self.print_stderr('ERROR: No purls specified to process.')
return None
purl_count = len(purl_request.get('purls', []))
self.print_debug(f'Parsed Purls ({purl_count}): {purl_request}')
purl_count = len(purl_request.get(field, []))
self.print_debug(f'Parsed {field} ({purl_count}): {purl_request}')
if purl_count == 0:
self.print_stderr('ERROR: No PURLs parsed from request.')
self.print_stderr(f'ERROR: No {field} parsed from request.')
return None
return purl_request

Expand All @@ -142,8 +161,8 @@ def _open_file_or_sdtout(self, filename):
"""
Open the given filename if requested, otherwise return STDOUT

:param filename:
:return:
:param filename: filename to open or None to return STDOUT
:return: file descriptor or None
"""
file = sys.stdout
if filename:
Expand Down Expand Up @@ -202,7 +221,7 @@ def get_vulnerabilities(self, json_file: str = None, purls: [] = None, output_fi
:return: True on success, False otherwise
"""
success = False
purls_request = self.load_purls(json_file, purls)
purls_request = self.load_comps(json_file, purls)
if purls_request is None or len(purls_request) == 0:
return False
file = self._open_file_or_sdtout(output_file)
Expand Down
3 changes: 3 additions & 0 deletions src/scanoss/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ def __init__( # noqa: PLR0913, PLR0915
skip_md5_ids=None,
scan_settings: 'ScanossSettings | None' = None,
req_headers: dict = None,
use_grpc: bool = False,
):
"""
Initialise scanning class, including Winnowing, ScanossApi, ThreadedScanning
Expand Down Expand Up @@ -173,6 +174,8 @@ def __init__( # noqa: PLR0913, PLR0915
pac=pac,
grpc_proxy=grpc_proxy,
req_headers=self.req_headers,
ignore_cert_errors=ignore_cert_errors,
use_grpc=use_grpc
)
self.threaded_deps = ThreadedDependencies(sc_deps, grpc_api, debug=debug, quiet=quiet, trace=trace)
self.nb_threads = nb_threads
Expand Down
15 changes: 10 additions & 5 deletions src/scanoss/scanossapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def __init__( # noqa: PLR0913, PLR0915
"""
super().__init__(debug, trace, quiet)
self.url = url
self.api_key = api_key
self.api_key = api_key if api_key else SCANOSS_API_KEY
self.sbom = None
self.scan_format = scan_format if scan_format else 'plain'
self.flags = flags
Expand All @@ -107,10 +107,7 @@ def __init__( # noqa: PLR0913, PLR0915
self.headers['user-agent'] = f'scanoss-py/{__version__}'
self.load_generic_headers()

self.url = url if url else SCANOSS_SCAN_URL
self.api_key = api_key if api_key else SCANOSS_API_KEY
if self.api_key and not url and not os.environ.get('SCANOSS_SCAN_URL'):
self.url = DEFAULT_URL2 # API key specific and no alternative URL, so use the default premium
self.url = self._get_scan_url()

if self.trace:
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
Expand Down Expand Up @@ -284,6 +281,14 @@ def load_generic_headers(self):
self.api_key = value
self.headers[key] = value


def _get_scan_url(self):
url = SCANOSS_SCAN_URL
if url not in[DEFAULT_URL, DEFAULT_URL2]:
return url
if self.api_key and url in[DEFAULT_URL, DEFAULT_URL2]:
return DEFAULT_URL2
return url
#
# End of ScanossApi Class
#
Loading