socketsecurity 2.4.8__tar.gz → 2.4.10__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.
Files changed (152) hide show
  1. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/CHANGELOG.md +23 -0
  2. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/PKG-INFO +1 -1
  3. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/docs/cli-reference.md +3 -2
  4. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/pyproject.toml +1 -1
  5. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/__init__.py +1 -1
  6. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/config.py +37 -0
  7. socketsecurity-2.4.10/socketsecurity/core/cli_run.py +79 -0
  8. socketsecurity-2.4.10/socketsecurity/core/log_uploader.py +112 -0
  9. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/socket_config.py +4 -0
  10. socketsecurity-2.4.10/socketsecurity/core/streaming.py +112 -0
  11. socketsecurity-2.4.10/socketsecurity/socketcli.py +924 -0
  12. socketsecurity-2.4.10/tests/unit/test_cli_run.py +125 -0
  13. socketsecurity-2.4.10/tests/unit/test_include_dirs.py +99 -0
  14. socketsecurity-2.4.10/tests/unit/test_log_uploader.py +192 -0
  15. socketsecurity-2.4.10/tests/unit/test_streaming.py +123 -0
  16. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/uv.lock +1 -1
  17. socketsecurity-2.4.8/socketsecurity/socketcli.py +0 -899
  18. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/CODEOWNERS +0 -0
  19. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/PULL_REQUEST_TEMPLATE/bug-fix.md +0 -0
  20. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/PULL_REQUEST_TEMPLATE/feature.md +0 -0
  21. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/PULL_REQUEST_TEMPLATE/improvement.md +0 -0
  22. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  23. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/actions/setup-docker/action.yml +0 -0
  24. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/actions/setup-hatch/action.yml +0 -0
  25. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/actions/setup-sfw/action.yml +0 -0
  26. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/dependabot.yml +0 -0
  27. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/workflows/dependency-review.yml +0 -0
  28. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/workflows/docker-stable.yml +0 -0
  29. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/workflows/e2e-test.yml +0 -0
  30. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/workflows/pr-preview.yml +0 -0
  31. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/workflows/python-tests.yml +0 -0
  32. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/workflows/release.yml +0 -0
  33. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/workflows/version-check.yml +0 -0
  34. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.github/zizmor.yml +0 -0
  35. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.gitignore +0 -0
  36. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.hooks/sync_version.py +0 -0
  37. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.pre-commit-config.yaml +0 -0
  38. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/.python-version +0 -0
  39. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/Dockerfile +0 -0
  40. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/LICENSE +0 -0
  41. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/Makefile +0 -0
  42. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/README.md +0 -0
  43. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/docs/ci-cd.md +0 -0
  44. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/docs/development.md +0 -0
  45. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/docs/troubleshooting.md +0 -0
  46. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/examples/config/sarif-dashboard-parity.json +0 -0
  47. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/examples/config/sarif-dashboard-parity.toml +0 -0
  48. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/examples/config/sarif-diff-ci-cd.json +0 -0
  49. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/examples/config/sarif-diff-ci-cd.toml +0 -0
  50. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/examples/config/sarif-instance-detail.json +0 -0
  51. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/examples/config/sarif-instance-detail.toml +0 -0
  52. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/instructions/gitlab-commit-status/uat.md +0 -0
  53. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/pytest.ini +0 -0
  54. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/scripts/build_container.sh +0 -0
  55. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/scripts/build_container_flexible.sh +0 -0
  56. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/scripts/deploy-test-docker.sh +0 -0
  57. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/scripts/deploy-test-pypi.sh +0 -0
  58. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/scripts/docker-entrypoint.sh +0 -0
  59. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/scripts/run.sh +0 -0
  60. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/session.md +0 -0
  61. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socket.yml +0 -0
  62. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/__init__.py +0 -0
  63. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/alert_selection.py +0 -0
  64. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/classes.py +0 -0
  65. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/cli_client.py +0 -0
  66. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/exceptions.py +0 -0
  67. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/git_interface.py +0 -0
  68. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/helper/__init__.py +0 -0
  69. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/helper/socket_facts_loader.py +0 -0
  70. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/lazy_file_loader.py +0 -0
  71. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/logging.py +0 -0
  72. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/messages.py +0 -0
  73. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/resource_utils.py +0 -0
  74. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/scm/__init__.py +0 -0
  75. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/scm/base.py +0 -0
  76. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/scm/client.py +0 -0
  77. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/scm/github.py +0 -0
  78. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/scm/gitlab.py +0 -0
  79. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/scm_comments.py +0 -0
  80. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/tools/reachability.py +0 -0
  81. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/core/utils.py +0 -0
  82. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/fossa_compat.py +0 -0
  83. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/output.py +0 -0
  84. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/plugins/__init__.py +0 -0
  85. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/plugins/base.py +0 -0
  86. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/plugins/formatters/__init__.py +0 -0
  87. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/plugins/formatters/slack.py +0 -0
  88. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/plugins/jira.py +0 -0
  89. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/plugins/manager.py +0 -0
  90. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/plugins/slack.py +0 -0
  91. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/plugins/teams.py +0 -0
  92. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/socketsecurity/plugins/webhook.py +0 -0
  93. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/__init__.py +0 -0
  94. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/core/conftest.py +0 -0
  95. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/core/create_diff_input.json +0 -0
  96. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/core/test_diff_alerts.py +0 -0
  97. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/core/test_diff_generation.py +0 -0
  98. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/core/test_facts_compression.py +0 -0
  99. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/core/test_has_manifest_files.py +0 -0
  100. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/core/test_package_and_alerts.py +0 -0
  101. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/core/test_sdk_methods.py +0 -0
  102. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/core/test_supporting_methods.py +0 -0
  103. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/data/fullscans/create_response.json +0 -0
  104. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/data/fullscans/diff/stream_diff.json +0 -0
  105. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/data/fullscans/diff/stream_diff_full.json +0 -0
  106. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/data/fullscans/head_scan/metadata.json +0 -0
  107. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/data/fullscans/head_scan/stream_scan.json +0 -0
  108. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/data/fullscans/head_scan/stream_scan_full.json +0 -0
  109. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/data/fullscans/new_scan/metadata.json +0 -0
  110. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/data/fullscans/new_scan/stream_scan.json +0 -0
  111. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/data/repos/repo_info_error.json +0 -0
  112. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/data/repos/repo_info_no_head.json +0 -0
  113. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/data/repos/repo_info_success.json +0 -0
  114. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/data/settings/security-policy.json +0 -0
  115. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/e2e/fixtures/simple-npm/index.js +0 -0
  116. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/e2e/fixtures/simple-npm/package.json +0 -0
  117. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/e2e/fixtures/simple-pypi/requirements.txt +0 -0
  118. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/e2e/validate-gitlab.sh +0 -0
  119. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/e2e/validate-json.sh +0 -0
  120. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/e2e/validate-reachability.sh +0 -0
  121. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/e2e/validate-sarif.sh +0 -0
  122. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/e2e/validate-scan.sh +0 -0
  123. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/fixtures/fossa/README.md +0 -0
  124. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/fixtures/fossa/fossa-analyze-empty.json +0 -0
  125. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/fixtures/fossa/fossa-analyze-populated.json +0 -0
  126. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/fixtures/fossa/fossa-sbom-empty-deep.json +0 -0
  127. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/fixtures/fossa/fossa-sbom-populated.json +0 -0
  128. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/__init__.py +0 -0
  129. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_alert_selection.py +0 -0
  130. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_cli_config.py +0 -0
  131. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_client.py +0 -0
  132. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_config.py +0 -0
  133. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_dependency_overview.py +0 -0
  134. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_disable_ignore.py +0 -0
  135. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_exclude_paths.py +0 -0
  136. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_fossa_compat.py +0 -0
  137. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_fossa_parity.py +0 -0
  138. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_full_scan_retry.py +0 -0
  139. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_gitlab_auth.py +0 -0
  140. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_gitlab_auth_fallback.py +0 -0
  141. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_gitlab_commit_status.py +0 -0
  142. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_gitlab_format.py +0 -0
  143. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_ignore_telemetry_filtering.py +0 -0
  144. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_output.py +0 -0
  145. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_reachability.py +0 -0
  146. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_slack_plugin.py +0 -0
  147. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_socketcli.py +0 -0
  148. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/tests/unit/test_tier1_finalize.py +0 -0
  149. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/workflows/bitbucket-pipelines.yml +0 -0
  150. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/workflows/buildkite.yml +0 -0
  151. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/workflows/github-actions.yml +0 -0
  152. {socketsecurity-2.4.8 → socketsecurity-2.4.10}/workflows/gitlab-ci.yml +0 -0
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.4.10
4
+
5
+ ### Added: opt directories back into manifest discovery via `--include-dirs`
6
+
7
+ - New `--include-dirs` flag (comma-separated directory names) that re-includes directories
8
+ the CLI excludes from manifest discovery by default. The default exclude list
9
+ (`node_modules`, `bower_components`, `jspm_packages`, `__pycache__`, `.venv`, `venv`,
10
+ `build`, `dist`, `.tox`, `.mypy_cache`, `.pytest_cache`, `*.egg-info`, `vendor`) is a sane
11
+ default, but some projects keep manifest files under those names — e.g. `build/requirements.txt`.
12
+ Pass `--include-dirs build,dist` to scan them. Names are matched against any path segment,
13
+ mirroring how the default exclude list is applied.
14
+ - `--include-module-folders` now functions as documented: it re-includes the JS/TS module
15
+ folders (`node_modules`, `bower_components`, `jspm_packages`) as a group. Previously the
16
+ flag was accepted but had no effect.
17
+
18
+ ## 2.4.9
19
+
20
+ ### Added: opt-in streaming log channel via `--upload-logs`
21
+
22
+ - New `--upload-logs` flag (default off). When set, each CLI invocation registers a run, reports a per-run status (`in_progress` / `success` / `failure` / `cancelled`), and uploads a transcript of its own log output to the Socket backend for that run, visible in the Socket admin views. The transcript is captured regardless of the local `--enable-debug` state; the existing terminal verbosity is unchanged.
23
+ - New `--no-upload-logs` flag (mutually exclusive with `--upload-logs`) explicitly opts the run out of uploading logs, even when an org-level override would otherwise enable it. Use this when you need a guaranteed no-upload guarantee (e.g. legal/consent reasons).
24
+ - The Socket backend can also force-enable streaming for specific orgs in the absence of an explicit opt-out. The feature is best-effort — registration or upload failures silently degrade and never block the scan.
25
+
3
26
  ## 2.4.8
