socketsecurity 2.2.15__tar.gz → 2.2.22__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.
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/Dockerfile +2 -1
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/PKG-INFO +30 -3
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/README.md +27 -1
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/pyproject.toml +4 -3
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/__init__.py +1 -1
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/config.py +101 -1
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/git_interface.py +1 -2
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/helper/__init__.py +2 -1
- socketsecurity-2.2.22/socketsecurity/core/tools/reachability.py +238 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/socketcli.py +135 -1
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/uv.lock +41 -5
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/.github/CODEOWNERS +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/.github/PULL_REQUEST_TEMPLATE/bug-fix.md +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/.github/PULL_REQUEST_TEMPLATE/feature.md +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/.github/PULL_REQUEST_TEMPLATE/improvement.md +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/.github/workflows/docker-stable.yml +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/.github/workflows/pr-preview.yml +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/.github/workflows/release.yml +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/.github/workflows/version-check.yml +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/.gitignore +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/.hooks/sync_version.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/.pre-commit-config.yaml +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/.python-version +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/LICENSE +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/Makefile +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/docs/README.md +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/pytest.ini +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/scripts/build_container.sh +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/scripts/deploy-test-docker.sh +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/scripts/deploy-test-pypi.sh +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/scripts/run.sh +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/__init__.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/classes.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/cli_client.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/exceptions.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/lazy_file_loader.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/logging.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/messages.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/resource_utils.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/scm/__init__.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/scm/base.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/scm/client.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/scm/github.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/scm/gitlab.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/scm_comments.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/socket_config.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/core/utils.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/output.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/plugins/__init__.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/plugins/base.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/plugins/jira.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/plugins/manager.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/plugins/slack.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/plugins/teams.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/socketsecurity/plugins/webhook.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/__init__.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/core/conftest.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/core/create_diff_input.json +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/core/test_diff_generation.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/core/test_package_and_alerts.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/core/test_sdk_methods.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/core/test_supporting_methods.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/fullscans/create_response.json +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/fullscans/diff/stream_diff.json +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/fullscans/diff/stream_diff_full.json +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/fullscans/head_scan/metadata.json +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/fullscans/head_scan/stream_scan.json +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/fullscans/head_scan/stream_scan_full.json +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/fullscans/new_scan/metadata.json +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/fullscans/new_scan/stream_scan.json +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/repos/repo_info_error.json +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/repos/repo_info_no_head.json +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/repos/repo_info_success.json +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/settings/security-policy.json +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/unit/__init__.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/unit/test_cli_config.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/unit/test_client.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/unit/test_config.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/unit/test_gitlab_auth.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/unit/test_gitlab_auth_fallback.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/unit/test_output.py +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/workflows/bitbucket-pipelines.yml +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/workflows/github-actions.yml +0 -0
- {socketsecurity-2.2.15 → socketsecurity-2.2.22}/workflows/gitlab-ci.yml +0 -0
|
@@ -6,7 +6,8 @@ ARG PIP_INDEX_URL=https://pypi.org/simple
|
|
|
6
6
|
ARG PIP_EXTRA_INDEX_URL=https://pypi.org/simple
|
|
7
7
|
|
|
8
8
|
RUN apk update \
|
|
9
|
-
&& apk add --no-cache git nodejs npm yarn
|
|
9
|
+
&& apk add --no-cache git nodejs npm yarn \
|
|
10
|
+
&& npm install @coana-tech/cli -g
|
|
10
11
|
|
|
11
12
|
# Install CLI with retries for TestPyPI propagation (10 attempts, 30s each = 5 minutes total)
|
|
12
13
|
RUN for i in $(seq 1 10); do \
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: socketsecurity
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.22
|
|
4
4
|
Summary: Socket Security CLI for CI/CD
|
|
5
5
|
Project-URL: Homepage, https://socket.dev
|
|
6
6
|
Author-email: Douglas Coburn <douglas@socket.dev>
|
|
@@ -33,13 +33,14 @@ Classifier: Intended Audience :: Developers
|
|
|
33
33
|
Classifier: Programming Language :: Python :: 3.11
|
|
34
34
|
Classifier: Programming Language :: Python :: 3.12
|
|
35
35
|
Requires-Python: >=3.10
|
|
36
|
+
Requires-Dist: bs4>=0.0.2
|
|
36
37
|
Requires-Dist: gitpython
|
|
37
38
|
Requires-Dist: mdutils
|
|
38
39
|
Requires-Dist: packaging
|
|
39
40
|
Requires-Dist: prettytable
|
|
40
41
|
Requires-Dist: python-dotenv
|
|
41
42
|
Requires-Dist: requests
|
|
42
|
-
Requires-Dist: socketdev<4.0.0,>=3.0.
|
|
43
|
+
Requires-Dist: socketdev<4.0.0,>=3.0.16
|
|
43
44
|
Provides-Extra: dev
|
|
44
45
|
Requires-Dist: hatch; extra == 'dev'
|
|
45
46
|
Requires-Dist: pre-commit; extra == 'dev'
|
|
@@ -150,7 +151,11 @@ socketcli [-h] [--api-token API_TOKEN] [--repo REPO] [--repo-is-public] [--branc
|
|
|
150
151
|
[--save-manifest-tar SAVE_MANIFEST_TAR] [--files FILES] [--sub-path SUB_PATH] [--workspace-name WORKSPACE_NAME]
|
|
151
152
|
[--excluded-ecosystems EXCLUDED_ECOSYSTEMS] [--default-branch] [--pending-head] [--generate-license] [--enable-debug]
|
|
152
153
|
[--enable-json] [--enable-sarif] [--disable-overview] [--exclude-license-details] [--allow-unverified] [--disable-security-issue]
|
|
153
|
-
[--ignore-commit-files] [--disable-blocking] [--enable-diff] [--scm SCM] [--timeout TIMEOUT] [--include-module-folders]
|
|
154
|
+
[--ignore-commit-files] [--disable-blocking] [--enable-diff] [--scm SCM] [--timeout TIMEOUT] [--include-module-folders]
|
|
155
|
+
[--reach] [--reach-version REACH_VERSION] [--reach-analysis-timeout REACH_ANALYSIS_TIMEOUT]
|
|
156
|
+
[--reach-analysis-memory-limit REACH_ANALYSIS_MEMORY_LIMIT] [--reach-ecosystems REACH_ECOSYSTEMS] [--reach-exclude-paths REACH_EXCLUDE_PATHS]
|
|
157
|
+
[--reach-min-severity {low,medium,high,critical}] [--reach-skip-cache] [--reach-disable-analytics] [--reach-output-file REACH_OUTPUT_FILE]
|
|
158
|
+
[--only-facts-file] [--version]
|
|
154
159
|
````
|
|
155
160
|
|
|
156
161
|
If you don't want to provide the Socket API Token every time then you can use the environment variable `SOCKET_SECURITY_API_KEY`
|
|
@@ -216,6 +221,28 @@ If you don't want to provide the Socket API Token every time then you can use th
|
|
|
216
221
|
| --allow-unverified | False | False | Allow unverified packages |
|
|
217
222
|
| --disable-security-issue | False | False | Disable security issue checks |
|
|
218
223
|
|
|
224
|
+
#### Reachability Analysis
|
|
225
|
+
| Parameter | Required | Default | Description |
|
|
226
|
+
|:---------------------------------|:---------|:--------|:---------------------------------------------------------------------------------------------------------------------------|
|
|
227
|
+
| --reach | False | False | Enable reachability analysis to identify which vulnerable functions are actually called by your code |
|
|
228
|
+
| --reach-version | False | latest | Version of @coana-tech/cli to use for analysis |
|
|
229
|
+
| --reach-analysis-timeout | False | 1200 | Timeout in seconds for the reachability analysis (default: 1200 seconds / 20 minutes) |
|
|
230
|
+
| --reach-analysis-memory-limit | False | 4096 | Memory limit in MB for the reachability analysis (default: 4096 MB / 4 GB) |
|
|
231
|
+
| --reach-ecosystems | False | | Comma-separated list of ecosystems to analyze (e.g., "npm,pypi"). If not specified, all supported ecosystems are analyzed |
|
|
232
|
+
| --reach-exclude-paths | False | | Comma-separated list of file paths or patterns to exclude from reachability analysis |
|
|
233
|
+
| --reach-min-severity | False | | Minimum severity level for reporting reachability results (low, medium, high, critical) |
|
|
234
|
+
| --reach-skip-cache | False | False | Skip cache and force fresh reachability analysis |
|
|
235
|
+
| --reach-disable-analytics | False | False | Disable analytics collection during reachability analysis |
|
|
236
|
+
| --reach-output-file | False | .socket.facts.json | Path where reachability analysis results should be saved |
|
|
237
|
+
| --only-facts-file | False | False | Submit only the .socket.facts.json file to an existing scan (requires --reach and a prior scan) |
|
|
238
|
+
|
|
239
|
+
**Reachability Analysis Requirements:**
|
|
240
|
+
- `npm` - Required to install and run @coana-tech/cli
|
|
241
|
+
- `npx` - Required to execute @coana-tech/cli
|
|
242
|
+
- `uv` - Required for Python environment management
|
|
243
|
+
|
|
244
|
+
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.
|
|
245
|
+
|
|
219
246
|
#### Advanced Configuration
|
|
220
247
|
| Parameter | Required | Default | Description |
|
|
221
248
|
|:-------------------------|:---------|:--------|:----------------------------------------------------------------------|
|
|
@@ -94,7 +94,11 @@ socketcli [-h] [--api-token API_TOKEN] [--repo REPO] [--repo-is-public] [--branc
|
|
|
94
94
|
[--save-manifest-tar SAVE_MANIFEST_TAR] [--files FILES] [--sub-path SUB_PATH] [--workspace-name WORKSPACE_NAME]
|
|
95
95
|
[--excluded-ecosystems EXCLUDED_ECOSYSTEMS] [--default-branch] [--pending-head] [--generate-license] [--enable-debug]
|
|
96
96
|
[--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]
|
|
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]
|
|
98
102
|
````
|
|
99
103
|
|
|
100
104
|
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
|
|
|
160
164
|
| --allow-unverified | False | False | Allow unverified packages |
|
|
161
165
|
| --disable-security-issue | False | False | Disable security issue checks |
|
|
162
166
|
|
|
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
|
+
|
|
163
189
|
#### Advanced Configuration
|
|
164
190
|
| Parameter | Required | Default | Description |
|
|
165
191
|
|:-------------------------|:---------|:--------|:----------------------------------------------------------------------|
|
|
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "socketsecurity"
|
|
9
|
-
version = "2.2.
|
|
9
|
+
version = "2.2.22"
|
|
10
10
|
requires-python = ">= 3.10"
|
|
11
11
|
license = {"file" = "LICENSE"}
|
|
12
12
|
dependencies = [
|
|
@@ -16,7 +16,8 @@ dependencies = [
|
|
|
16
16
|
'GitPython',
|
|
17
17
|
'packaging',
|
|
18
18
|
'python-dotenv',
|
|
19
|
-
'socketdev>=3.0.
|
|
19
|
+
'socketdev>=3.0.16,<4.0.0',
|
|
20
|
+
"bs4>=0.0.2",
|
|
20
21
|
]
|
|
21
22
|
readme = "README.md"
|
|
22
23
|
description = "Socket Security CLI for CI/CD"
|
|
@@ -158,4 +159,4 @@ docstring-code-format = false
|
|
|
158
159
|
docstring-code-line-length = "dynamic"
|
|
159
160
|
|
|
160
161
|
[tool.hatch.build.targets.wheel]
|
|
161
|
-
include = ["socketsecurity", "LICENSE"]
|
|
162
|
+
include = ["socketsecurity", "LICENSE"]
|
|
@@ -62,7 +62,19 @@ class CliConfig:
|
|
|
62
62
|
save_manifest_tar: Optional[str] = None
|
|
63
63
|
sub_paths: List[str] = field(default_factory=list)
|
|
64
64
|
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
|
+
|
|
66
78
|
@classmethod
|
|
67
79
|
def from_args(cls, args_list: Optional[List[str]] = None) -> 'CliConfig':
|
|
68
80
|
parser = create_argument_parser()
|
|
@@ -110,6 +122,17 @@ class CliConfig:
|
|
|
110
122
|
'save_manifest_tar': args.save_manifest_tar,
|
|
111
123
|
'sub_paths': args.sub_paths or [],
|
|
112
124
|
'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,
|
|
113
136
|
'version': __version__
|
|
114
137
|
}
|
|
115
138
|
try:
|
|
@@ -141,6 +164,11 @@ class CliConfig:
|
|
|
141
164
|
logging.error("--workspace-name requires --sub-path to be specified")
|
|
142
165
|
exit(1)
|
|
143
166
|
|
|
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
|
+
|
|
144
172
|
return cls(**config_args)
|
|
145
173
|
|
|
146
174
|
def to_dict(self) -> dict:
|
|
@@ -474,6 +502,78 @@ def create_argument_parser() -> argparse.ArgumentParser:
|
|
|
474
502
|
help="Enabling including module folders like node_modules"
|
|
475
503
|
)
|
|
476
504
|
|
|
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
|
+
|
|
477
577
|
parser.add_argument(
|
|
478
578
|
'--version',
|
|
479
579
|
action='version',
|
|
@@ -97,8 +97,7 @@ class Git:
|
|
|
97
97
|
else:
|
|
98
98
|
# Try to get branch name from git properties
|
|
99
99
|
try:
|
|
100
|
-
self.branch = self.head.reference
|
|
101
|
-
urllib.parse.unquote(str(self.branch))
|
|
100
|
+
self.branch = urllib.parse.unquote(str(self.head.reference))
|
|
102
101
|
log.debug(f"Branch detected from git reference: {self.branch}")
|
|
103
102
|
except Exception as error:
|
|
104
103
|
log.debug(f"Failed to get branch from git reference: {error}")
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
from socketdev import socketdev
|
|
2
|
+
from typing import List, Optional, Dict, Any
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
import json
|
|
6
|
+
import pathlib
|
|
7
|
+
import logging
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
log = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ReachabilityAnalyzer:
|
|
14
|
+
def __init__(self, sdk: socketdev, api_token: str):
|
|
15
|
+
self.sdk = sdk
|
|
16
|
+
self.api_token = api_token
|
|
17
|
+
|
|
18
|
+
def _ensure_coana_cli_installed(self, version: Optional[str] = None) -> str:
|
|
19
|
+
"""
|
|
20
|
+
Check if @coana-tech/cli is installed, and install/update it if needed.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
version: Specific version to install (e.g., '1.2.3'). If None, updates to latest.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
str: The package specifier to use with npx
|
|
27
|
+
"""
|
|
28
|
+
# Determine the package specifier
|
|
29
|
+
package_spec = f"@coana-tech/cli@{version}" if version else "@coana-tech/cli"
|
|
30
|
+
|
|
31
|
+
# If a specific version is requested, check if it's already installed
|
|
32
|
+
if version:
|
|
33
|
+
try:
|
|
34
|
+
check_cmd = ["npm", "list", "-g", "@coana-tech/cli", "--depth=0"]
|
|
35
|
+
result = subprocess.run(
|
|
36
|
+
check_cmd,
|
|
37
|
+
capture_output=True,
|
|
38
|
+
text=True,
|
|
39
|
+
timeout=10
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# If npm list succeeds and mentions the specific version, it's installed
|
|
43
|
+
if result.returncode == 0 and f"@coana-tech/cli@{version}" in result.stdout:
|
|
44
|
+
log.debug(f"@coana-tech/cli@{version} is already installed globally")
|
|
45
|
+
return package_spec
|
|
46
|
+
|
|
47
|
+
except Exception as e:
|
|
48
|
+
log.debug(f"Could not check for existing @coana-tech/cli installation: {e}")
|
|
49
|
+
|
|
50
|
+
# Install or update the package
|
|
51
|
+
if version:
|
|
52
|
+
log.info(f"Installing reachability analysis plugin (@coana-tech/cli@{version})...")
|
|
53
|
+
else:
|
|
54
|
+
log.info("Updating reachability analysis plugin (@coana-tech/cli) to latest version...")
|
|
55
|
+
log.info("This may take a moment...")
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
install_cmd = ["npm", "install", "-g", package_spec]
|
|
59
|
+
log.debug(f"Installing with command: {' '.join(install_cmd)}")
|
|
60
|
+
|
|
61
|
+
result = subprocess.run(
|
|
62
|
+
install_cmd,
|
|
63
|
+
capture_output=True,
|
|
64
|
+
text=True,
|
|
65
|
+
timeout=300 # 5 minute timeout for installation
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
if result.returncode != 0:
|
|
69
|
+
log.warning(f"Global installation failed, npx will download on demand")
|
|
70
|
+
log.debug(f"Install stderr: {result.stderr}")
|
|
71
|
+
else:
|
|
72
|
+
log.info("Reachability analysis plugin installed successfully")
|
|
73
|
+
|
|
74
|
+
except subprocess.TimeoutExpired:
|
|
75
|
+
log.warning("Installation timed out, npx will download on demand")
|
|
76
|
+
except Exception as e:
|
|
77
|
+
log.warning(f"Could not install globally: {e}, npx will download on demand")
|
|
78
|
+
|
|
79
|
+
return package_spec
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def run_reachability_analysis(
|
|
83
|
+
self,
|
|
84
|
+
org_slug: str,
|
|
85
|
+
target_directory: str,
|
|
86
|
+
tar_hash: Optional[str] = None,
|
|
87
|
+
output_path: str = ".socket.facts.json",
|
|
88
|
+
timeout: Optional[int] = None,
|
|
89
|
+
memory_limit: Optional[int] = None,
|
|
90
|
+
ecosystems: Optional[List[str]] = None,
|
|
91
|
+
exclude_paths: Optional[List[str]] = None,
|
|
92
|
+
min_severity: Optional[str] = None,
|
|
93
|
+
skip_cache: bool = False,
|
|
94
|
+
disable_analytics: bool = False,
|
|
95
|
+
repo_name: Optional[str] = None,
|
|
96
|
+
branch_name: Optional[str] = None,
|
|
97
|
+
version: Optional[str] = None,
|
|
98
|
+
) -> Dict[str, Any]:
|
|
99
|
+
"""
|
|
100
|
+
Run reachability analysis.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
org_slug: Socket organization slug
|
|
104
|
+
target_directory: Directory to analyze
|
|
105
|
+
tar_hash: Tar hash from manifest upload or existing scan (optional)
|
|
106
|
+
output_path: Output file path for results
|
|
107
|
+
timeout: Analysis timeout in seconds
|
|
108
|
+
memory_limit: Memory limit in MB
|
|
109
|
+
ecosystems: List of ecosystems to analyze (e.g., ['npm', 'pypi'])
|
|
110
|
+
exclude_paths: Paths to exclude from analysis
|
|
111
|
+
min_severity: Minimum severity level (info, low, moderate, high, critical)
|
|
112
|
+
skip_cache: Skip cache usage
|
|
113
|
+
disable_analytics: Disable analytics sharing
|
|
114
|
+
repo_name: Repository name
|
|
115
|
+
branch_name: Branch name
|
|
116
|
+
version: Specific version of @coana-tech/cli to use
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Dict containing scan_id and report_path
|
|
120
|
+
"""
|
|
121
|
+
# Ensure @coana-tech/cli is installed
|
|
122
|
+
cli_package = self._ensure_coana_cli_installed(version)
|
|
123
|
+
|
|
124
|
+
# Build CLI command arguments
|
|
125
|
+
cmd = ["npx", cli_package, "run", target_directory]
|
|
126
|
+
|
|
127
|
+
# Add required arguments
|
|
128
|
+
output_dir = str(pathlib.Path(output_path).parent)
|
|
129
|
+
cmd.extend([
|
|
130
|
+
"--output-dir", output_dir,
|
|
131
|
+
"--socket-mode", output_path,
|
|
132
|
+
"--disable-report-submission"
|
|
133
|
+
])
|
|
134
|
+
|
|
135
|
+
# Add conditional arguments
|
|
136
|
+
if timeout:
|
|
137
|
+
cmd.extend(["--analysis-timeout", str(timeout)])
|
|
138
|
+
|
|
139
|
+
if memory_limit:
|
|
140
|
+
cmd.extend(["--memory-limit", str(memory_limit)])
|
|
141
|
+
|
|
142
|
+
if disable_analytics:
|
|
143
|
+
cmd.append("--disable-analytics-sharing")
|
|
144
|
+
|
|
145
|
+
# KEY POINT: Only add manifest tar hash if we have one
|
|
146
|
+
if tar_hash:
|
|
147
|
+
cmd.extend(["--run-without-docker", "--manifests-tar-hash", tar_hash])
|
|
148
|
+
|
|
149
|
+
if ecosystems:
|
|
150
|
+
cmd.extend(["--purl-types"] + ecosystems)
|
|
151
|
+
|
|
152
|
+
if exclude_paths:
|
|
153
|
+
cmd.extend(["--exclude-dirs"] + exclude_paths)
|
|
154
|
+
|
|
155
|
+
if min_severity:
|
|
156
|
+
cmd.extend(["--min-severity", min_severity])
|
|
157
|
+
|
|
158
|
+
if skip_cache:
|
|
159
|
+
cmd.append("--skip-cache-usage")
|
|
160
|
+
|
|
161
|
+
# Set up environment variables
|
|
162
|
+
env = os.environ.copy()
|
|
163
|
+
|
|
164
|
+
# Required environment variables for Coana CLI
|
|
165
|
+
env["SOCKET_ORG_SLUG"] = org_slug
|
|
166
|
+
env["SOCKET_CLI_API_TOKEN"] = self.api_token
|
|
167
|
+
|
|
168
|
+
# Optional environment variables
|
|
169
|
+
if repo_name:
|
|
170
|
+
env["SOCKET_REPO_NAME"] = repo_name
|
|
171
|
+
|
|
172
|
+
if branch_name:
|
|
173
|
+
env["SOCKET_BRANCH_NAME"] = branch_name
|
|
174
|
+
|
|
175
|
+
# Execute CLI
|
|
176
|
+
log.info("Running reachability analysis...")
|
|
177
|
+
log.debug(f"Reachability command: {' '.join(cmd)}")
|
|
178
|
+
log.debug(f"Environment: SOCKET_ORG_SLUG={org_slug}, SOCKET_REPO_NAME={repo_name or 'not set'}, SOCKET_BRANCH_NAME={branch_name or 'not set'}")
|
|
179
|
+
|
|
180
|
+
try:
|
|
181
|
+
# Run with output streaming to stderr (don't capture output)
|
|
182
|
+
result = subprocess.run(
|
|
183
|
+
cmd,
|
|
184
|
+
env=env,
|
|
185
|
+
cwd=os.getcwd(),
|
|
186
|
+
stdout=sys.stderr, # Send stdout to stderr so user sees it
|
|
187
|
+
stderr=sys.stderr, # Send stderr to stderr
|
|
188
|
+
timeout=timeout + 60 if timeout else None # Add buffer to subprocess timeout
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
if result.returncode != 0:
|
|
192
|
+
log.error(f"Reachability analysis failed with exit code {result.returncode}")
|
|
193
|
+
raise Exception(f"Reachability analysis failed with exit code {result.returncode}")
|
|
194
|
+
|
|
195
|
+
# Extract scan ID from output file
|
|
196
|
+
scan_id = self._extract_scan_id(output_path)
|
|
197
|
+
|
|
198
|
+
log.info(f"Reachability analysis completed successfully")
|
|
199
|
+
if scan_id:
|
|
200
|
+
log.info(f"Scan ID: {scan_id}")
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
"scan_id": scan_id,
|
|
204
|
+
"report_path": output_path,
|
|
205
|
+
"tar_hash_used": tar_hash
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
except subprocess.TimeoutExpired:
|
|
209
|
+
log.error(f"Reachability analysis timed out after {timeout} seconds")
|
|
210
|
+
raise Exception(f"Reachability analysis timed out after {timeout} seconds")
|
|
211
|
+
except Exception as e:
|
|
212
|
+
log.error(f"Failed to run reachability analysis: {str(e)}")
|
|
213
|
+
raise Exception(f"Failed to run reachability analysis: {str(e)}")
|
|
214
|
+
|
|
215
|
+
def _extract_scan_id(self, facts_file_path: str) -> Optional[str]:
|
|
216
|
+
"""
|
|
217
|
+
Extract tier1ReachabilityScanId from the socket facts JSON file.
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
facts_file_path: Path to the .socket.facts.json file
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
Optional[str]: The scan ID if found, None otherwise
|
|
224
|
+
"""
|
|
225
|
+
try:
|
|
226
|
+
if not os.path.exists(facts_file_path):
|
|
227
|
+
log.warning(f"Facts file not found: {facts_file_path}")
|
|
228
|
+
return None
|
|
229
|
+
|
|
230
|
+
with open(facts_file_path, 'r') as f:
|
|
231
|
+
facts = json.load(f)
|
|
232
|
+
|
|
233
|
+
scan_id = facts.get('tier1ReachabilityScanId')
|
|
234
|
+
return scan_id.strip() if scan_id else None
|
|
235
|
+
|
|
236
|
+
except (json.JSONDecodeError, IOError) as e:
|
|
237
|
+
log.warning(f"Failed to extract scan ID from {facts_file_path}: {e}")
|
|
238
|
+
return None
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import sys
|
|
3
3
|
import traceback
|
|
4
|
+
import shutil
|
|
4
5
|
|
|
5
6
|
from dotenv import load_dotenv
|
|
6
7
|
from git import InvalidGitRepositoryError, NoSuchPathError
|
|
@@ -75,6 +76,50 @@ def main_code():
|
|
|
75
76
|
log.debug("loaded client")
|
|
76
77
|
core = Core(socket_config, sdk)
|
|
77
78
|
log.debug("loaded core")
|
|
79
|
+
|
|
80
|
+
# Check for required dependencies if reachability analysis is enabled
|
|
81
|
+
if config.reach:
|
|
82
|
+
log.info("Reachability analysis enabled, checking for required dependencies...")
|
|
83
|
+
required_deps = ["npm", "uv", "npx"]
|
|
84
|
+
missing_deps = []
|
|
85
|
+
found_deps = []
|
|
86
|
+
|
|
87
|
+
for dep in required_deps:
|
|
88
|
+
if shutil.which(dep):
|
|
89
|
+
found_deps.append(dep)
|
|
90
|
+
log.debug(f"Found required dependency: {dep}")
|
|
91
|
+
else:
|
|
92
|
+
missing_deps.append(dep)
|
|
93
|
+
|
|
94
|
+
if missing_deps:
|
|
95
|
+
log.error(f"Reachability analysis requires the following dependencies: {', '.join(required_deps)}")
|
|
96
|
+
log.error(f"Missing dependencies: {', '.join(missing_deps)}")
|
|
97
|
+
log.error("Please install the missing dependencies and try again.")
|
|
98
|
+
sys.exit(3)
|
|
99
|
+
|
|
100
|
+
log.info(f"All required dependencies found: {', '.join(found_deps)}")
|
|
101
|
+
|
|
102
|
+
# Check if organization has an enterprise plan
|
|
103
|
+
log.info("Checking organization plan for reachability analysis eligibility...")
|
|
104
|
+
org_response = sdk.org.get(use_types=True)
|
|
105
|
+
organizations = org_response.get("organizations", {})
|
|
106
|
+
|
|
107
|
+
if organizations:
|
|
108
|
+
org_id = next(iter(organizations))
|
|
109
|
+
org_plan = organizations[org_id].get('plan', '')
|
|
110
|
+
|
|
111
|
+
# Check if plan matches enterprise* pattern (enterprise, enterprise_trial, etc.)
|
|
112
|
+
if not org_plan.startswith('enterprise'):
|
|
113
|
+
log.error(f"Reachability analysis is only available for enterprise plans.")
|
|
114
|
+
log.error(f"Your organization plan is: {org_plan}")
|
|
115
|
+
log.error("Please upgrade to an enterprise plan to use reachability analysis.")
|
|
116
|
+
sys.exit(3)
|
|
117
|
+
|
|
118
|
+
log.info(f"Organization plan verified: {org_plan}")
|
|
119
|
+
else:
|
|
120
|
+
log.error("Unable to retrieve organization information for plan verification.")
|
|
121
|
+
sys.exit(3)
|
|
122
|
+
|
|
78
123
|
# Parse files argument
|
|
79
124
|
try:
|
|
80
125
|
if isinstance(config.files, list):
|
|
@@ -112,6 +157,9 @@ def main_code():
|
|
|
112
157
|
# Determine if files were explicitly specified
|
|
113
158
|
files_explicitly_specified = config.files != "[]" and len(specified_files) > 0
|
|
114
159
|
|
|
160
|
+
# Variable to track if we need to override files with facts file
|
|
161
|
+
facts_file_to_submit = None
|
|
162
|
+
|
|
115
163
|
# Git setup
|
|
116
164
|
is_repo = False
|
|
117
165
|
git_repo: Git
|
|
@@ -172,6 +220,85 @@ def main_code():
|
|
|
172
220
|
# If no repo name was set but workspace_name is provided, we'll use it later
|
|
173
221
|
log.debug(f"Workspace name provided: {config.workspace_name}")
|
|
174
222
|
|
|
223
|
+
# Run reachability analysis if enabled
|
|
224
|
+
if config.reach:
|
|
225
|
+
from socketsecurity.core.tools.reachability import ReachabilityAnalyzer
|
|
226
|
+
|
|
227
|
+
log.info("Starting reachability analysis...")
|
|
228
|
+
|
|
229
|
+
# Find manifest files in scan paths (excluding .socket.facts.json to avoid circular dependency)
|
|
230
|
+
log.info("Finding manifest files for reachability analysis...")
|
|
231
|
+
manifest_files = []
|
|
232
|
+
for scan_path in scan_paths:
|
|
233
|
+
scan_manifests = core.find_files(scan_path)
|
|
234
|
+
# Filter out .socket.facts.json files from manifest upload
|
|
235
|
+
scan_manifests = [f for f in scan_manifests if not f.endswith('.socket.facts.json')]
|
|
236
|
+
manifest_files.extend(scan_manifests)
|
|
237
|
+
|
|
238
|
+
if not manifest_files:
|
|
239
|
+
log.warning("No manifest files found for reachability analysis")
|
|
240
|
+
else:
|
|
241
|
+
log.info(f"Found {len(manifest_files)} manifest files for reachability upload")
|
|
242
|
+
|
|
243
|
+
# Upload manifests and get tar hash
|
|
244
|
+
log.info("Uploading manifest files...")
|
|
245
|
+
try:
|
|
246
|
+
# Get org_slug early (we'll need it)
|
|
247
|
+
org_slug = core.config.org_slug
|
|
248
|
+
|
|
249
|
+
# Upload manifest files
|
|
250
|
+
tar_hash = sdk.uploadmanifests.upload_manifest_files(
|
|
251
|
+
org_slug=org_slug,
|
|
252
|
+
file_paths=manifest_files,
|
|
253
|
+
workspace=config.repo or "default-workspace",
|
|
254
|
+
base_path=None,
|
|
255
|
+
base_paths=base_paths,
|
|
256
|
+
use_lazy_loading=False
|
|
257
|
+
)
|
|
258
|
+
log.info(f"Manifest upload successful, tar hash: {tar_hash}")
|
|
259
|
+
|
|
260
|
+
# Initialize and run reachability analyzer
|
|
261
|
+
analyzer = ReachabilityAnalyzer(sdk, config.api_token)
|
|
262
|
+
|
|
263
|
+
# Determine output path
|
|
264
|
+
output_path = config.reach_output_file or ".socket.facts.json"
|
|
265
|
+
|
|
266
|
+
# Run the analysis
|
|
267
|
+
result = analyzer.run_reachability_analysis(
|
|
268
|
+
org_slug=org_slug,
|
|
269
|
+
target_directory=config.target_path,
|
|
270
|
+
tar_hash=tar_hash,
|
|
271
|
+
output_path=output_path,
|
|
272
|
+
timeout=config.reach_analysis_timeout,
|
|
273
|
+
memory_limit=config.reach_analysis_memory_limit,
|
|
274
|
+
ecosystems=config.reach_ecosystems,
|
|
275
|
+
exclude_paths=config.reach_exclude_paths,
|
|
276
|
+
min_severity=config.reach_min_severity,
|
|
277
|
+
skip_cache=config.reach_skip_cache or False,
|
|
278
|
+
disable_analytics=config.reach_disable_analytics or False,
|
|
279
|
+
repo_name=config.repo,
|
|
280
|
+
branch_name=config.branch,
|
|
281
|
+
version=config.reach_version
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
log.info(f"Reachability analysis completed successfully")
|
|
285
|
+
log.info(f"Results written to: {result['report_path']}")
|
|
286
|
+
if result.get('scan_id'):
|
|
287
|
+
log.info(f"Reachability scan ID: {result['scan_id']}")
|
|
288
|
+
|
|
289
|
+
# If only-facts-file mode, mark the facts file for submission
|
|
290
|
+
if config.only_facts_file:
|
|
291
|
+
import os
|
|
292
|
+
facts_file_to_submit = os.path.abspath(output_path)
|
|
293
|
+
log.info(f"Only-facts-file mode: will submit only {facts_file_to_submit}")
|
|
294
|
+
|
|
295
|
+
except Exception as e:
|
|
296
|
+
log.error(f"Reachability analysis failed: {str(e)}")
|
|
297
|
+
if not config.disable_blocking:
|
|
298
|
+
sys.exit(3)
|
|
299
|
+
|
|
300
|
+
log.info("Continuing with normal scan flow...")
|
|
301
|
+
|
|
175
302
|
scm = None
|
|
176
303
|
if config.scm == "github":
|
|
177
304
|
from socketsecurity.core.scm.github import Github, GithubConfig
|
|
@@ -188,6 +315,12 @@ def main_code():
|
|
|
188
315
|
if scm is not None and not config.default_branch:
|
|
189
316
|
config.default_branch = scm.config.is_default_branch
|
|
190
317
|
|
|
318
|
+
# Override files if only-facts-file mode is active
|
|
319
|
+
if facts_file_to_submit:
|
|
320
|
+
specified_files = [facts_file_to_submit]
|
|
321
|
+
files_explicitly_specified = True
|
|
322
|
+
log.debug(f"Overriding files to only submit facts file: {facts_file_to_submit}")
|
|
323
|
+
|
|
191
324
|
# Determine files to check based on the new logic
|
|
192
325
|
files_to_check = []
|
|
193
326
|
force_api_mode = False
|
|
@@ -282,7 +415,8 @@ def main_code():
|
|
|
282
415
|
pull_request=pr_number,
|
|
283
416
|
committers=config.committers,
|
|
284
417
|
make_default_branch=is_default_branch,
|
|
285
|
-
set_as_pending_head=is_default_branch
|
|
418
|
+
set_as_pending_head=is_default_branch,
|
|
419
|
+
tmp=False
|
|
286
420
|
)
|
|
287
421
|
|
|
288
422
|
params.include_license_details = not config.exclude_license_details
|
|
@@ -35,6 +35,31 @@ wheels = [
|
|
|
35
35
|
{ url = "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", size = 30181, upload-time = "2024-05-28T17:01:53.112Z" },
|
|
36
36
|
]
|
|
37
37
|
|
|
38
|
+
[[package]]
|
|
39
|
+
name = "beautifulsoup4"
|
|
40
|
+
version = "4.14.2"
|
|
41
|
+
source = { registry = "https://pypi.org/simple" }
|
|
42
|
+
dependencies = [
|
|
43
|
+
{ name = "soupsieve" },
|
|
44
|
+
{ name = "typing-extensions" },
|
|
45
|
+
]
|
|
46
|
+
sdist = { url = "https://files.pythonhosted.org/packages/77/e9/df2358efd7659577435e2177bfa69cba6c33216681af51a707193dec162a/beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e", size = 625822, upload-time = "2025-09-29T10:05:42.613Z" }
|
|
47
|
+
wheels = [
|
|
48
|
+
{ url = "https://files.pythonhosted.org/packages/94/fe/3aed5d0be4d404d12d36ab97e2f1791424d9ca39c2f754a6285d59a3b01d/beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515", size = 106392, upload-time = "2025-09-29T10:05:43.771Z" },
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[[package]]
|
|
52
|
+
name = "bs4"
|
|
53
|
+
version = "0.0.2"
|
|
54
|
+
source = { registry = "https://pypi.org/simple" }
|
|
55
|
+
dependencies = [
|
|
56
|
+
{ name = "beautifulsoup4" },
|
|
57
|
+
]
|
|
58
|
+
sdist = { url = "https://files.pythonhosted.org/packages/c9/aa/4acaf814ff901145da37332e05bb510452ebed97bc9602695059dd46ef39/bs4-0.0.2.tar.gz", hash = "sha256:a48685c58f50fe127722417bae83fe6badf500d54b55f7e39ffe43b798653925", size = 698, upload-time = "2024-01-17T18:15:47.371Z" }
|
|
59
|
+
wheels = [
|
|
60
|
+
{ url = "https://files.pythonhosted.org/packages/51/bb/bf7aab772a159614954d84aa832c129624ba6c32faa559dfb200a534e50b/bs4-0.0.2-py2.py3-none-any.whl", hash = "sha256:abf8742c0805ef7f662dce4b51cca104cffe52b835238afc169142ab9b3fbccc", size = 1189, upload-time = "2024-01-17T18:15:48.613Z" },
|
|
61
|
+
]
|
|
62
|
+
|
|
38
63
|
[[package]]
|
|
39
64
|
name = "certifi"
|
|
40
65
|
version = "2025.8.3"
|
|
@@ -1027,22 +1052,23 @@ wheels = [
|
|
|
1027
1052
|
|
|
1028
1053
|
[[package]]
|
|
1029
1054
|
name = "socketdev"
|
|
1030
|
-
version = "3.0.
|
|
1055
|
+
version = "3.0.16"
|
|
1031
1056
|
source = { registry = "https://pypi.org/simple" }
|
|
1032
1057
|
dependencies = [
|
|
1033
1058
|
{ name = "requests" },
|
|
1034
1059
|
{ name = "typing-extensions" },
|
|
1035
1060
|
]
|
|
1036
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
1061
|
+
sdist = { url = "https://files.pythonhosted.org/packages/02/0d/6da0e0c34b97eef3a926d55470fa4bda2fcbbc42cc9e26ac51a34c6f117d/socketdev-3.0.16.tar.gz", hash = "sha256:5145300945e4e8d2d7f71db9c55cb44cc1449874f9d6416cc1d6ec129c64d638", size = 132505, upload-time = "2025-11-07T03:24:16.231Z" }
|
|
1037
1062
|
wheels = [
|
|
1038
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1063
|
+
{ url = "https://files.pythonhosted.org/packages/a3/91/8486b2a62ba71d62a8f4f2f9ad22c61fcaabb461c5f269bbe0734eae76f9/socketdev-3.0.16-py3-none-any.whl", hash = "sha256:f5e413f5f2f8c0c938d5654da7f0a157c0be02a25e14d94af62c252e9fb3b502", size = 58567, upload-time = "2025-11-07T03:24:14.965Z" },
|
|
1039
1064
|
]
|
|
1040
1065
|
|
|
1041
1066
|
[[package]]
|
|
1042
1067
|
name = "socketsecurity"
|
|
1043
|
-
version = "2.2.
|
|
1068
|
+
version = "2.2.18"
|
|
1044
1069
|
source = { editable = "." }
|
|
1045
1070
|
dependencies = [
|
|
1071
|
+
{ name = "bs4" },
|
|
1046
1072
|
{ name = "gitpython" },
|
|
1047
1073
|
{ name = "mdutils" },
|
|
1048
1074
|
{ name = "packaging" },
|
|
@@ -1070,6 +1096,7 @@ test = [
|
|
|
1070
1096
|
|
|
1071
1097
|
[package.metadata]
|
|
1072
1098
|
requires-dist = [
|
|
1099
|
+
{ name = "bs4", specifier = ">=0.0.2" },
|
|
1073
1100
|
{ name = "gitpython" },
|
|
1074
1101
|
{ name = "hatch", marker = "extra == 'dev'" },
|
|
1075
1102
|
{ name = "mdutils" },
|
|
@@ -1084,12 +1111,21 @@ requires-dist = [
|
|
|
1084
1111
|
{ name = "python-dotenv" },
|
|
1085
1112
|
{ name = "requests" },
|
|
1086
1113
|
{ name = "ruff", marker = "extra == 'dev'", specifier = ">=0.3.0" },
|
|
1087
|
-
{ name = "socketdev", specifier = ">=3.0.
|
|
1114
|
+
{ name = "socketdev", specifier = ">=3.0.16,<4.0.0" },
|
|
1088
1115
|
{ name = "twine", marker = "extra == 'dev'" },
|
|
1089
1116
|
{ name = "uv", marker = "extra == 'dev'", specifier = ">=0.1.0" },
|
|
1090
1117
|
]
|
|
1091
1118
|
provides-extras = ["test", "dev"]
|
|
1092
1119
|
|
|
1120
|
+
[[package]]
|
|
1121
|
+
name = "soupsieve"
|
|
1122
|
+
version = "2.8"
|
|
1123
|
+
source = { registry = "https://pypi.org/simple" }
|
|
1124
|
+
sdist = { url = "https://files.pythonhosted.org/packages/6d/e6/21ccce3262dd4889aa3332e5a119a3491a95e8f60939870a3a035aabac0d/soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f", size = 103472, upload-time = "2025-08-27T15:39:51.78Z" }
|
|
1125
|
+
wheels = [
|
|
1126
|
+
{ url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679, upload-time = "2025-08-27T15:39:50.179Z" },
|
|
1127
|
+
]
|
|
1128
|
+
|
|
1093
1129
|
[[package]]
|
|
1094
1130
|
name = "tomli"
|
|
1095
1131
|
version = "2.2.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{socketsecurity-2.2.15 → socketsecurity-2.2.22}/.github/PULL_REQUEST_TEMPLATE/improvement.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/fullscans/diff/stream_diff_full.json
RENAMED
|
File without changes
|
{socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/fullscans/head_scan/metadata.json
RENAMED
|
File without changes
|
{socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/fullscans/head_scan/stream_scan.json
RENAMED
|
File without changes
|
{socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/fullscans/head_scan/stream_scan_full.json
RENAMED
|
File without changes
|
|
File without changes
|
{socketsecurity-2.2.15 → socketsecurity-2.2.22}/tests/data/fullscans/new_scan/stream_scan.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|