Skip to content

Commit ef1fbf9

Browse files
authored
feat: add Socket tier 1 reachability analysis support (#125)
* feat: add Socket tier 1 reachability analysis support - Add --reach flag and related CLI arguments for reachability analysis - Add ReachabilityAnalyzer class to run @coana-tech/cli - Add dependency checks for java, npm, uv, npx when --reach is enabled - Add --only-facts-file mode to submit only .socket.facts.json - Auto-install @coana-tech/cli if not present - Stream reachability CLI output to stderr for user visibility - Filter .socket.facts.json from manifest uploads but include in full scans - Set tmp=False in FullScanParams to fix API 400 errors * docs: update README with reachability parameters and remove java requirement - Add comprehensive reachability analysis parameters section to README - Document all --reach-* CLI flags with descriptions and defaults - List required dependencies (npm, npx, uv) excluding java - Remove java from required dependencies check in socketcli.py - Update usage synopsis to include reachability flags * Added org check details
1 parent cc45ff4 commit ef1fbf9

File tree

8 files changed

+545
-13
lines changed

8 files changed

+545
-13
lines changed

README.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,11 @@ socketcli [-h] [--api-token API_TOKEN] [--repo REPO] [--repo-is-public] [--branc
9494
[--save-manifest-tar SAVE_MANIFEST_TAR] [--files FILES] [--sub-path SUB_PATH] [--workspace-name WORKSPACE_NAME]
9595
[--excluded-ecosystems EXCLUDED_ECOSYSTEMS] [--default-branch] [--pending-head] [--generate-license] [--enable-debug]
9696
[--enable-json] [--enable-sarif] [--disable-overview] [--exclude-license-details] [--allow-unverified] [--disable-security-issue]
97-
[--ignore-commit-files] [--disable-blocking] [--enable-diff] [--scm SCM] [--timeout TIMEOUT] [--include-module-folders] [--version]
97+
[--ignore-commit-files] [--disable-blocking] [--enable-diff] [--scm SCM] [--timeout TIMEOUT] [--include-module-folders]
98+
[--reach] [--reach-version REACH_VERSION] [--reach-analysis-timeout REACH_ANALYSIS_TIMEOUT]
99+
[--reach-analysis-memory-limit REACH_ANALYSIS_MEMORY_LIMIT] [--reach-ecosystems REACH_ECOSYSTEMS] [--reach-exclude-paths REACH_EXCLUDE_PATHS]
100+
[--reach-min-severity {low,medium,high,critical}] [--reach-skip-cache] [--reach-disable-analytics] [--reach-output-file REACH_OUTPUT_FILE]
101+
[--only-facts-file] [--version]
98102
````
99103

100104
If you don't want to provide the Socket API Token every time then you can use the environment variable `SOCKET_SECURITY_API_KEY`
@@ -160,6 +164,28 @@ If you don't want to provide the Socket API Token every time then you can use th
160164
| --allow-unverified | False | False | Allow unverified packages |
161165
| --disable-security-issue | False | False | Disable security issue checks |
162166
167+
#### Reachability Analysis
168+
| Parameter | Required | Default | Description |
169+
|:---------------------------------|:---------|:--------|:---------------------------------------------------------------------------------------------------------------------------|
170+
| --reach | False | False | Enable reachability analysis to identify which vulnerable functions are actually called by your code |
171+
| --reach-version | False | latest | Version of @coana-tech/cli to use for analysis |
172+
| --reach-analysis-timeout | False | 1200 | Timeout in seconds for the reachability analysis (default: 1200 seconds / 20 minutes) |
173+
| --reach-analysis-memory-limit | False | 4096 | Memory limit in MB for the reachability analysis (default: 4096 MB / 4 GB) |
174+
| --reach-ecosystems | False | | Comma-separated list of ecosystems to analyze (e.g., "npm,pypi"). If not specified, all supported ecosystems are analyzed |
175+
| --reach-exclude-paths | False | | Comma-separated list of file paths or patterns to exclude from reachability analysis |
176+
| --reach-min-severity | False | | Minimum severity level for reporting reachability results (low, medium, high, critical) |
177+
| --reach-skip-cache | False | False | Skip cache and force fresh reachability analysis |
178+
| --reach-disable-analytics | False | False | Disable analytics collection during reachability analysis |
179+
| --reach-output-file | False | .socket.facts.json | Path where reachability analysis results should be saved |
180+
| --only-facts-file | False | False | Submit only the .socket.facts.json file to an existing scan (requires --reach and a prior scan) |
181+
182+
**Reachability Analysis Requirements:**
183+
- `npm` - Required to install and run @coana-tech/cli
184+
- `npx` - Required to execute @coana-tech/cli
185+
- `uv` - Required for Python environment management
186+
187+
The CLI will automatically install @coana-tech/cli if not present. Use `--reach` to enable reachability analysis during a full scan, or use `--only-facts-file` with `--reach` to submit reachability results to an existing scan.
188+
163189
#### Advanced Configuration
164190
| Parameter | Required | Default | Description |
165191
|:-------------------------|:---------|:--------|:----------------------------------------------------------------------|

pyproject.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
66

77
[project]
88
name = "socketsecurity"
9-
version = "2.2.15"
9+
version = "2.2.18"
1010
requires-python = ">= 3.10"
1111
license = {"file" = "LICENSE"}
1212
dependencies = [
@@ -16,7 +16,8 @@ dependencies = [
1616
'GitPython',
1717
'packaging',
1818
'python-dotenv',
19-
'socketdev>=3.0.6,<4.0.0'
19+
'socketdev>=3.0.6,<4.0.0',
20+
"bs4>=0.0.2",
2021
]
2122
readme = "README.md"
2223
description = "Socket Security CLI for CI/CD"
@@ -158,4 +159,4 @@ docstring-code-format = false
158159
docstring-code-line-length = "dynamic"
159160

160161
[tool.hatch.build.targets.wheel]
161-
include = ["socketsecurity", "LICENSE"]
162+
include = ["socketsecurity", "LICENSE"]

socketsecurity/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
__author__ = 'socket.dev'
2-
__version__ = '2.2.15'
2+
__version__ = '2.2.18'
33
USER_AGENT = f'SocketPythonCLI/{__version__}'

socketsecurity/config.py

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,19 @@ class CliConfig:
6262
save_manifest_tar: Optional[str] = None
6363
sub_paths: List[str] = field(default_factory=list)
6464
workspace_name: Optional[str] = None
65-
65+
# Reachability Flags
66+
reach: bool = False
67+
reach_version: Optional[str] = None
68+
reach_analysis_memory_limit: Optional[int] = None
69+
reach_analysis_timeout: Optional[int] = None
70+
reach_disable_analytics: bool = False
71+
reach_ecosystems: Optional[List[str]] = None
72+
reach_exclude_paths: Optional[List[str]] = None
73+
reach_skip_cache: bool = False
74+
reach_min_severity: Optional[str] = None
75+
reach_output_file: Optional[str] = None
76+
only_facts_file: bool = False
77+
6678
@classmethod
6779
def from_args(cls, args_list: Optional[List[str]] = None) -> 'CliConfig':
6880
parser = create_argument_parser()
@@ -110,6 +122,17 @@ def from_args(cls, args_list: Optional[List[str]] = None) -> 'CliConfig':
110122
'save_manifest_tar': args.save_manifest_tar,
111123
'sub_paths': args.sub_paths or [],
112124
'workspace_name': args.workspace_name,
125+
'reach': args.reach,
126+
'reach_version': args.reach_version,
127+
'reach_analysis_timeout': args.reach_analysis_timeout,
128+
'reach_analysis_memory_limit': args.reach_analysis_memory_limit,
129+
'reach_disable_analytics': args.reach_disable_analytics,
130+
'reach_ecosystems': args.reach_ecosystems.split(',') if args.reach_ecosystems else None,
131+
'reach_exclude_paths': args.reach_exclude_paths.split(',') if args.reach_exclude_paths else None,
132+
'reach_skip_cache': args.reach_skip_cache,
133+
'reach_min_severity': args.reach_min_severity,
134+
'reach_output_file': args.reach_output_file,
135+
'only_facts_file': args.only_facts_file,
113136
'version': __version__
114137
}
115138
try:
@@ -141,6 +164,11 @@ def from_args(cls, args_list: Optional[List[str]] = None) -> 'CliConfig':
141164
logging.error("--workspace-name requires --sub-path to be specified")
142165
exit(1)
143166

167+
# Validate that only_facts_file requires reach
168+
if args.only_facts_file and not args.reach:
169+
logging.error("--only-facts-file requires --reach to be specified")
170+
exit(1)
171+
144172
return cls(**config_args)
145173

146174
def to_dict(self) -> dict:
@@ -474,6 +502,78 @@ def create_argument_parser() -> argparse.ArgumentParser:
474502
help="Enabling including module folders like node_modules"
475503
)
476504

505+
# Reachability Configuration
506+
reachability_group = parser.add_argument_group('Reachability Analysis')
507+
reachability_group.add_argument(
508+
"--reach",
509+
dest="reach",
510+
action="store_true",
511+
help="Enable reachability analysis"
512+
)
513+
reachability_group.add_argument(
514+
"--reach-version",
515+
dest="reach_version",
516+
metavar="<version>",
517+
help="Specific version of @coana-tech/cli to use (e.g., '1.2.3')"
518+
)
519+
reachability_group.add_argument(
520+
"--reach-timeout",
521+
dest="reach_analysis_timeout",
522+
type=int,
523+
metavar="<seconds>",
524+
help="Timeout for reachability analysis in seconds"
525+
)
526+
reachability_group.add_argument(
527+
"--reach-memory-limit",
528+
dest="reach_analysis_memory_limit",
529+
type=int,
530+
metavar="<mb>",
531+
help="Memory limit for reachability analysis in MB"
532+
)
533+
reachability_group.add_argument(
534+
"--reach-ecosystems",
535+
dest="reach_ecosystems",
536+
metavar="<list>",
537+
help="Ecosystems to analyze for reachability (comma-separated, e.g., 'npm,pypi')"
538+
)
539+
reachability_group.add_argument(
540+
"--reach-exclude-paths",
541+
dest="reach_exclude_paths",
542+
metavar="<list>",
543+
help="Paths to exclude from reachability analysis (comma-separated)"
544+
)
545+
reachability_group.add_argument(
546+
"--reach-min-severity",
547+
dest="reach_min_severity",
548+
metavar="<level>",
549+
help="Minimum severity level for reachability analysis (info, low, moderate, high, critical)"
550+
)
551+
reachability_group.add_argument(
552+
"--reach-skip-cache",
553+
dest="reach_skip_cache",
554+
action="store_true",
555+
help="Skip cache usage for reachability analysis"
556+
)
557+
reachability_group.add_argument(
558+
"--reach-disable-analytics",
559+
dest="reach_disable_analytics",
560+
action="store_true",
561+
help="Disable analytics sharing for reachability analysis"
562+
)
563+
reachability_group.add_argument(
564+
"--reach-output-file",
565+
dest="reach_output_file",
566+
metavar="<path>",
567+
default=".socket.facts.json",
568+
help="Output file path for reachability analysis results (default: .socket.facts.json)"
569+
)
570+
reachability_group.add_argument(
571+
"--only-facts-file",
572+
dest="only_facts_file",
573+
action="store_true",
574+
help="Submit only the .socket.facts.json file when creating full scan (requires --reach)"
575+
)
576+
477577
parser.add_argument(
478578
'--version',
479579
action='version',

socketsecurity/core/helper/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import markdown
2-
from bs4 import BeautifulSoup, NavigableString, Tag
2+
from bs4 import BeautifulSoup, Tag
3+
from bs4.element import NavigableString
34
import string
45

56

0 commit comments

Comments
 (0)