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
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## 2.4.11

### Changed: units for `--reach-analysis-timeout` and `--reach-analysis-memory-limit`

- `--reach-analysis-timeout` now accepts a duration with an optional unit suffix — `s`, `m`
or `h` (e.g. `90s`, `10m`, `1h`). `--reach-analysis-memory-limit` now accepts a size with an
optional unit suffix — `MB` or `GB`, case-insensitive (e.g. `512MB`, `8GB`). The value is
passed through verbatim to the reachability engine (`@coana-tech/cli`), which owns parsing
and validation, so error messages come from a single source of truth.
- Backward compatible: a bare number is still accepted (seconds for the timeout, MB for the
memory limit), exactly as before. This legacy form is no longer documented but keeps working.
- Bumped the pinned `@coana-tech/cli` version to `15.5.0`, which ships the unit parser.

## 2.4.10

### Added: opt directories back into manifest discovery via `--include-dirs`
Expand Down
6 changes: 3 additions & 3 deletions docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,9 @@ If you don't want to provide the Socket API Token every time then you can use th
| Parameter | Required | Default | Description |
|:---------------------------------|:---------|:--------|:---------------------------------------------------------------------------------------------------------------------------|
| `--reach` | False | False | Enable reachability analysis to identify which vulnerable functions are actually called by your code. Creates a tier-1 full-application reachability scan (`scan_type=socket_tier1`). |
| `--reach-version` | False | 15.3.24 | Version of @coana-tech/cli to use. Defaults to the pinned version that ships with this CLI release, so the engine only changes when you upgrade the Socket CLI. Pass `latest` to always use the newest published version (opt-in auto-update), or an explicit version (e.g. `1.2.3`) to pin it. |
| `--reach-analysis-timeout` | False | 600 | Timeout in seconds for the reachability analysis. Omitted by default, so coana applies its own default. Alias: `--reach-timeout` |
| `--reach-analysis-memory-limit` | False | 8192 | Memory limit in MB for the reachability analysis. Omitted by default, so coana applies its own default. Alias: `--reach-memory-limit` |
| `--reach-version` | False | 15.5.0 | Version of @coana-tech/cli to use. Defaults to the pinned version that ships with this CLI release, so the engine only changes when you upgrade the Socket CLI. Pass `latest` to always use the newest published version (opt-in auto-update), or an explicit version (e.g. `1.2.3`) to pin it. |
| `--reach-analysis-timeout` | False | 10m | Timeout for each reachability analysis run, e.g. `90s`, `10m` or `1h`. Omitted by default, so coana applies its own default (`10m`). Alias: `--reach-timeout` |
| `--reach-analysis-memory-limit` | False | 8GB | Memory limit for each reachability analysis run, e.g. `512MB` or `8GB`. Omitted by default, so coana applies its own default (`8GB`). Alias: `--reach-memory-limit` |
| `--reach-concurrency` | False | 1 | Control parallel analysis execution (must be >= 1). Omitted by default, so coana applies its own default. |
| `--reach-additional-params` | False | | Pass custom parameters to the coana CLI tool |
| `--reach-ecosystems` | False | | Comma-separated list of ecosystems to analyze (e.g., "npm,pypi"). If not specified, all supported ecosystems are analyzed |
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-backend = "hatchling.build"

