Skip to content

Add grpc-ssl-target option to CLI to override SSL target name for gRPC connections #121

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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.25.0] - 2025-06-04
### Added
- Add `grpc-ssl-target` option to CLI to override SSL target name for gRPC connections

## [1.24.0] - 2025-05-28
### Added
- Add `crypto` subcommand to retrieve cryptographic algorithms for the given components
Expand Down Expand Up @@ -522,4 +526,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[1.21.0]: https://github.com/scanoss/scanoss.py/compare/v1.20.6...v1.21.0
[1.22.0]: https://github.com/scanoss/scanoss.py/compare/v1.21.0...v1.22.0
[1.23.0]: https://github.com/scanoss/scanoss.py/compare/v1.22.0...v1.23.0
[1.24.0]: https://github.com/scanoss/scanoss.py/compare/v1.23.0...v1.24.0
[1.24.0]: https://github.com/scanoss/scanoss.py/compare/v1.23.0...v1.24.0
[1.25.0]: https://github.com/scanoss/scanoss.py/compare/v1.24.0...v1.25.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.24.0'
__version__ = '1.25.0'
12 changes: 12 additions & 0 deletions src/scanoss/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,12 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
'"REQUESTS_CA_BUNDLE=/path/to/cacert.pem" and '
'"GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=/path/to/cacert.pem" for gRPC',
)
p.add_argument(
'--grpc-ssl-target',
type=str,
help='Override SSL target name for gRPC connections (optional). '
'Useful when connecting to localhost with a certificate issued for a different domain.',
)

