socketsecurity 2.10.5__tar.gz → 2.10.7__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 (174) hide show
  1. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/CHANGELOG.md +22 -0
  2. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/PKG-INFO +1 -1
  3. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/docs/cli-reference.md +1 -1
  4. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/pyproject.toml +1 -1
  5. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/__init__.py +1 -1
  6. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/git_interface.py +147 -55
  7. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/tools/reachability.py +3 -3
  8. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_git_interface.py +154 -0
  9. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/uv.lock +1 -1
  10. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/CODEOWNERS +0 -0
  11. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/PULL_REQUEST_TEMPLATE/bug-fix.md +0 -0
  12. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/PULL_REQUEST_TEMPLATE/feature.md +0 -0
  13. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/PULL_REQUEST_TEMPLATE/improvement.md +0 -0
  14. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  15. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/actions/setup-docker/action.yml +0 -0
  16. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/actions/setup-hatch/action.yml +0 -0
  17. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/actions/setup-sfw/action.yml +0 -0
  18. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/dependabot.yml +0 -0
  19. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/workflows/dependency-audit.yml +0 -0
  20. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/workflows/dependency-review.yml +0 -0
  21. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/workflows/docker-stable.yml +0 -0
  22. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/workflows/e2e-test.yml +0 -0
  23. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/workflows/package-check.yml +0 -0
  24. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/workflows/pr-preview.yml +0 -0
  25. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/workflows/python-tests.yml +0 -0
  26. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/workflows/release.yml +0 -0
  27. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/workflows/version-check.yml +0 -0
  28. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.github/zizmor.yml +0 -0
  29. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.gitignore +0 -0
  30. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.hooks/sync_version.py +0 -0
  31. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.pre-commit-config.yaml +0 -0
  32. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/.python-version +0 -0
  33. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/CONTRIBUTING.md +0 -0
  34. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/Dockerfile +0 -0
  35. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/Dockerfile.preview +0 -0
  36. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/LICENSE +0 -0
  37. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/Makefile +0 -0
  38. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/README.md +0 -0
  39. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/benchmarks/manifest_discovery.py +0 -0
  40. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/docs/ci-cd.md +0 -0
  41. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/docs/development.md +0 -0
  42. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/docs/troubleshooting.md +0 -0
  43. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/examples/config/sarif-dashboard-parity.json +0 -0
  44. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/examples/config/sarif-dashboard-parity.toml +0 -0
  45. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/examples/config/sarif-diff-ci-cd.json +0 -0
  46. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/examples/config/sarif-diff-ci-cd.toml +0 -0
  47. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/examples/config/sarif-instance-detail.json +0 -0
  48. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/examples/config/sarif-instance-detail.toml +0 -0
  49. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/instructions/gitlab-commit-status/uat.md +0 -0
  50. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/pytest.ini +0 -0
  51. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/scripts/build_container.sh +0 -0
  52. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/scripts/build_container_flexible.sh +0 -0
  53. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/scripts/deploy-test-docker.sh +0 -0
  54. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/scripts/deploy-test-pypi.sh +0 -0
  55. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/scripts/docker-entrypoint.sh +0 -0
  56. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/scripts/run.sh +0 -0
  57. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/session.md +0 -0
  58. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socket.yml +0 -0
  59. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/config.py +0 -0
  60. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/__init__.py +0 -0
  61. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/alert_selection.py +0 -0
  62. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/classes.py +0 -0
  63. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/cli_client.py +0 -0
  64. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/cli_run.py +0 -0
  65. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/exceptions.py +0 -0
  66. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/git_remote.py +0 -0
  67. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/helper/__init__.py +0 -0
  68. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/helper/socket_facts_loader.py +0 -0
  69. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/lazy_file_loader.py +0 -0
  70. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/log_uploader.py +0 -0
  71. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/logging.py +0 -0
  72. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/messages.py +0 -0
  73. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/pull_request.py +0 -0
  74. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/resource_utils.py +0 -0
  75. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/scm/__init__.py +0 -0
  76. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/scm/base.py +0 -0
  77. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/scm/client.py +0 -0
  78. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/scm/github.py +0 -0
  79. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/scm/gitlab.py +0 -0
  80. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/scm_comments.py +0 -0
  81. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/socket_config.py +0 -0
  82. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/streaming.py +0 -0
  83. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/core/utils.py +0 -0
  84. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/fossa_compat.py +0 -0
  85. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/output.py +0 -0
  86. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/plugins/__init__.py +0 -0
  87. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/plugins/base.py +0 -0
  88. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/plugins/formatters/__init__.py +0 -0
  89. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/plugins/formatters/slack.py +0 -0
  90. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/plugins/jira.py +0 -0
  91. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/plugins/manager.py +0 -0
  92. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/plugins/slack.py +0 -0
  93. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/plugins/teams.py +0 -0
  94. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/plugins/webhook.py +0 -0
  95. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/socketsecurity/socketcli.py +0 -0
  96. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/__init__.py +0 -0
  97. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/core/conftest.py +0 -0
  98. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/core/create_diff_input.json +0 -0
  99. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/core/test_diff_alerts.py +0 -0
  100. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/core/test_diff_generation.py +0 -0
  101. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/core/test_diff_scan_polling.py +0 -0
  102. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/core/test_facts_compression.py +0 -0
  103. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/core/test_full_scan_outputs.py +0 -0
  104. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/core/test_has_manifest_files.py +0 -0
  105. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/core/test_invalid_facts_marker.py +0 -0
  106. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/core/test_package_and_alerts.py +0 -0
  107. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/core/test_sdk_methods.py +0 -0
  108. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/core/test_supporting_methods.py +0 -0
  109. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/data/fullscans/create_response.json +0 -0
  110. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/data/fullscans/diff/stream_diff.json +0 -0
  111. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/data/fullscans/diff/stream_diff_full.json +0 -0
  112. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/data/fullscans/head_scan/metadata.json +0 -0
  113. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/data/fullscans/head_scan/stream_scan.json +0 -0
  114. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/data/fullscans/head_scan/stream_scan_full.json +0 -0
  115. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/data/fullscans/new_scan/metadata.json +0 -0
  116. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/data/fullscans/new_scan/stream_scan.json +0 -0
  117. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/data/repos/repo_info_error.json +0 -0
  118. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/data/repos/repo_info_no_head.json +0 -0
  119. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/data/repos/repo_info_success.json +0 -0
  120. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/data/settings/security-policy.json +0 -0
  121. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/e2e/fixtures/simple-npm/index.js +0 -0
  122. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/e2e/fixtures/simple-npm/package.json +0 -0
  123. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/e2e/fixtures/simple-pypi/requirements.txt +0 -0
  124. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/e2e/reach-facts-probe.sh +0 -0
  125. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/e2e/validate-gitlab.sh +0 -0
  126. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/e2e/validate-json.sh +0 -0
  127. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/e2e/validate-reachability.sh +0 -0
  128. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/e2e/validate-sarif.sh +0 -0
  129. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/e2e/validate-scan.sh +0 -0
  130. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/fixtures/fossa/README.md +0 -0
  131. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/fixtures/fossa/fossa-analyze-empty.json +0 -0
  132. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/fixtures/fossa/fossa-analyze-populated.json +0 -0
  133. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/fixtures/fossa/fossa-sbom-empty-deep.json +0 -0
  134. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/fixtures/fossa/fossa-sbom-populated.json +0 -0
  135. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/__init__.py +0 -0
  136. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_alert_selection.py +0 -0
  137. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_cli_config.py +0 -0
  138. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_cli_run.py +0 -0
  139. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_client.py +0 -0
  140. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_commit_message_truncation.py +0 -0
  141. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_config.py +0 -0
  142. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_dependency_overview.py +0 -0
  143. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_disable_ignore.py +0 -0
  144. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_exclude_paths.py +0 -0
  145. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_fossa_compat.py +0 -0
  146. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_fossa_parity.py +0 -0
  147. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_full_scan_retry.py +0 -0
  148. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_git_remote.py +0 -0
  149. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_github_buildkite_config.py +0 -0
  150. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_gitlab_auth.py +0 -0
  151. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_gitlab_auth_fallback.py +0 -0
  152. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_gitlab_commit_status.py +0 -0
  153. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_gitlab_format.py +0 -0
  154. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_ignore_authorization.py +0 -0
  155. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_ignore_telemetry_filtering.py +0 -0
  156. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_include_dirs.py +0 -0
  157. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_log_uploader.py +0 -0
  158. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_manifest_discovery.py +0 -0
  159. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_messages.py +0 -0
  160. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_output.py +0 -0
  161. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_pr_comment_rendering.py +0 -0
  162. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_pull_request_context.py +0 -0
  163. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_reachability.py +0 -0
  164. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_scan_scope.py +0 -0
  165. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_slack_plugin.py +0 -0
  166. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_slack_severity_normalization.py +0 -0
  167. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_socketcli.py +0 -0
  168. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_streaming.py +0 -0
  169. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_summary_text.py +0 -0
  170. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/tests/unit/test_tier1_finalize.py +0 -0
  171. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/workflows/bitbucket-pipelines.yml +0 -0
  172. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/workflows/buildkite.yml +0 -0
  173. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/workflows/github-actions.yml +0 -0
  174. {socketsecurity-2.10.5 → socketsecurity-2.10.7}/workflows/gitlab-ci.yml +0 -0
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.10.7
4
+
5
+ ### Changed: bump pinned @coana-tech/cli to 15.11.5
6
+
7
+ - Bumped the pinned reachability engine (`@coana-tech/cli`) from `15.11.4` to
8
+ `15.11.5`. See the
9
+ [reachability analysis changelog](https://docs.socket.dev/docs/reachability-analysis-changelog)
10
+ for engine changes.
11
+
12
+ ## 2.10.6
13
+
14
+ ### Fixed: default-branch detection in single-branch CI checkouts
15
+
16
+ - Repositories whose default branch isn't `main` or `master` are detected as the
17
+ default branch again when the checkout has no `origin/HEAD`, as with
18
+ `actions/checkout`. The CLI reads the default branch from the GitHub event
19
+ payload or asks the remote, before falling back to `main`/`master`. Scans on
20
+ those branches become the branch head again.
21
+ - GitLab's `CI_DEFAULT_BRANCH` and Buildkite's `BUILDKITE_PIPELINE_DEFAULT_BRANCH`
22
+ now apply to every default-branch check, including whether the commit is on
23
+ the default branch.
24
+
3
25
  ## 2.10.5
4
26
 
5
27
  ### Changed: bump pinned @coana-tech/cli to 15.11.4
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: socketsecurity
3
- Version: 2.10.5
3
+ Version: 2.10.7
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>
@@ -338,7 +338,7 @@ If you don't want to provide the Socket API Token every time then you can use th
338
338
  | Parameter | Required | Default | Description |
339
339
  |:---------------------------------|:---------|:--------|:---------------------------------------------------------------------------------------------------------------------------|
340
340
  | `--reach` | False | False | Enable reachability analysis to identify which vulnerable functions are actually called by your code. Creates a full application reachability scan (`scan_type=socket_tier1`). |
341
- | `--reach-version` | False | 15.11.4 | Version of @coana-tech/cli to use. Defaults to the pinned version that ships with this CLI release, so the engine only changes when you upgrade the Socket CLI. Pass `latest` to always use the newest published version (opt-in auto-update), or an explicit version (e.g. `1.2.3`) to pin it. |
341
+ | `--reach-version` | False | 15.11.5 | Version of @coana-tech/cli to use. Defaults to the pinned version that ships with this CLI release, so the engine only changes when you upgrade the Socket CLI. Pass `latest` to always use the newest published version (opt-in auto-update), or an explicit version (e.g. `1.2.3`) to pin it. |
342
342
  | `--reach-analysis-timeout` | False | 10m | Timeout for each reachability analysis run, e.g. `90s`, `10m` or `1h`. Omitted by default, so coana applies its own default (`10m`). Alias: `--reach-timeout` |
343
343
  | `--reach-analysis-memory-limit` | False | 8GB | Memory limit for each reachability analysis run, e.g. `512MB` or `8GB`. Omitted by default, so coana applies its own default (`8GB`). Alias: `--reach-memory-limit` |
344
344
  | `--reach-concurrency` | False | 1 | Control parallel analysis execution (must be >= 1). Omitted by default, so coana applies its own default. |
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "socketsecurity"
9
- version = "2.10.5"
9
+ version = "2.10.7"
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.10.5'
2
+ __version__ = '2.10.7'
3
3
  USER_AGENT = f'SocketPythonCLI/{__version__}'
@@ -1,5 +1,8 @@
1
+ import json
1
2
  import os
2
3
  import re
4
+ import signal
5
+ import subprocess
3
6
  import time
4
7
  import urllib.parse
5
8
 
@@ -7,6 +10,9 @@ from git import Repo
7
10
 
8
11
  from socketsecurity.core import log
9
12
 
13
+ REMOTE_HEAD_TIMEOUT_SECONDS = 30
14
+ IS_WINDOWS = os.name == "nt"
15
+
10
16
 
11
17
  class Git:
12
18
  repo: Repo
@@ -27,6 +33,7 @@ class Git:
27
33
  self.path = path
28
34
  self.base_commit_sha = base_commit_sha
29
35
  self._fetched_ref_commits = {}
36
+ self._default_branch_name: str | None = None
30
37
  self.ensure_safe_directory(path)
31
38
  self.repo = Repo(path)
32
39
  assert self.repo
@@ -407,23 +414,16 @@ class Git:
407
414
  True if commit is on default branch and we're processing the default branch
408
415
  """
409
416
  try:
410
- # First check if the commit is reachable from the default branch
411
- if not self.is_commit_on_default_branch():
412
- log.debug("Commit is not on default branch")
413
- return False
414
-
415
- # Check if we're processing the default branch via CI environment variables
416
417
  github_ref = os.getenv('GITHUB_REF') # e.g., 'refs/heads/main' or 'refs/pull/123/merge'
417
418
  gitlab_branch = os.getenv('CI_COMMIT_BRANCH')
418
419
  gitlab_mr_branch = os.getenv('CI_MERGE_REQUEST_SOURCE_BRANCH_NAME')
419
- gitlab_default_branch = os.getenv('CI_DEFAULT_BRANCH', '')
420
420
  bitbucket_branch = os.getenv('BITBUCKET_BRANCH')
421
+ bitbucket_pr = os.getenv('BITBUCKET_PR_ID')
421
422
  buildkite_branch = os.getenv('BUILDKITE_BRANCH')
422
423
  buildkite_pr = os.getenv('BUILDKITE_PULL_REQUEST')
423
- buildkite_default_branch = os.getenv('BUILDKITE_PIPELINE_DEFAULT_BRANCH')
424
-
425
- # Handle Buildkite before GitHub because some Buildkite pipelines
426
- # intentionally provide GitHub-compatible environment variables.
424
+
425
+ # PR and non-branch builds cannot become the default branch head.
426
+ # Decide that locally before default-branch lookup contacts origin.
427
427
  if buildkite_branch:
428
428
  if self._is_buildkite_pull_request(buildkite_pr):
429
429
  log.debug(
@@ -431,7 +431,29 @@ class Git:
431
431
  "not default branch"
432
432
  )
433
433
  return False
434
- default_branch_name = buildkite_default_branch or self.get_default_branch_name()
434
+ elif github_ref:
435
+ if github_ref.startswith('refs/pull/'):
436
+ log.debug("Processing a pull request, not default branch")
437
+ return False
438
+ if not github_ref.startswith('refs/heads/'):
439
+ log.debug(f"Non-branch ref: {github_ref}, not default branch")
440
+ return False
441
+ elif gitlab_branch or gitlab_mr_branch:
442
+ if gitlab_mr_branch:
443
+ log.debug(f"Processing GitLab MR from branch: {gitlab_mr_branch}, not default branch")
444
+ return False
445
+ elif bitbucket_branch and bitbucket_pr:
446
+ log.debug(f"Processing Bitbucket pull request from branch: {bitbucket_branch}, not default branch")
447
+ return False
448
+
449
+ if not self.is_commit_on_default_branch():
450
+ log.debug("Commit is not on default branch")
451
+ return False
452
+
453
+ # Handle Buildkite before GitHub because some Buildkite pipelines
454
+ # intentionally provide GitHub-compatible environment variables.
455
+ if buildkite_branch:
456
+ default_branch_name = self.get_default_branch_name()
435
457
  is_default = buildkite_branch == default_branch_name
436
458
  log.debug(
437
459
  f"Buildkite branch: {buildkite_branch}, Default: {default_branch_name}, "
@@ -442,35 +464,16 @@ class Git:
442
464
  # Handle GitHub Actions
443
465
  elif github_ref:
444
466
  log.debug(f"GitHub ref: {github_ref}")
445
-
446
- # Handle pull requests - they're not on the default branch
447
- if github_ref.startswith('refs/pull/'):
448
- log.debug("Processing a pull request, not default branch")
449
- return False
450
-
451
- # Handle regular branch pushes
452
- if github_ref.startswith('refs/heads/'):
453
- branch_from_ref = github_ref.replace('refs/heads/', '')
454
- default_branch_name = self.get_default_branch_name()
455
- is_default = branch_from_ref == default_branch_name
456
- log.debug(f"Branch from GITHUB_REF: {branch_from_ref}, Default: {default_branch_name}, Is default: {is_default}")
457
- return is_default
458
-
459
- # Handle tags or other refs - not default branch
460
- log.debug(f"Non-branch ref: {github_ref}, not default branch")
461
- return False
467
+ branch_from_ref = github_ref.removeprefix('refs/heads/')
468
+ default_branch_name = self.get_default_branch_name()
469
+ is_default = branch_from_ref == default_branch_name
470
+ log.debug(f"Branch from GITHUB_REF: {branch_from_ref}, Default: {default_branch_name}, Is default: {is_default}")
471
+ return is_default
462
472
 
463
473
  # Handle GitLab CI
464
474
  elif gitlab_branch or gitlab_mr_branch:
465
- # If this is a merge request, use the source branch
466
475
  current_branch = gitlab_mr_branch or gitlab_branch
467
- default_branch_name = gitlab_default_branch or self.get_default_branch_name()
468
-
469
- # For merge requests, they're typically not considered "default branch"
470
- if gitlab_mr_branch:
471
- log.debug(f"Processing GitLab MR from branch: {gitlab_mr_branch}, not default branch")
472
- return False
473
-
476
+ default_branch_name = self.get_default_branch_name()
474
477
  is_default = current_branch == default_branch_name
475
478
  log.debug(f"GitLab branch: {current_branch}, Default: {default_branch_name}, Is default: {is_default}")
476
479
  return is_default
@@ -638,27 +641,116 @@ class Git:
638
641
  Returns:
639
642
  Default branch name (e.g., 'main', 'master')
640
643
  """
644
+ if self._default_branch_name is None:
645
+ self._default_branch_name = self._detect_default_branch_name()
646
+ return self._default_branch_name
647
+
648
+ def _detect_default_branch_name(self) -> str:
649
+ for variable in ('CI_DEFAULT_BRANCH', 'BUILDKITE_PIPELINE_DEFAULT_BRANCH'):
650
+ default_branch = os.getenv(variable)
651
+ if default_branch:
652
+ log.debug(f"Default branch detected from {variable}: {default_branch}")
653
+ return default_branch
654
+
641
655
  try:
642
- # Try to get the default branch from remote HEAD
643
- remote_head = self.repo.remotes.origin.refs.HEAD
644
- # Extract branch name from refs/remotes/origin/HEAD -> refs/remotes/origin/main
645
- default_branch = str(remote_head.reference).split('/')[-1]
646
- log.debug(f"Default branch detected: {default_branch}")
656
+ default_branch = self.repo.remotes.origin.refs.HEAD.reference.remote_head
657
+ log.debug(f"Default branch detected from origin/HEAD: {default_branch}")
647
658
  return default_branch
648
659
  except Exception as error:
649
- log.debug(f"Could not determine default branch from remote: {error}")
650
- # Fallback: check common default branch names
651
- for branch_name in ['main', 'master']:
652
- try:
653
- if f'origin/{branch_name}' in [str(ref) for ref in self.repo.remotes.origin.refs]:
654
- log.debug(f"Using fallback default branch: {branch_name}")
655
- return branch_name
656
- except Exception:
657
- continue
658
-
659
- # Last fallback: assume 'main'
660
- log.debug("Using final fallback default branch: main")
661
- return 'main'
660
+ log.debug(f"Could not determine default branch from origin/HEAD: {error}")
661
+
662
+ # CI checkouts such as actions/checkout fetch a single branch and leave no origin/HEAD.
663
+ default_branch = (
664
+ self._default_branch_from_github_event()
665
+ or self._default_branch_from_remote()
666
+ )
667
+ if default_branch:
668
+ return default_branch
669
+
670
+ try:
671
+ remote_refs = {str(ref) for ref in self.repo.remotes.origin.refs}
672
+ except Exception:
673
+ remote_refs = set()
674
+ for branch_name in ['main', 'master']:
675
+ if f'origin/{branch_name}' in remote_refs:
676
+ log.debug(f"Using fallback default branch: {branch_name}")
677
+ return branch_name
678
+
679
+ log.debug("Using final fallback default branch: main")
680
+ return 'main'
681
+
682
+ @staticmethod
683
+ def _default_branch_from_github_event() -> str | None:
684
+ event_path = os.getenv('GITHUB_EVENT_PATH')
685
+ if not event_path:
686
+ return None
687
+ try:
688
+ with open(event_path, encoding="utf-8") as event_file:
689
+ default_branch = json.load(event_file).get("repository", {}).get("default_branch")
690
+ except Exception as error:
691
+ log.debug(f"Could not read default branch from GitHub event payload: {error}")
692
+ return None
693
+ if default_branch:
694
+ log.debug(f"Default branch detected from GitHub event payload: {default_branch}")
695
+ return default_branch or None
696
+
697
+ def _default_branch_from_remote(self) -> str | None:
698
+ # A new session lets a timeout also kill the remote helpers, which otherwise
699
+ # hold stdout open and keep communicate() blocked. Windows ignores it.
700
+ try:
701
+ process = subprocess.Popen(
702
+ ["git", "ls-remote", "--symref", "origin", "HEAD"],
703
+ cwd=self.repo.working_dir,
704
+ env={**os.environ, "GIT_TERMINAL_PROMPT": "0"},
705
+ stdin=subprocess.DEVNULL,
706
+ stdout=subprocess.PIPE,
707
+ stderr=subprocess.DEVNULL,
708
+ text=True,
709
+ start_new_session=True,
710
+ )
711
+ except Exception as error:
712
+ log.debug(f"Could not query origin for its default branch: {error}")
713
+ return None
714
+ try:
715
+ output, _ = process.communicate(timeout=REMOTE_HEAD_TIMEOUT_SECONDS)
716
+ except subprocess.TimeoutExpired:
717
+ self._kill_process_tree(process)
718
+ log.debug(
719
+ f"Querying origin for its default branch timed out after "
720
+ f"{REMOTE_HEAD_TIMEOUT_SECONDS}s"
721
+ )
722
+ return None
723
+ if process.returncode != 0:
724
+ log.debug(f"Querying origin for its default branch exited with {process.returncode}")
725
+ return None
726
+ for line in output.splitlines():
727
+ match = re.match(r"ref: refs/heads/(\S+)\tHEAD$", line)
728
+ if match:
729
+ log.debug(f"Default branch detected from origin: {match.group(1)}")
730
+ return match.group(1)
731
+ return None
732
+
733
+ @staticmethod
734
+ def _kill_process_tree(process: subprocess.Popen) -> None:
735
+ try:
736
+ if IS_WINDOWS:
737
+ subprocess.run(
738
+ ["taskkill", "/F", "/T", "/PID", str(process.pid)],
739
+ stdout=subprocess.DEVNULL,
740
+ stderr=subprocess.DEVNULL,
741
+ timeout=10,
742
+ )
743
+ else:
744
+ os.killpg(process.pid, signal.SIGKILL)
745
+ except Exception as error:
746
+ log.debug(f"Failed to stop git ls-remote process tree: {error}")
747
+ process.kill()
748
+ if process.stdout:
749
+ process.stdout.close()
750
+ try:
751
+ process.wait(timeout=5)
752
+ except subprocess.TimeoutExpired:
753
+ log.debug("git ls-remote did not exit after being killed")
662
754
 
663
755
  def is_commit_on_default_branch(self) -> bool:
664
756
  """
@@ -19,7 +19,7 @@ log = logging.getLogger(__name__)
19
19
  # Pinned @coana-tech/cli version. Bumped deliberately per Python CLI release so the
20
20
  # reachability engine version only changes through a standard pip upgrade (advance notice).
21
21
  # Pass --reach-version latest to opt into the newest published version instead.
22
- DEFAULT_COANA_CLI_VERSION: Final = "15.11.4"
22
+ DEFAULT_COANA_CLI_VERSION: Final = "15.11.5"
23
23
 
24
24
  # Resolved @coana-tech/cli script paths from the npm-install fallback, keyed by version.
25
25
  # Lives for the process lifetime so repeated fallback invocations install only once
@@ -56,7 +56,7 @@ class ReachabilityAnalyzer:
56
56
 
57
57
  def _resolve_coana_package_spec(self, version: Optional[str] = None) -> str:
58
58
  """
59
- Resolve the @coana-tech/cli package spec to run (e.g. '@coana-tech/cli@15.11.4').
59
+ Resolve the @coana-tech/cli package spec to run (e.g. '@coana-tech/cli@15.11.5').
60
60
 
61
61
  Args:
62
62
  version: Coana CLI version to use.
@@ -65,7 +65,7 @@ class ReachabilityAnalyzer:
65
65
  - '<semver>': that exact version.
66
66
 
67
67
  Returns:
68
- str: The package specifier to use with npx (e.g. '@coana-tech/cli@15.11.4').
68
+ str: The package specifier to use with npx (e.g. '@coana-tech/cli@15.11.5').
69
69
  """
70
70
  return f"@coana-tech/cli@{self._resolve_coana_version(version)}"
71
71
 
@@ -1,10 +1,14 @@
1
1
  import logging
2
+ import socket
2
3
  import subprocess
4
+ import time
3
5
  from types import SimpleNamespace
4
6
  from unittest.mock import MagicMock
5
7
 
6
8
  import pytest
9
+ from git import Repo
7
10
 
11
+ from socketsecurity.core import git_interface
8
12
  from socketsecurity.core.git_interface import Git
9
13
 
10
14
  CI_ENVIRONMENT_VARIABLES = (
@@ -17,6 +21,7 @@ CI_ENVIRONMENT_VARIABLES = (
17
21
  "GITHUB_BASE_REF",
18
22
  "GITHUB_EVENT_BEFORE",
19
23
  "GITHUB_EVENT_NAME",
24
+ "GITHUB_EVENT_PATH",
20
25
  "GITHUB_HEAD_REF",
21
26
  "GITHUB_REF",
22
27
  "GITHUB_SHA",
@@ -127,6 +132,11 @@ def test_pull_request_context_uses_local_refs_without_fetch(
127
132
  "_fetch_ref",
128
133
  side_effect=AssertionError("unexpected fetch"),
129
134
  )
135
+ remote_lookup = mocker.patch.object(
136
+ Git,
137
+ "_default_branch_from_remote",
138
+ side_effect=AssertionError("unexpected remote default-branch lookup"),
139
+ )
130
140
  mocker.patch.object(Git, "ensure_safe_directory")
131
141
 
132
142
  with caplog.at_level(logging.INFO, logger="socketdev"):
@@ -136,6 +146,7 @@ def test_pull_request_context_uses_local_refs_without_fetch(
136
146
  assert repository.changed_files == ["package.json"]
137
147
  assert repository.is_default_branch is False
138
148
  fetch.assert_not_called()
149
+ remote_lookup.assert_not_called()
139
150
  assert any(
140
151
  f"source={expected_source}" in record.message
141
152
  for record in caplog.records
@@ -375,3 +386,146 @@ def test_unresolvable_base_commit_warns_and_falls_back(
375
386
  for record in caplog.records
376
387
  )
377
388
  fetch.assert_called_once()
389
+
390
+
391
+ @pytest.fixture
392
+ def single_branch_checkout(tmp_path):
393
+ """A repo whose default branch is dev, checked out the way actions/checkout does."""
394
+ source = tmp_path / "source"
395
+ source.mkdir()
396
+ _git(source, "init", "-b", "dev")
397
+ _git(source, "config", "user.name", "Socket Test")
398
+ _git(source, "config", "user.email", "socket@example.com")
399
+ (source / "package.json").write_text("{}\n", encoding="utf-8")
400
+ _git(source, "add", "package.json")
401
+ _git(source, "commit", "-m", "base")
402
+ origin = tmp_path / "origin.git"
403
+ _git(tmp_path, "clone", "--bare", str(source), str(origin))
404
+
405
+ checkout = tmp_path / "checkout"
406
+ checkout.mkdir()
407
+ _git(checkout, "init")
408
+ _git(checkout, "remote", "add", "origin", str(origin))
409
+ _git(checkout, "fetch", "--no-tags", "--depth=1", "origin", "+refs/heads/dev:refs/remotes/origin/dev")
410
+ _git(checkout, "checkout", "-B", "dev", "refs/remotes/origin/dev")
411
+ return checkout
412
+
413
+
414
+ def test_single_branch_checkout_detects_non_main_default_branch(
415
+ single_branch_checkout, monkeypatch, mocker
416
+ ):
417
+ monkeypatch.setenv("GITHUB_REF", "refs/heads/dev")
418
+ mocker.patch.object(Git, "ensure_safe_directory")
419
+
420
+ repository = Git(str(single_branch_checkout))
421
+
422
+ assert repository.get_default_branch_name() == "dev"
423
+ assert repository.is_default_branch is True
424
+
425
+
426
+ def test_github_event_payload_supplies_default_branch(
427
+ single_branch_checkout, tmp_path, monkeypatch, mocker
428
+ ):
429
+ event_path = tmp_path / "event.json"
430
+ event_path.write_text('{"repository": {"default_branch": "dev"}}', encoding="utf-8")
431
+ monkeypatch.setenv("GITHUB_REF", "refs/heads/dev")
432
+ monkeypatch.setenv("GITHUB_EVENT_PATH", str(event_path))
433
+ mocker.patch.object(Git, "ensure_safe_directory")
434
+ remote_lookup = mocker.patch.object(Git, "_default_branch_from_remote")
435
+
436
+ repository = Git(str(single_branch_checkout))
437
+
438
+ assert repository.is_default_branch is True
439
+ remote_lookup.assert_not_called()
440
+
441
+
442
+ @pytest.mark.parametrize(
443
+ ("branch_variable", "default_variable"),
444
+ [
445
+ ("CI_COMMIT_BRANCH", "CI_DEFAULT_BRANCH"),
446
+ ("BUILDKITE_BRANCH", "BUILDKITE_PIPELINE_DEFAULT_BRANCH"),
447
+ ],
448
+ )
449
+ def test_ci_default_branch_variable_skips_remote_lookup(
450
+ single_branch_checkout, monkeypatch, mocker, branch_variable, default_variable
451
+ ):
452
+ monkeypatch.setenv(branch_variable, "dev")
453
+ monkeypatch.setenv(default_variable, "dev")
454
+ mocker.patch.object(Git, "ensure_safe_directory")
455
+ remote_lookup = mocker.patch.object(Git, "_default_branch_from_remote")
456
+
457
+ repository = Git(str(single_branch_checkout))
458
+
459
+ assert repository.is_default_branch is True
460
+ remote_lookup.assert_not_called()
461
+
462
+
463
+ def test_origin_head_wins_without_remote_lookup(single_branch_checkout, monkeypatch, mocker):
464
+ _git(single_branch_checkout, "symbolic-ref", "refs/remotes/origin/HEAD", "refs/remotes/origin/dev")
465
+ monkeypatch.setenv("GITHUB_REF", "refs/heads/dev")
466
+ mocker.patch.object(Git, "ensure_safe_directory")
467
+ remote_lookup = mocker.patch.object(Git, "_default_branch_from_remote")
468
+
469
+ repository = Git(str(single_branch_checkout))
470
+
471
+ assert repository.is_default_branch is True
472
+ remote_lookup.assert_not_called()
473
+
474
+
475
+ def test_feature_branch_in_single_branch_checkout_is_not_default(
476
+ single_branch_checkout, monkeypatch, mocker
477
+ ):
478
+ monkeypatch.setenv("GITHUB_REF", "refs/heads/feature")
479
+ mocker.patch.object(Git, "ensure_safe_directory")
480
+
481
+ repository = Git(str(single_branch_checkout))
482
+
483
+ assert repository.is_default_branch is False
484
+
485
+
486
+ @pytest.fixture
487
+ def stalled_http_remote():
488
+ """An HTTP remote that completes the TCP handshake and never responds."""
489
+ server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
490
+ server.bind(("127.0.0.1", 0))
491
+ server.listen()
492
+ yield f"http://127.0.0.1:{server.getsockname()[1]}/repo.git"
493
+ server.close()
494
+
495
+
496
+ def test_stalled_remote_lookup_stops_at_timeout(
497
+ single_branch_checkout, stalled_http_remote, monkeypatch
498
+ ):
499
+ _git(single_branch_checkout, "remote", "set-url", "origin", stalled_http_remote)
500
+ monkeypatch.setattr(git_interface, "REMOTE_HEAD_TIMEOUT_SECONDS", 1)
501
+ for variable in ("HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "http_proxy", "https_proxy", "all_proxy"):
502
+ monkeypatch.delenv(variable, raising=False)
503
+ repository = Git.__new__(Git)
504
+ repository.repo = Repo(str(single_branch_checkout))
505
+
506
+ started = time.monotonic()
507
+ result = repository._default_branch_from_remote()
508
+
509
+ assert result is None
510
+ assert 1 <= time.monotonic() - started < 10
511
+
512
+
513
+ def test_remote_lookup_parses_branch_with_slash(mocker):
514
+ process = MagicMock(returncode=0)
515
+ process.communicate.return_value = ("ref: refs/heads/release/stable\tHEAD\n", "")
516
+ mocker.patch.object(git_interface.subprocess, "Popen", return_value=process)
517
+ repository = Git.__new__(Git)
518
+ repository.repo = MagicMock(working_dir="/repo")
519
+
520
+ assert repository._default_branch_from_remote() == "release/stable"
521
+
522
+
523
+ def test_windows_timeout_kills_the_whole_process_tree(monkeypatch, mocker):
524
+ monkeypatch.setattr(git_interface, "IS_WINDOWS", True)
525
+ run = mocker.patch.object(git_interface.subprocess, "run")
526
+ process = MagicMock(pid=4321)
527
+
528
+ Git._kill_process_tree(process)
529
+
530
+ assert run.call_args.args[0] == ["taskkill", "/F", "/T", "/PID", "4321"]
531
+ process.wait.assert_called_once()
@@ -1293,7 +1293,7 @@ wheels = [
1293
1293
 
1294
1294
  [[package]]
1295
1295
  name = "socketsecurity"
1296
- version = "2.10.5"
1296
+ version = "2.10.7"
1297
1297
  source = { editable = "." }
1298
1298
  dependencies = [
1299
1299
  { name = "beautifulsoup4" },
File without changes