4
27
 
5
28
  ### Fixed: retry transient full-scan upload failures
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: socketsecurity
3
- Version: 2.4.8
3
+ Version: 2.4.10
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>
@@ -148,7 +148,7 @@ socketcli [-h] [--api-token API_TOKEN] [--repo REPO] [--workspace WORKSPACE] [--
148
148
  [--owner OWNER] [--pr-number PR_NUMBER] [--commit-message COMMIT_MESSAGE] [--commit-sha COMMIT_SHA] [--committers [COMMITTERS ...]]
149
149
  [--target-path TARGET_PATH] [--sbom-file SBOM_FILE] [--license-file-name LICENSE_FILE_NAME] [--save-submitted-files-list SAVE_SUBMITTED_FILES_LIST]
150
150
  [--save-manifest-tar SAVE_MANIFEST_TAR] [--files FILES] [--sub-path SUB_PATH] [--workspace-name WORKSPACE_NAME]
151
- [--excluded-ecosystems EXCLUDED_ECOSYSTEMS] [--exclude-paths EXCLUDE_PATHS] [--default-branch] [--pending-head] [--generate-license] [--enable-debug]
151
+ [--excluded-ecosystems EXCLUDED_ECOSYSTEMS] [--exclude-paths EXCLUDE_PATHS] [--include-dirs INCLUDE_DIRS] [--default-branch] [--pending-head] [--generate-license] [--enable-debug]
152
152
  [--enable-json] [--enable-sarif] [--sarif-file <path>] [--sarif-scope {diff,full}] [--sarif-grouping {instance,alert}] [--sarif-reachability {all,reachable,potentially,reachable-or-potentially}] [--enable-gitlab-security] [--gitlab-security-file <path>]
153
153
  [--disable-overview] [--exclude-license-details] [--allow-unverified] [--disable-security-issue]
154
154
  [--ignore-commit-files] [--disable-blocking] [--disable-ignore] [--enable-diff] [--scm SCM] [--timeout TIMEOUT] [--include-module-folders]
@@ -205,13 +205,14 @@ If you don't want to provide the Socket API Token every time then you can use th
205
205
  | `--workspace-name` | False | | Workspace name suffix to append to repository name (repo-name-workspace_name). Must be used with `--sub-path` |
206
206
  | `--excluded-ecosystems` | False | [] | List of ecosystems to exclude from analysis (JSON array string). You can get supported files from the [Supported Files API](https://docs.socket.dev/reference/getsupportedfiles) |
207
207
  | `--exclude-paths` | False | | Comma-separated paths/globs to exclude from **both** manifest discovery (every scan) **and** reachability analysis (e.g. `tests/**,packages/legacy,*.spec.ts`). Patterns are scan-root-relative, case-sensitive globs where `*` does not cross `/` and `**` does. Supersedes `--reach-exclude-paths`. |
208
+ | `--include-dirs` | False | | Comma-separated directory **names** that are excluded from manifest discovery by default but should be scanned (e.g. `build,dist`). Names are matched against any path segment, mirroring the default exclude list (`node_modules`, `bower_components`, `jspm_packages`, `__pycache__`, `.venv`, `venv`, `build`, `dist`, `.tox`, `.mypy_cache`, `.pytest_cache`, `*.egg-info`, `vendor`). Use this when manifest files live under a normally-ignored folder, e.g. `build/requirements.txt`. |
208
209
 
209
210
  #### Branch and Scan Configuration
210
211
  | Parameter | Required | Default | Description |
211
212
  |:-------------------------|:---------|:--------|:------------------------------------------------------------------------------------------------------|
212
213
  | `--default-branch` | False | *auto* | Make this branch the default branch (auto-detected from git and CI environment when not specified) |
213
214
  | `--pending-head` | False | *auto* | If true, the new scan will be set as the branch's head scan (automatically synced with default-branch) |
214
- | `--include-module-folders` | False | False | If enabled will include manifest files from folders like node_modules |
215
+ | `--include-module-folders` | False | False | If enabled, re-includes the JS/TS module folders (`node_modules`, `bower_components`, `jspm_packages`) in manifest discovery. For other excluded directories, use `--include-dirs`. |
215
216
 
216
217
  #### Output Configuration
217
218
  | Parameter | Required | Default | Description |
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "socketsecurity"
9
- version = "2.4.8"
9
+ version = "2.4.10"
10
10
  requires-python = ">= 3.11"
11
11
  license = {"file" = "LICENSE"}
12
12
  dependencies = [
@@ -1,3 +1,3 @@
1
1
  __author__ = 'socket.dev'
2
- __version__ = '2.4.8'
2
+ __version__ = '2.4.10'
3
3
  USER_AGENT = f'SocketPythonCLI/{__version__}'
@@ -139,6 +139,9 @@ class CliConfig:
139
139
  ignore_commit_files: bool = False
140
140
  disable_blocking: bool = False
141
141
  disable_ignore: bool = False
142
+ # Tri-state log-upload preference: True = --upload-logs, False = --no-upload-logs,
143
+ # None = neither (server-side override decides).
144
+ upload_logs: Optional[bool] = None
142
145
  strict_blocking: bool = False
143
146
  integration_type: IntegrationType = "api"
144
147
  integration_org_slug: Optional[str] = None
@@ -151,6 +154,7 @@ class CliConfig:
151
154
  repo_is_public: bool = False
152
155
  excluded_ecosystems: list[str] = field(default_factory=lambda: [])
153
156
  exclude_paths: Optional[List[str]] = None
157
+ included_dirs: List[str] = field(default_factory=lambda: [])
154
158
  version: str = __version__
155
159
  jira_plugin: PluginConfig = field(default_factory=PluginConfig)
156
160
  slack_plugin: PluginConfig = field(default_factory=PluginConfig)
@@ -282,6 +286,7 @@ class CliConfig:
282
286
  'ignore_commit_files': args.ignore_commit_files,
283
287
  'disable_blocking': args.disable_blocking,
284
288
  'disable_ignore': args.disable_ignore,
289
+ 'upload_logs': args.upload_logs,
285
290
  'strict_blocking': args.strict_blocking,
286
291
  'integration_type': args.integration,
287
292
  'pending_head': args.pending_head,
@@ -310,6 +315,7 @@ class CliConfig:
310
315
  'reach_ecosystems': args.reach_ecosystems.split(',') if args.reach_ecosystems else None,
311
316
  'reach_exclude_paths': args.reach_exclude_paths.split(',') if args.reach_exclude_paths else None,
312
317
  'exclude_paths': normalize_exclude_paths(args.exclude_paths),
318
+ 'included_dirs': normalize_exclude_paths(args.include_dirs) or [],
313
319
  'reach_skip_cache': args.reach_skip_cache,
314
320
  'reach_min_severity': args.reach_min_severity,
315
321
  'reach_output_file': args.reach_output_file,
@@ -635,6 +641,17 @@ def create_argument_parser() -> argparse.ArgumentParser:
635
641
  "Supersedes --reach-exclude-paths."
636
642
  )
637
643
 
644
+ path_group.add_argument(
645
+ "--include-dirs",
646
+ dest="include_dirs",
647
+ metavar="<list>",
648
+ help="Comma-separated directory names that are excluded from manifest discovery by "
649
+ "default but should be scanned (e.g. 'build,dist'). Names are matched against any "
650
+ "path segment, mirroring the default exclude list. Defaults excluded: "
651
+ "node_modules, bower_components, jspm_packages, __pycache__, .venv, venv, build, "
652
+ "dist, .tox, .mypy_cache, .pytest_cache, *.egg-info, vendor."
653
+ )
654
+
638
655
  # Branch and Scan Configuration
639
656
  config_group = parser.add_argument_group('Branch and Scan Configuration')
640
657
  config_group.add_argument(
@@ -866,6 +883,26 @@ def create_argument_parser() -> argparse.ArgumentParser:
866
883
  action="store_true",
867
884
  help=argparse.SUPPRESS
868
885
  )
886
+ log_upload_group = advanced_group.add_mutually_exclusive_group()
887
+ log_upload_group.add_argument(
888
+ "--upload-logs",
889
+ dest="upload_logs",
890
+ action="store_const",
891
+ const=True,
892
+ help="Upload the CLI's log output to the Socket backend for this run. "
893
+ "When set, the CLI registers the run with share_logs=true and streams "
894
+ "its log records in 5s batches. Default off. Mutually exclusive with "
895
+ "--no-upload-logs."
896
+ )
897
+ log_upload_group.add_argument(
898
+ "--no-upload-logs",
899
+ dest="upload_logs",
900
+ action="store_const",
901
+ const=False,
902
+ help="Explicitly opt out of uploading CLI logs to the Socket backend, even "
903
+ "when an org-level override would otherwise enable it. Mutually "
904
+ "exclusive with --upload-logs."
905
+ )
869
906
  advanced_group.add_argument(
870
907
  "--strict-blocking",
871
908
  dest="strict_blocking",
@@ -0,0 +1,79 @@
1
+ """Lifecycle helpers for a CLI run on the Socket backend.
2
+
3
+ A "run" represents a single CLI invocation. `register_cli_run` opens it and
4
+ returns a server-issued `run_id` when streaming is enabled; `finalize_cli_run`
5
+ closes it on exit. The run_id keys the rows that `BatchedLogUploader` POSTs to
6
+ `/python-cli-runs/<run_id>/logs` during the run so the dashboard can show
7
+ what the user saw in their terminal.
8
+
9
+ Streaming is opt-in via the `share_logs` field on register. The server may
10
+ also force-enable streaming for an org regardless of the client's request,
11
+ so the CLI always calls register and gates on the response's
12
+ `log_streaming_enabled` flag rather than the client's intent.
13
+
14
+ Both calls are best-effort: failures fall back to no-streaming and never
15
+ prevent the scan from running.
16
+ """
17
+
18
+ import json
19
+ import logging
20
+ from typing import Optional
21
+
22
+ from .cli_client import CliClient
23
+
24
+ log = logging.getLogger("socketcli")
25
+
26
+
27
+ def register_cli_run(
28
+ client: CliClient,
29
+ client_version: str,
30
+ upload_logs: Optional[bool],
31
+ ) -> Optional[str]:
32
+ """Register a CLI run with the backend.
33
+
34
+ `upload_logs` is the user's tri-state preference (True / False / None);
35
+ it's projected to the wire-format `share_logs` and `decline_logs`
36
+ booleans here, at the API boundary.
37
+
38
+ Best-effort: any failure (network, malformed response, unexpected JSON
39
+ shape, etc.) falls back to no-streaming and must never prevent the
40
+ scan from running. The single broad except is intentional.
41
+ """
42
+ try:
43
+ resp = client.request(
44
+ path="python-cli-runs",
45
+ method="POST",
46
+ payload=json.dumps({
47
+ "client_version": client_version,
48
+ "share_logs": upload_logs is True,
49
+ "decline_logs": upload_logs is False,
50
+ }),
51
+ )
52
+ body = resp.json()
53
+ if not body.get("log_streaming_enabled"):
54
+ log.debug("cli-run register: log streaming not enabled by server")
55
+ return None
56
+ run_id = body.get("run_id")
57
+ if not isinstance(run_id, str) or not run_id:
58
+ log.debug(f"cli-run register: enabled but missing run_id in response: {body!r}")
59
+ return None
60
+ return run_id
61
+ except Exception as e:
62
+ log.debug(f"cli-run register failed (streaming disabled): {e}")
63
+ return None
64
+
65
+
66
+ def finalize_cli_run(
67
+ client: CliClient,
68
+ run_id: str,
69
+ status: str = "success",
70
+ report_run_id: Optional[str] = None,
71
+ ) -> None:
72
+ try:
73
+ client.request(
74
+ path=f"python-cli-runs/{run_id}/finalize",
75
+ method="POST",
76
+ payload=json.dumps({"status": status, "report_run_id": report_run_id}),
77
+ )
78
+ except Exception as e:
79
+ log.debug(f"cli-run finalize failed (swallowed): {e}")
@@ -0,0 +1,112 @@
1
+ """Buffer the CLI's local log records and POST them in batches to
2
+ /python-cli-runs/<run_id>/logs so the dashboard's view of a CLI run
3
+ mirrors what the user sees in their terminal.
4
+
5
+ Behavior:
6
+ - daemon thread, 5s flush
7
+ - swallow all network errors (debug log only)
8
+ - skip empty buffers
9
+ - drain on shutdown
10
+ - at-most-once semantics (failed batches dropped, not retried)
11
+
12
+ A thread-local recursion guard prevents the uploader's own request-error
13
+ log lines (emitted by `cli_client.py`'s `socketdev` logger) from being
14
+ re-enqueued during a flush.
15
+ """
16
+
17
+ import json
18
+ import logging
19
+ import threading
20
+ from datetime import datetime, timezone
21
+ from typing import Optional
22
+
23
+ from .cli_client import CliClient
24
+
25
+ log = logging.getLogger(__name__)
26
+
27
+ _FLUSH_GUARD = threading.local()
28
+
29
+
30
+ def _now_str() -> str:
31
+ return datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
32
+
33
+
34
+ class BatchedLogUploader:
35
+ def __init__(
36
+ self,
37
+ client: CliClient,
38
+ run_id: str,
39
+ flush_interval: float = 5.0,
40
+ ):
41
+ self._client = client
42
+ self._run_id = run_id
43
+ self._flush_interval = flush_interval
44
+ self._buf: list = []
45
+ self._lock = threading.Lock()
46
+ self._stop = threading.Event()
47
+ self._thread: Optional[threading.Thread] = None
48
+
49
+ def add(self, entry: dict) -> None:
50
+ with self._lock:
51
+ self._buf.append(entry)
52
+
53
+ def start(self) -> None:
54
+ if self._thread is not None:
55
+ return
56
+ self._thread = threading.Thread(
57
+ target=self._run,
58
+ name=f"socket-log-uploader-{self._run_id[:8]}",
59
+ daemon=True,
60
+ )
61
+ self._thread.start()
62
+
63
+ def stop(self, timeout: float = 2.0) -> None:
64
+ if self._thread is not None:
65
+ self._stop.set()
66
+ self._thread.join(timeout=timeout)
67
+ self._thread = None
68
+ self._flush()
69
+
70
+ def _run(self) -> None:
71
+ while not self._stop.is_set():
72
+ self._flush()
73
+ self._stop.wait(self._flush_interval)
74
+
75
+ def _flush(self) -> None:
76
+ with self._lock:
77
+ if not self._buf:
78
+ return
79
+ batch = self._buf
80
+ self._buf = []
81
+
82
+ _FLUSH_GUARD.active = True
83
+ try:
84
+ self._client.request(
85
+ path=f"python-cli-runs/{self._run_id}/logs",
86
+ method="POST",
87
+ payload=json.dumps({"logs": batch}),
88
+ )
89
+ except Exception as e:
90
+ log.debug(f"log upload failed (swallowed, {len(batch)} entries dropped): {e}")
91
+ finally:
92
+ _FLUSH_GUARD.active = False
93
+
94
+
95
+ class UploadingLogHandler(logging.Handler):
96
+ def __init__(self, uploader: BatchedLogUploader, context: str = "socket-python-cli"):
97
+ super().__init__()
98
+ self._uploader = uploader
99
+ self._context = context
100
+
101
+ def emit(self, record: logging.LogRecord) -> None:
102
+ if getattr(_FLUSH_GUARD, "active", False):
103
+ return
104
+ try:
105
+ self._uploader.add({
106
+ "timestamp": _now_str(),
107
+ "level": logging.getLevelName(record.levelno),
108
+ "message": self.format(record),
109
+ "context": self._context,
110
+ })
111
+ except Exception:
112
+ self.handleError(record)
@@ -15,6 +15,10 @@ default_exclude_dirs = {
15
15
  "vendor"
16
16
  }
17
17
 
18
+ # Subset of default_exclude_dirs that hold installed JS/TS modules. Re-included as a group
19
+ # by --include-module-folders (see CliConfig.include_module_folders).
20
+ module_folder_dirs = {"node_modules", "bower_components", "jspm_packages"}
21
+
18
22
  @dataclass
19
23
  class SocketConfig:
20
24
  api_key: str
@@ -0,0 +1,112 @@
1
+ """Server log streaming pipeline for one CLI run.
2
+
3
+ `StreamingLogs` is a context manager. On enter it registers a run with the
4
+ backend, attaches handlers that route the CLI's own log output through both
5
+ the local terminal and a batched uploader, and forces the loggers into DEBUG
6
+ so the upload captures everything regardless of local terminal verbosity.
7
+ On exit it tears the handlers back down and finalizes the run; the status
8
+ sent to finalize is inferred from the exception that closed the `with`
9
+ block (success / failure / cancelled).
10
+
11
+ If registration fails the manager becomes a no-op — nothing is wired up and
12
+ __exit__ does nothing.
13
+ """
14
+
15
+ import logging
16
+ from typing import Optional
17
+
18
+ from .cli_client import CliClient
19
+ from .cli_run import finalize_cli_run, register_cli_run
20
+ from .log_uploader import BatchedLogUploader, UploadingLogHandler
21
+
22
+
23
+ class StreamingLogs:
24
+ def __init__(
25
+ self,
26
+ *,
27
+ client: CliClient,
28
+ cli_logger: logging.Logger,
29
+ sdk_logger: logging.Logger,
30
+ client_version: str,
31
+ upload_logs: Optional[bool],
32
+ enable_debug: bool,
33
+ ):
34
+ self._client = client
35
+ self._loggers = (cli_logger, sdk_logger)
36
+ self._client_version = client_version
37
+ self._upload_logs = upload_logs
38
+ self._enable_debug = enable_debug
39
+
40
+ self._run_id: Optional[str] = None
41
+ self._report_run_id: Optional[str] = None
42
+ self._uploader: Optional[BatchedLogUploader] = None
43
+ self._upload_handler: Optional[UploadingLogHandler] = None
44
+ self._terminal_handler: Optional[logging.StreamHandler] = None
45
+ self._saved_levels: tuple = ()
46
+ self._saved_propagate: tuple = ()
47
+
48
+ def set_report_run_id(self, report_run_id: Optional[str]) -> None:
49
+ self._report_run_id = report_run_id
50
+
51
+ def __enter__(self) -> "StreamingLogs":
52
+ self._run_id = register_cli_run(
53
+ self._client,
54
+ client_version=self._client_version,
55
+ upload_logs=self._upload_logs,
56
+ )
57
+ cli_logger = self._loggers[0]
58
+ if not self._run_id:
59
+ cli_logger.debug("server log streaming not active for this run")
60
+ return self
61
+
62
+ self._uploader = BatchedLogUploader(self._client, self._run_id)
63
+ self._uploader.start()
64
+ self._upload_handler = UploadingLogHandler(self._uploader, context="socket-python-cli")
65
+ self._upload_handler.setFormatter(logging.Formatter("%(message)s"))
66
+
67
+ self._terminal_handler = logging.StreamHandler()
68
+ self._terminal_handler.setLevel(logging.DEBUG if self._enable_debug else logging.INFO)
69
+ self._terminal_handler.setFormatter(logging.Formatter("%(asctime)s: %(message)s"))
70
+
71
+ self._saved_levels = tuple(lg.level for lg in self._loggers)
72
+ self._saved_propagate = tuple(lg.propagate for lg in self._loggers)
73
+ for lg in self._loggers:
74
+ lg.setLevel(logging.DEBUG)
75
+ lg.propagate = False
76
+ lg.addHandler(self._terminal_handler)
77
+ lg.addHandler(self._upload_handler)
78
+
79
+ cli_logger.debug(f"server log streaming enabled (run_id={self._run_id})")
80
+ return self
81
+
82
+ def __exit__(self, exc_type, exc_val, exc_tb) -> bool:
83
+ if self._run_id is None:
84
+ return False
85
+
86
+ status = self._status_for_exit(exc_type, exc_val)
87
+ for lg in self._loggers:
88
+ lg.removeHandler(self._upload_handler)
89
+ self._uploader.stop()
90
+ finalize_cli_run(
91
+ self._client,
92
+ self._run_id,
93
+ status=status,
94
+ report_run_id=self._report_run_id,
95
+ )
96
+ for lg in self._loggers:
97
+ lg.removeHandler(self._terminal_handler)
98
+ for lg, level, propagate in zip(self._loggers, self._saved_levels, self._saved_propagate):
99
+ lg.setLevel(level)
100
+ lg.propagate = propagate
101
+ return False
102
+
103
+ @staticmethod
104
+ def _status_for_exit(exc_type, exc_val) -> str:
105
+ if exc_type is None:
106
+ return "success"
107
+ if issubclass(exc_type, KeyboardInterrupt):
108
+ return "cancelled"
109
+ # SystemExit with code 0 / None is a clean exit; non-zero codes signal failure.
110
+ if issubclass(exc_type, SystemExit) and not getattr(exc_val, "code", None):
111
+ return "success"
112
+ return "failure"