# Global GRPC options
for p in [
Expand Down Expand Up @@ -1138,6 +1144,7 @@ def scan(parser, args): # noqa: PLR0912, PLR0915
ignore_cert_errors=args.ignore_cert_errors,
proxy=args.proxy,
grpc_proxy=args.grpc_proxy,
grpc_ssl_target=args.grpc_ssl_target,
pac=pac_file,
ca_cert=args.ca_cert,
retry=args.retry,
Expand Down Expand Up @@ -1617,6 +1624,7 @@ def comp_vulns(parser, args):
ca_cert=args.ca_cert,
proxy=args.proxy,
grpc_proxy=args.grpc_proxy,
grpc_ssl_target=args.grpc_ssl_target,
pac=pac_file,
timeout=args.timeout,
req_headers=process_req_headers(args.header),
Expand Down Expand Up @@ -1652,6 +1660,7 @@ def comp_semgrep(parser, args):
ca_cert=args.ca_cert,
proxy=args.proxy,
grpc_proxy=args.grpc_proxy,
grpc_ssl_target=args.grpc_ssl_target,
pac=pac_file,
timeout=args.timeout,
req_headers=process_req_headers(args.header),
Expand Down Expand Up @@ -1690,6 +1699,7 @@ def comp_search(parser, args):
ca_cert=args.ca_cert,
proxy=args.proxy,
grpc_proxy=args.grpc_proxy,
grpc_ssl_target=args.grpc_ssl_target,
pac=pac_file,
timeout=args.timeout,
req_headers=process_req_headers(args.header),
Expand Down Expand Up @@ -1735,6 +1745,7 @@ def comp_versions(parser, args):
ca_cert=args.ca_cert,
proxy=args.proxy,
grpc_proxy=args.grpc_proxy,
grpc_ssl_target=args.grpc_ssl_target,
pac=pac_file,
timeout=args.timeout,
req_headers=process_req_headers(args.header),
Expand Down Expand Up @@ -1770,6 +1781,7 @@ def comp_provenance(parser, args):
ca_cert=args.ca_cert,
proxy=args.proxy,
grpc_proxy=args.grpc_proxy,
grpc_ssl_target=args.grpc_ssl_target,
pac=pac_file,
timeout=args.timeout,
req_headers=process_req_headers(args.header),
Expand Down
2 changes: 2 additions & 0 deletions src/scanoss/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def __init__( # noqa: PLR0913, PLR0915
proxy: str = None,
grpc_proxy: str = None,
ca_cert: str = None,
grpc_ssl_target: str = None,
pac: PACFile = None,
req_headers: dict = None,
):
Expand Down Expand Up @@ -77,6 +78,7 @@ def __init__( # noqa: PLR0913, PLR0915
api_key=api_key,
ver_details=ver_details,
ca_cert=ca_cert,
grpc_ssl_target=grpc_ssl_target,
proxy=proxy,
pac=pac,
grpc_proxy=grpc_proxy,
Expand Down
54 changes: 27 additions & 27 deletions src/scanoss/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,40 +22,40 @@
THE SOFTWARE.
"""

import datetime
import json
import os
from pathlib import Path
import sys
import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional
import importlib_resources

import importlib_resources
from progress.bar import Bar
from progress.spinner import Spinner
from pypac.parser import PACFile

from scanoss.file_filters import FileFilters

from .scanossapi import ScanossApi
from .cyclonedx import CycloneDx
from .spdxlite import SpdxLite
from . import __version__
from .csvoutput import CsvOutput
from .threadedscanning import ThreadedScanning
from .cyclonedx import CycloneDx
from .scancodedeps import ScancodeDeps
from .threadeddependencies import ThreadedDependencies, SCOPE
from .scanossgrpc import ScanossGrpc
from .scantype import ScanType
from .scanossbase import ScanossBase
from .scanoss_settings import ScanossSettings
from .scanossapi import ScanossApi
from .scanossbase import ScanossBase
from .scanossgrpc import ScanossGrpc
from .scanpostprocessor import ScanPostProcessor
from . import __version__
from .scantype import ScanType
from .spdxlite import SpdxLite
from .threadeddependencies import SCOPE, ThreadedDependencies
from .threadedscanning import ThreadedScanning

FAST_WINNOWING = False
try:
from scanoss_winnowing.winnowing import Winnowing

FAST_WINNOWING = True
except ModuleNotFoundError or ImportError:
except ModuleNotFoundError or ImportError: # noqa: PLW0711
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix incorrect exception syntax.

The exception handling syntax is incorrect and will cause a runtime error. The or operator should not be used in exception handling.

-except ModuleNotFoundError or ImportError:  # noqa: PLW0711
+except (ModuleNotFoundError, ImportError):  # noqa: PLW0711
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
except ModuleNotFoundError or ImportError: # noqa: PLW0711
except (ModuleNotFoundError, ImportError): # noqa: PLW0711
🧰 Tools
🪛 Pylint (3.3.7)

[warning] 58-60: Exception to catch is the result of a binary "or" operation

(W0711)

🤖 Prompt for AI Agents
In src/scanoss/scanner.py at line 58, the exception handling uses incorrect
syntax with 'or' between exceptions. Replace 'except ModuleNotFoundError or
ImportError:' with 'except (ModuleNotFoundError, ImportError):' to correctly
catch both exceptions.

FAST_WINNOWING = False
from .winnowing import Winnowing

Expand All @@ -69,7 +69,7 @@ class Scanner(ScanossBase):
Handle the scanning of files, snippets and dependencies
"""

def __init__( # noqa: PLR0913, PLR0915
def __init__( # noqa: PLR0913, PLR0915
self,
wfp: str = None,
scan_output: str = None,
Expand All @@ -96,6 +96,7 @@ def __init__( # noqa: PLR0913, PLR0915
proxy: str = None,
grpc_proxy: str = None,
ca_cert: str = None,
grpc_ssl_target: str = None,
pac: PACFile = None,
retry: int = 5,
hpsm: bool = False,
Expand Down Expand Up @@ -158,7 +159,7 @@ def __init__( # noqa: PLR0913, PLR0915
ca_cert=ca_cert,
pac=pac,
retry=retry,
req_headers= self.req_headers,
req_headers=self.req_headers,
)
sc_deps = ScancodeDeps(debug=debug, quiet=quiet, trace=trace, timeout=sc_timeout, sc_command=sc_command)
grpc_api = ScanossGrpc(
Expand All @@ -169,6 +170,7 @@ def __init__( # noqa: PLR0913, PLR0915
api_key=api_key,
ver_details=ver_details,
ca_cert=ca_cert,
grpc_ssl_target=grpc_ssl_target,
proxy=proxy,
pac=pac,
grpc_proxy=grpc_proxy,
Expand Down Expand Up @@ -284,7 +286,7 @@ def is_dependency_scan(self):
return True
return False

def scan_folder_with_options(
def scan_folder_with_options( # noqa: PLR0913
self,
scan_dir: str,
deps_file: str = None,
Expand Down Expand Up @@ -332,7 +334,7 @@ def scan_folder_with_options(
success = False
return success

def scan_folder(self, scan_dir: str) -> bool:
def scan_folder(self, scan_dir: str) -> bool: # noqa: PLR0912, PLR0915
"""
Scan the specified folder producing fingerprints, send to the SCANOSS API and return results

Expand Down Expand Up @@ -400,7 +402,7 @@ def scan_folder(self, scan_dir: str) -> bool:
scan_block += wfp
scan_size = len(scan_block.encode('utf-8'))
wfp_file_count += 1
# If the scan request block (group of WFPs) or larger than the POST size or we have reached the file limit, add it to the queue
# If the scan request block (group of WFPs) or larger than the POST size or we have reached the file limit, add it to the queue # noqa: E501
if wfp_file_count > self.post_file_count or scan_size >= self.max_post_size:
self.threaded_scan.queue_add(scan_block)
queue_size += 1
Expand Down Expand Up @@ -509,7 +511,7 @@ def _merge_scan_results(
for response in scan_responses:
if response is not None:
if file_map:
response = self._deobfuscate_filenames(response, file_map)
response = self._deobfuscate_filenames(response, file_map) # noqa: PLW2901
results.update(response)

dep_files = dep_responses.get('files', None) if dep_responses else None
Expand All @@ -532,7 +534,7 @@ def _deobfuscate_filenames(self, response: dict, file_map: dict) -> dict:
deobfuscated[key] = value
return deobfuscated

def scan_file_with_options(
def scan_file_with_options( # noqa: PLR0913
self,
file: str,
deps_file: str = None,
Expand Down Expand Up @@ -603,7 +605,7 @@ def scan_file(self, file: str) -> bool:
success = False
return success

def scan_files(self, files: []) -> bool:
def scan_files(self, files: []) -> bool: # noqa: PLR0912, PLR0915
"""
Scan the specified list of files, producing fingerprints, send to the SCANOSS API and return results
Please note that by providing an explicit list you bypass any exclusions that may be defined on the scanner
Expand Down Expand Up @@ -657,7 +659,7 @@ def scan_files(self, files: []) -> bool:
file_count += 1
if self.threaded_scan:
wfp_size = len(wfp.encode('utf-8'))
# If the WFP is bigger than the max post size and we already have something stored in the scan block, add it to the queue
# If the WFP is bigger than the max post size and we already have something stored in the scan block, add it to the queue # noqa: E501
if scan_block != '' and (wfp_size + scan_size) >= self.max_post_size:
self.threaded_scan.queue_add(scan_block)
queue_size += 1
Expand All @@ -666,7 +668,7 @@ def scan_files(self, files: []) -> bool:
scan_block += wfp
scan_size = len(scan_block.encode('utf-8'))
wfp_file_count += 1
# If the scan request block (group of WFPs) or larger than the POST size or we have reached the file limit, add it to the queue
# If the scan request block (group of WFPs) or larger than the POST size or we have reached the file limit, add it to the queue # noqa: E501
if wfp_file_count > self.post_file_count or scan_size >= self.max_post_size:
self.threaded_scan.queue_add(scan_block)
queue_size += 1
Expand All @@ -675,9 +677,7 @@ def scan_files(self, files: []) -> bool:
if not scan_started and queue_size > self.nb_threads: # Start scanning if we have something to do
scan_started = True
if not self.threaded_scan.run(wait=False):
self.print_stderr(
'Warning: Some errors encounted while scanning. Results might be incomplete.'
)
self.print_stderr('Warning: Some errors encounted while scanning. Results might be incomplete.')
success = False

# End for loop
Expand Down Expand Up @@ -755,7 +755,7 @@ def scan_contents(self, filename: str, contents: bytes) -> bool:
success = False
return success

def scan_wfp_file(self, file: str = None) -> bool:
def scan_wfp_file(self, file: str = None) -> bool: # noqa: PLR0912, PLR0915
"""
Scan the contents of the specified WFP file (in the current process)
:param file: Scan the contents of the specified WFP file (in the current process)
Expand Down
1 change: 1 addition & 0 deletions src/scanoss/scanners/container_scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ def __init__(
url=config.apiurl,
api_key=config.key,
ca_cert=config.ca_cert,
grpc_ssl_target=config.grpc_ssl_target,
proxy=config.proxy,
pac=config.pac,
grpc_proxy=config.grpc_proxy,
Expand Down
2 changes: 2 additions & 0 deletions src/scanoss/scanners/scanner_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class ScannerConfig:
grpc_proxy: Optional[str] = None

ca_cert: Optional[str] = None
grpc_ssl_target: Optional[str] = None
pac: Optional[PACFile] = None


Expand All @@ -69,5 +70,6 @@ def create_scanner_config_from_args(args) -> ScannerConfig:
proxy=getattr(args, 'proxy', None),
grpc_proxy=getattr(args, 'grpc_proxy', None),
ca_cert=getattr(args, 'ca_cert', None),
grpc_ssl_target=getattr(args, 'grpc_ssl_target', None),
pac=getattr(args, 'pac', None),
)
27 changes: 20 additions & 7 deletions src/scanoss/scanossgrpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ def __init__( # noqa: PLR0913, PLR0915
trace: bool = False,
quiet: bool = False,
ca_cert: str = None,
grpc_ssl_target: str = None,
api_key: str = None,
ver_details: str = None,
timeout: int = 600,
Expand Down Expand Up @@ -132,6 +133,7 @@ def __init__( # noqa: PLR0913, PLR0915
self.timeout = timeout
self.proxy = proxy
self.grpc_proxy = grpc_proxy
self.grpc_ssl_target = grpc_ssl_target
self.pac = pac
self.req_headers = req_headers
self.metadata = []
Expand Down Expand Up @@ -171,17 +173,26 @@ def __init__( # noqa: PLR0913, PLR0915
self.provenance_stub = GeoProvenanceStub(grpc.insecure_channel(self.url))
self.scanning_stub = ScanningStub(grpc.insecure_channel(self.url))
else:
channel_options = []
if self.grpc_ssl_target:
channel_options.append(('grpc.ssl_target_name_override', self.grpc_ssl_target))

if ca_cert is not None:
credentials = grpc.ssl_channel_credentials(cert_data) # secure with specified certificate
else:
credentials = grpc.ssl_channel_credentials() # secure connection with default certificate
self.comp_search_stub = ComponentsStub(grpc.secure_channel(self.url, credentials))
self.crypto_stub = CryptographyStub(grpc.secure_channel(self.url, credentials))
self.dependencies_stub = DependenciesStub(grpc.secure_channel(self.url, credentials))
self.semgrep_stub = SemgrepStub(grpc.secure_channel(self.url, credentials))
self.vuln_stub = VulnerabilitiesStub(grpc.secure_channel(self.url, credentials))
self.provenance_stub = GeoProvenanceStub(grpc.secure_channel(self.url, credentials))
self.scanning_stub = ScanningStub(grpc.secure_channel(self.url, credentials))

self.comp_search_stub = ComponentsStub(grpc.secure_channel(self.url, credentials, options=channel_options))
self.crypto_stub = CryptographyStub(grpc.secure_channel(self.url, credentials, options=channel_options))
self.dependencies_stub = DependenciesStub(
grpc.secure_channel(self.url, credentials, options=channel_options)
)
self.semgrep_stub = SemgrepStub(grpc.secure_channel(self.url, credentials, options=channel_options))
self.vuln_stub = VulnerabilitiesStub(grpc.secure_channel(self.url, credentials, options=channel_options))
self.provenance_stub = GeoProvenanceStub(
grpc.secure_channel(self.url, credentials, options=channel_options)
)
self.scanning_stub = ScanningStub(grpc.secure_channel(self.url, credentials, options=channel_options))

@classmethod
def _load_cert(cls, cert_file: str) -> bytes:
Expand Down Expand Up @@ -694,6 +705,7 @@ class GrpcConfig:
timeout: Optional[int] = DEFAULT_TIMEOUT
proxy: Optional[str] = None
grpc_proxy: Optional[str] = None
grpc_ssl_target: Optional[str] = None
pac: Optional[PACFile] = None
req_headers: Optional[dict] = None

Expand All @@ -710,4 +722,5 @@ def create_grpc_config_from_args(args) -> GrpcConfig:
timeout=getattr(args, 'timeout', DEFAULT_TIMEOUT),
proxy=getattr(args, 'proxy', None),
grpc_proxy=getattr(args, 'grpc_proxy', None),
grpc_ssl_target=getattr(args, 'grpc_ssl_target', None),
)