[project]
name = "socketsecurity"
version = "2.4.10"
version = "2.4.11"
requires-python = ">= 3.11"
license = {"file" = "LICENSE"}
dependencies = [
Expand Down
2 changes: 1 addition & 1 deletion socketsecurity/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
__author__ = 'socket.dev'
__version__ = '2.4.10'
__version__ = '2.4.11'
USER_AGENT = f'SocketPythonCLI/{__version__}'
16 changes: 6 additions & 10 deletions socketsecurity/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ class CliConfig:
# Reachability Flags
reach: bool = False
reach_version: Optional[str] = None
reach_analysis_memory_limit: Optional[int] = None
reach_analysis_timeout: Optional[int] = None
reach_analysis_memory_limit: Optional[str] = None
reach_analysis_timeout: Optional[str] = None
reach_disable_analytics: bool = False
reach_disable_analysis_splitting: bool = False # Deprecated, kept for backwards compatibility
reach_enable_analysis_splitting: bool = False
Expand Down Expand Up @@ -988,29 +988,25 @@ def create_argument_parser() -> argparse.ArgumentParser:
reachability_group.add_argument(
"--reach-analysis-timeout",
dest="reach_analysis_timeout",
type=int,
metavar="<seconds>",
help="Timeout for reachability analysis in seconds"
metavar="<duration>",
help="Set the timeout for each reachability analysis run, e.g. 90s, 10m or 1h. (default: 10m)"
)
# Backwards-compatible alias for the pre-alignment name. Kept working, hidden from help.
reachability_group.add_argument(
"--reach-timeout",
dest="reach_analysis_timeout",
type=int,
help=argparse.SUPPRESS
)
reachability_group.add_argument(
"--reach-analysis-memory-limit",
dest="reach_analysis_memory_limit",
type=int,
metavar="<mb>",
help="Memory limit for reachability analysis in MB (defaults to the coana CLI's own default, currently 8192)"
metavar="<size>",
help="Set the memory limit for each reachability analysis run, e.g. 512MB or 8GB. (default: 8GB)"
)
# Backwards-compatible alias for the pre-alignment name. Kept working, hidden from help.
reachability_group.add_argument(
"--reach-memory-limit",
dest="reach_analysis_memory_limit",
type=int,
help=argparse.SUPPRESS
)
reachability_group.add_argument(
Expand Down
28 changes: 17 additions & 11 deletions socketsecurity/core/tools/reachability.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
# Pinned @coana-tech/cli version. Bumped deliberately per Python CLI release so the
# reachability engine version only changes through a standard pip upgrade (advance notice).
# Pass --reach-version latest to opt into the newest published version instead.
DEFAULT_COANA_CLI_VERSION: Final = "15.3.24"
DEFAULT_COANA_CLI_VERSION: Final = "15.5.0"

# Resolved @coana-tech/cli script paths from the npm-install fallback, keyed by version.
# Lives for the process lifetime so repeated fallback invocations install only once
Expand Down Expand Up @@ -55,7 +55,7 @@ def __init__(self, sdk: socketdev, api_token: str):

def _resolve_coana_package_spec(self, version: Optional[str] = None) -> str:
"""
Resolve the @coana-tech/cli package spec to run (e.g. '@coana-tech/cli@15.3.24').
Resolve the @coana-tech/cli package spec to run (e.g. '@coana-tech/cli@15.5.0').

Args:
version: Coana CLI version to use.
Expand All @@ -64,7 +64,7 @@ def _resolve_coana_package_spec(self, version: Optional[str] = None) -> str:
- '<semver>': that exact version.

Returns:
str: The package specifier to use with npx (e.g. '@coana-tech/cli@15.3.24').
str: The package specifier to use with npx (e.g. '@coana-tech/cli@15.5.0').
"""
return f"@coana-tech/cli@{self._resolve_coana_version(version)}"

Expand All @@ -79,8 +79,8 @@ def run_reachability_analysis(
target_directory: str,
tar_hash: Optional[str] = None,
output_path: str = ".socket.facts.json",
timeout: Optional[int] = None,
memory_limit: Optional[int] = None,
timeout: Optional[str] = None,
memory_limit: Optional[str] = None,
ecosystems: Optional[List[str]] = None,
exclude_paths: Optional[List[str]] = None,
min_severity: Optional[str] = None,
Expand Down Expand Up @@ -112,8 +112,10 @@ def run_reachability_analysis(
target_directory: Directory to analyze
tar_hash: Tar hash from manifest upload or existing scan (optional)
output_path: Output file path for results
timeout: Analysis timeout in seconds
memory_limit: Memory limit in MB
timeout: Analysis timeout, forwarded verbatim to coana --analysis-timeout
(coana parses the units, e.g. '90s', '10m', '1h'; a bare number is seconds)
memory_limit: Memory limit, forwarded verbatim to coana --memory-limit
(coana parses the units, e.g. '512MB', '8GB'; a bare number is MB)
ecosystems: List of ecosystems to analyze (e.g., ['npm', 'pypi'])
exclude_paths: Paths to exclude from analysis
min_severity: Minimum severity level (info, low, moderate, high, critical)
Expand Down Expand Up @@ -149,11 +151,15 @@ def run_reachability_analysis(
"--disable-report-submission"
])

# Add conditional arguments
if timeout:
# Add conditional arguments. timeout/memory_limit are forwarded verbatim; coana owns
# unit parsing/validation (e.g. '90s', '8GB'). We coerce to str only for subprocess
# safety — config-file values can arrive as ints via argparse set_defaults — and use
# `is not None` (not truthiness) so an explicit empty string still reaches coana and
# triggers coana's own error, rather than being silently dropped.
if timeout is not None:
coana_args.extend(["--analysis-timeout", str(timeout)])
if memory_limit:

if memory_limit is not None:
coana_args.extend(["--memory-limit", str(memory_limit)])

if disable_analytics:
Expand Down
20 changes: 15 additions & 5 deletions tests/unit/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,21 +180,31 @@ def test_reach_defaults_are_unset_and_delegated_to_coana(self):
assert config.reach_analysis_timeout is None

def test_reach_node_style_name_aliases(self):
"""G8: Node-style primary names map to the same dests."""
"""G8: Node-style primary names map to the same dests. Values are kept as raw
strings and forwarded verbatim to coana (coana owns unit parsing)."""
config = CliConfig.from_args(
self.BASE_ARGS
+ ["--reach", "--reach-analysis-timeout", "300", "--reach-analysis-memory-limit", "2048"]
)
assert config.reach_analysis_timeout == 300
assert config.reach_analysis_memory_limit == 2048
assert config.reach_analysis_timeout == "300"
assert config.reach_analysis_memory_limit == "2048"

def test_reach_legacy_name_aliases_still_work(self):
"""G8: pre-alignment names keep working (hidden aliases)."""
config = CliConfig.from_args(
self.BASE_ARGS + ["--reach", "--reach-timeout", "111", "--reach-memory-limit", "512"]
)
assert config.reach_analysis_timeout == 111
assert config.reach_analysis_memory_limit == 512
assert config.reach_analysis_timeout == "111"
assert config.reach_analysis_memory_limit == "512"

def test_reach_unit_suffixes_are_passed_through_verbatim(self):
"""Unit-bearing values (parsed/validated by coana) are stored as-is, not coerced."""
config = CliConfig.from_args(
self.BASE_ARGS
+ ["--reach", "--reach-analysis-timeout", "10m", "--reach-analysis-memory-limit", "8GB"]
)
assert config.reach_analysis_timeout == "10m"
assert config.reach_analysis_memory_limit == "8GB"

def test_reach_debug_flag(self):
"""G9: dedicated --reach-debug flag, independent of --enable-debug."""
Expand Down
17 changes: 16 additions & 1 deletion tests/unit/test_reachability.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,26 @@ def test_disable_external_tool_checks(analyzer, mocker):

def test_concurrency_and_memory_args(analyzer, mocker):
"""G7: explicit concurrency/memory propagate as coana args."""
cmd, _ = _run(analyzer, mocker, concurrency=1, memory_limit=8192)
cmd, _ = _run(analyzer, mocker, concurrency=1, memory_limit="8192")
assert "--concurrency" in cmd and cmd[cmd.index("--concurrency") + 1] == "1"
assert "--memory-limit" in cmd and cmd[cmd.index("--memory-limit") + 1] == "8192"


def test_timeout_and_memory_units_forwarded_verbatim(analyzer, mocker):
"""Unit-bearing timeout/memory strings are forwarded to coana untouched (coana parses them)."""
cmd, _ = _run(analyzer, mocker, timeout="10m", memory_limit="8GB")
assert cmd[cmd.index("--analysis-timeout") + 1] == "10m"
assert cmd[cmd.index("--memory-limit") + 1] == "8GB"


def test_timeout_and_memory_int_values_coerced_to_str(analyzer, mocker):
"""Config-file values can arrive as ints (set_defaults bypasses argparse type=); they must
still reach subprocess as strings, not raw ints."""
cmd, _ = _run(analyzer, mocker, timeout=300, memory_limit=2048)
assert cmd[cmd.index("--analysis-timeout") + 1] == "300"
assert cmd[cmd.index("--memory-limit") + 1] == "2048"


def test_env_identifies_python_cli(analyzer, mocker):
"""G5: SOCKET_CLI_VERSION + SOCKET_CALLER_USER_AGENT forwarded to coana."""
_, env = _run(analyzer, mocker)
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading