socketsecurity 2.5.9__tar.gz → 2.6.0__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 (156) hide show
  1. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/actions/setup-docker/action.yml +5 -0
  2. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/workflows/dependency-review.yml +4 -1
  3. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/workflows/e2e-test.yml +48 -1
  4. socketsecurity-2.6.0/.github/workflows/package-check.yml +66 -0
  5. socketsecurity-2.6.0/.github/workflows/pr-preview.yml +306 -0
  6. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/workflows/release.yml +21 -7
  7. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.hooks/sync_version.py +34 -2
  8. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/CHANGELOG.md +24 -0
  9. socketsecurity-2.6.0/CONTRIBUTING.md +62 -0
  10. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/Dockerfile +27 -7
  11. socketsecurity-2.6.0/Dockerfile.preview +68 -0
  12. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/PKG-INFO +12 -12
  13. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/pyproject.toml +13 -13
  14. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/__init__.py +1 -1
  15. socketsecurity-2.6.0/tests/e2e/reach-facts-probe.sh +19 -0
  16. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/e2e/validate-reachability.sh +19 -0
  17. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/uv.lock +16 -28
  18. socketsecurity-2.5.9/.github/workflows/pr-preview.yml +0 -169
  19. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/CODEOWNERS +0 -0
  20. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/PULL_REQUEST_TEMPLATE/bug-fix.md +0 -0
  21. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/PULL_REQUEST_TEMPLATE/feature.md +0 -0
  22. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/PULL_REQUEST_TEMPLATE/improvement.md +0 -0
  23. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  24. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/actions/setup-hatch/action.yml +0 -0
  25. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/actions/setup-sfw/action.yml +0 -0
  26. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/dependabot.yml +0 -0
  27. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/workflows/docker-stable.yml +0 -0
  28. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/workflows/python-tests.yml +0 -0
  29. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/workflows/version-check.yml +0 -0
  30. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.github/zizmor.yml +0 -0
  31. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.gitignore +0 -0
  32. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.pre-commit-config.yaml +0 -0
  33. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/.python-version +0 -0
  34. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/LICENSE +0 -0
  35. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/Makefile +0 -0
  36. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/README.md +0 -0
  37. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/docs/ci-cd.md +0 -0
  38. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/docs/cli-reference.md +0 -0
  39. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/docs/development.md +0 -0
  40. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/docs/troubleshooting.md +0 -0
  41. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/examples/config/sarif-dashboard-parity.json +0 -0
  42. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/examples/config/sarif-dashboard-parity.toml +0 -0
  43. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/examples/config/sarif-diff-ci-cd.json +0 -0
  44. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/examples/config/sarif-diff-ci-cd.toml +0 -0
  45. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/examples/config/sarif-instance-detail.json +0 -0
  46. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/examples/config/sarif-instance-detail.toml +0 -0
  47. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/instructions/gitlab-commit-status/uat.md +0 -0
  48. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/pytest.ini +0 -0
  49. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/scripts/build_container.sh +0 -0
  50. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/scripts/build_container_flexible.sh +0 -0
  51. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/scripts/deploy-test-docker.sh +0 -0
  52. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/scripts/deploy-test-pypi.sh +0 -0
  53. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/scripts/docker-entrypoint.sh +0 -0
  54. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/scripts/run.sh +0 -0
  55. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/session.md +0 -0
  56. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socket.yml +0 -0
  57. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/config.py +0 -0
  58. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/__init__.py +0 -0
  59. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/alert_selection.py +0 -0
  60. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/classes.py +0 -0
  61. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/cli_client.py +0 -0
  62. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/cli_run.py +0 -0
  63. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/exceptions.py +0 -0
  64. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/git_interface.py +0 -0
  65. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/helper/__init__.py +0 -0
  66. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/helper/socket_facts_loader.py +0 -0
  67. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/lazy_file_loader.py +0 -0
  68. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/log_uploader.py +0 -0
  69. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/logging.py +0 -0
  70. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/messages.py +0 -0
  71. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/resource_utils.py +0 -0
  72. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/scm/__init__.py +0 -0
  73. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/scm/base.py +0 -0
  74. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/scm/client.py +0 -0
  75. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/scm/github.py +0 -0
  76. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/scm/gitlab.py +0 -0
  77. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/scm_comments.py +0 -0
  78. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/socket_config.py +0 -0
  79. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/streaming.py +0 -0
  80. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/tools/reachability.py +0 -0
  81. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/core/utils.py +0 -0
  82. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/fossa_compat.py +0 -0
  83. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/output.py +0 -0
  84. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/plugins/__init__.py +0 -0
  85. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/plugins/base.py +0 -0
  86. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/plugins/formatters/__init__.py +0 -0
  87. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/plugins/formatters/slack.py +0 -0
  88. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/plugins/jira.py +0 -0
  89. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/plugins/manager.py +0 -0
  90. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/plugins/slack.py +0 -0
  91. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/plugins/teams.py +0 -0
  92. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/plugins/webhook.py +0 -0
  93. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/socketsecurity/socketcli.py +0 -0
  94. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/__init__.py +0 -0
  95. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/core/conftest.py +0 -0
  96. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/core/create_diff_input.json +0 -0
  97. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/core/test_diff_alerts.py +0 -0
  98. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/core/test_diff_generation.py +0 -0
  99. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/core/test_facts_compression.py +0 -0
  100. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/core/test_has_manifest_files.py +0 -0
  101. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/core/test_package_and_alerts.py +0 -0
  102. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/core/test_sdk_methods.py +0 -0
  103. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/core/test_supporting_methods.py +0 -0
  104. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/data/fullscans/create_response.json +0 -0
  105. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/data/fullscans/diff/stream_diff.json +0 -0
  106. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/data/fullscans/diff/stream_diff_full.json +0 -0
  107. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/data/fullscans/head_scan/metadata.json +0 -0
  108. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/data/fullscans/head_scan/stream_scan.json +0 -0
  109. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/data/fullscans/head_scan/stream_scan_full.json +0 -0
  110. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/data/fullscans/new_scan/metadata.json +0 -0
  111. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/data/fullscans/new_scan/stream_scan.json +0 -0
  112. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/data/repos/repo_info_error.json +0 -0
  113. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/data/repos/repo_info_no_head.json +0 -0
  114. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/data/repos/repo_info_success.json +0 -0
  115. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/data/settings/security-policy.json +0 -0
  116. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/e2e/fixtures/simple-npm/index.js +0 -0
  117. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/e2e/fixtures/simple-npm/package.json +0 -0
  118. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/e2e/fixtures/simple-pypi/requirements.txt +0 -0
  119. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/e2e/validate-gitlab.sh +0 -0
  120. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/e2e/validate-json.sh +0 -0
  121. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/e2e/validate-sarif.sh +0 -0
  122. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/e2e/validate-scan.sh +0 -0
  123. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/fixtures/fossa/README.md +0 -0
  124. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/fixtures/fossa/fossa-analyze-empty.json +0 -0
  125. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/fixtures/fossa/fossa-analyze-populated.json +0 -0
  126. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/fixtures/fossa/fossa-sbom-empty-deep.json +0 -0
  127. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/fixtures/fossa/fossa-sbom-populated.json +0 -0
  128. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/__init__.py +0 -0
  129. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_alert_selection.py +0 -0
  130. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_cli_config.py +0 -0
  131. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_cli_run.py +0 -0
  132. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_client.py +0 -0
  133. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_config.py +0 -0
  134. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_dependency_overview.py +0 -0
  135. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_disable_ignore.py +0 -0
  136. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_exclude_paths.py +0 -0
  137. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_fossa_compat.py +0 -0
  138. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_fossa_parity.py +0 -0
  139. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_full_scan_retry.py +0 -0
  140. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_gitlab_auth.py +0 -0
  141. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_gitlab_auth_fallback.py +0 -0
  142. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_gitlab_commit_status.py +0 -0
  143. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_gitlab_format.py +0 -0
  144. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_ignore_telemetry_filtering.py +0 -0
  145. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_include_dirs.py +0 -0
  146. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_log_uploader.py +0 -0
  147. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_output.py +0 -0
  148. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_reachability.py +0 -0
  149. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_slack_plugin.py +0 -0
  150. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_socketcli.py +0 -0
  151. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_streaming.py +0 -0
  152. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/tests/unit/test_tier1_finalize.py +0 -0
  153. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/workflows/bitbucket-pipelines.yml +0 -0
  154. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/workflows/buildkite.yml +0 -0
  155. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/workflows/github-actions.yml +0 -0
  156. {socketsecurity-2.5.9 → socketsecurity-2.6.0}/workflows/gitlab-ci.yml +0 -0
@@ -5,6 +5,10 @@ description: >-
5
5
  preview, and stable workflows.
6
6
 
7
7
  inputs:
8
+ enable-qemu:
9
+ description: "Set up QEMU for multi-platform builds"
10
+ required: false
11
+ default: "true"
8
12
  dockerhub-username:
9
13
  description: "Docker Hub username (pass from secrets)"
10
14
  required: true
@@ -16,6 +20,7 @@ runs:
16
20
  using: "composite"
17
21
  steps:
18
22
  - uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
23
+ if: inputs.enable-qemu == 'true'
19
24
  - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
20
25
  - uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
21
26
  with:
@@ -571,7 +571,10 @@ jobs:
571
571
  persist-credentials: false
572
572
 
573
573
  - name: Build the Dockerfile (no push)
574
- run: docker build --pull -t socket-python-cli:dependabot-smoke .
574
+ run: >-
575
+ docker build --pull
576
+ --build-arg USE_LOCAL_INSTALL=true
577
+ -t socket-python-cli:dependabot-smoke .
575
578
 
576
579
  workflow-notice:
577
580
  needs: inspect
@@ -46,6 +46,11 @@ jobs:
46
46
  --enable-debug
47
47
  validate: tests/e2e/validate-reachability.sh
48
48
  setup-node: "true"
49
+ # The tier-1 reachability backend intermittently returns empty
50
+ # results while the CLI reports success. The probe exits 0 when
51
+ # the facts file has alerted components; anything else is
52
+ # retried before validation fails the job.
53
+ retry-probe: bash tests/e2e/reach-facts-probe.sh tests/e2e/fixtures/simple-npm
49
54
 
50
55
  - name: gitlab
51
56
  args: >-
@@ -94,17 +99,59 @@ jobs:
94
99
  run: pip install uv
95
100
 
96
101
  - name: Run Socket CLI
102
+ id: run-cli
97
103
  env:
98
104
  SOCKET_SECURITY_API_KEY: ${{ secrets.SOCKET_CLI_API_TOKEN }}
105
+ RETRY_PROBE: ${{ matrix.retry-probe }}
99
106
  run: |
100
107
  set -o pipefail
101
- socketcli ${{ matrix.args }} 2>&1 | tee /tmp/e2e-output.log
108
+ # Entries with retry-probe get up to 3 attempts: the probe exits 0
109
+ # when the scan output looks complete, and a run that fails it is
110
+ # re-run on the assumption of a transient backend failure. A
111
+ # persistent incomplete result still reaches validation. Validation
112
+ # only treats the explicit zero-project backend signature as
113
+ # inconclusive; any other empty result remains a failure. Retries are
114
+ # surfaced as warning annotations so flake frequency stays visible.
115
+ max_attempts=3
116
+ attempt=1
117
+ while :; do
118
+ socketcli ${{ matrix.args }} 2>&1 | tee /tmp/e2e-output.log
119
+ [ -z "$RETRY_PROBE" ] && break
120
+ if bash -c "$RETRY_PROBE"; then
121
+ break
122
+ fi
123
+ if [ "$attempt" -ge "$max_attempts" ]; then
124
+ echo "::warning title=e2e-${{ matrix.name }} incomplete results::output still fails the completeness probe after ${max_attempts} attempts; letting validation classify the result"
125
+ echo "diagnostics=true" >> "$GITHUB_OUTPUT"
126
+ break
127
+ fi
128
+ echo "::warning title=e2e-${{ matrix.name }} transient retry::attempt ${attempt} failed the completeness probe (suspected backend transient); retrying"
129
+ echo "e2e-${{ matrix.name }}: retry after attempt ${attempt} — completeness probe failed (suspected transient)" >> "$GITHUB_STEP_SUMMARY"
130
+ attempt=$((attempt+1))
131
+ sleep 30
132
+ done
102
133
 
103
134
  - name: Validate results
104
135
  env:
105
136
  SOCKET_SECURITY_API_KEY: ${{ secrets.SOCKET_CLI_API_TOKEN }}
106
137
  run: bash ${{ matrix.validate }}
107
138
 
139
+ - name: Upload diagnostics on failure
140
+ if: failure() || steps.run-cli.outputs.diagnostics == 'true'
141
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
142
+ with:
143
+ name: e2e-${{ matrix.name }}-diagnostics-attempt${{ github.run_attempt }}
144
+ path: |
145
+ /tmp/e2e-output.log
146
+ /tmp/*.sarif
147
+ tests/e2e/fixtures/simple-npm/.socket.facts.json
148
+ tests/e2e/fixtures/simple-pypi/.socket.facts.json
149
+ gl-*.json
150
+ license_output.json
151
+ if-no-files-found: ignore
152
+ include-hidden-files: true
153
+ retention-days: 14
154
+
108
155
  # Branch protection requires the e2e-* checks, but the `e2e` job above is
109
156
  # skipped on PRs that can't access repository secrets -- fork PRs and
110
157
  # Dependabot PRs. A job skipped via a job-level `if` never expands its
@@ -0,0 +1,66 @@
1
+ name: Package Check
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: package-check-${{ github.event.pull_request.number || github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ package-check:
18
+ runs-on: ubuntu-latest
19
+ timeout-minutes: 10
20
+ steps:
21
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
22
+ with:
23
+ fetch-depth: 1
24
+ persist-credentials: false
25
+
26
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
27
+ with:
28
+ python-version: "3.12"
29
+
30
+ - name: Install build tooling
31
+ uses: ./.github/actions/setup-hatch
32
+
33
+ - name: Install distribution validator
34
+ run: python -m pip install "twine>=4.0.0"
35
+
36
+ - name: Build distributions
37
+ run: hatch build
38
+
39
+ - name: Validate distributions
40
+ run: python -m twine check dist/*
41
+
42
+ - name: Install and inspect wheel without resolving dependencies
43
+ run: |
44
+ python -m venv "$RUNNER_TEMP/package-check"
45
+ "$RUNNER_TEMP/package-check/bin/pip" install --no-deps dist/*.whl
46
+ "$RUNNER_TEMP/package-check/bin/python" - <<'PY'
47
+ import compileall
48
+ import importlib.metadata
49
+ import pathlib
50
+ import sysconfig
51
+
52
+ distribution = importlib.metadata.distribution("socketsecurity")
53
+ entry_points = {entry_point.name for entry_point in distribution.entry_points}
54
+ assert "socketcli" in entry_points
55
+ package = pathlib.Path(sysconfig.get_paths()["purelib"]) / "socketsecurity"
56
+ assert compileall.compile_dir(package, quiet=1)
57
+ print("wheel metadata and bytecode smoke OK", distribution.version)
58
+ PY
59
+
60
+ - name: Upload distributions
61
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
62
+ with:
63
+ name: socketsecurity-${{ github.sha }}
64
+ path: dist/*
65
+ if-no-files-found: error
66
+ retention-days: 14
@@ -0,0 +1,306 @@
1
+ name: Publish PR Preview
2
+
3
+ on:
4
+ pull_request:
5
+ types: [labeled]
6
+ workflow_dispatch:
7
+ inputs:
8
+ pr_number:
9
+ description: Pull request number to publish
10
+ required: true
11
+ type: string
12
+ publish_test_pypi:
13
+ description: Publish the Python package to TestPyPI
14
+ required: true
15
+ default: true
16
+ type: boolean
17
+ publish_docker:
18
+ description: Publish socketdev/cli:pr-<number> to Docker Hub
19
+ required: true
20
+ default: false
21
+ type: boolean
22
+ sdk_preview_version:
23
+ description: Optional exact TestPyPI socketdev prerelease for the Docker image
24
+ required: false
25
+ type: string
26
+
27
+ concurrency:
28
+ group: publish-pr-preview-${{ github.event.pull_request.number || github.run_id }}
29
+ cancel-in-progress: false
30
+
31
+ jobs:
32
+ context:
33
+ if: >-
34
+ github.event_name == 'workflow_dispatch' ||
35
+ (github.event.label.name == 'publish-preview' ||
36
+ github.event.label.name == 'publish-docker-preview') &&
37
+ github.event.pull_request.head.repo.full_name == github.repository
38
+ runs-on: ubuntu-latest
39
+ timeout-minutes: 5
40
+ permissions:
41
+ contents: read
42
+ pull-requests: read
43
+ outputs:
44
+ pr_number: ${{ steps.context.outputs.pr_number }}
45
+ head_sha: ${{ steps.context.outputs.head_sha }}
46
+ steps:
47
+ - name: Validate pull request context
48
+ id: context
49
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
50
+ env:
51
+ DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
52
+ EVENT_PR_NUMBER: ${{ github.event.pull_request.number }}
53
+ INPUT_PR_NUMBER: ${{ inputs.pr_number }}
54
+ WORKFLOW_REF: ${{ github.ref }}
55
+ with:
56
+ script: |
57
+ const rawPrNumber = context.eventName === 'workflow_dispatch'
58
+ ? process.env.INPUT_PR_NUMBER
59
+ : process.env.EVENT_PR_NUMBER;
60
+ if (!/^[1-9][0-9]*$/.test(rawPrNumber || '')) {
61
+ core.setFailed('Pull request number must contain ASCII digits only.');
62
+ return;
63
+ }
64
+
65
+ if (context.eventName === 'workflow_dispatch') {
66
+ const defaultRef = `refs/heads/${process.env.DEFAULT_BRANCH}`;
67
+ if (process.env.WORKFLOW_REF !== defaultRef) {
68
+ core.setFailed(`Run manual previews from ${defaultRef}.`);
69
+ return;
70
+ }
71
+ }
72
+
73
+ const prNumber = Number(rawPrNumber);
74
+ if (!Number.isSafeInteger(prNumber)) {
75
+ core.setFailed('Pull request number is outside the supported range.');
76
+ return;
77
+ }
78
+ const {data: pullRequest} = await github.rest.pulls.get({
79
+ owner: context.repo.owner,
80
+ repo: context.repo.repo,
81
+ pull_number: prNumber,
82
+ });
83
+ if (pullRequest.state !== 'open') {
84
+ core.setFailed(`Pull request #${prNumber} is not open.`);
85
+ return;
86
+ }
87
+ if (pullRequest.head.repo?.full_name !== `${context.repo.owner}/${context.repo.repo}`) {
88
+ core.setFailed('Preview publication is limited to branches in this repository.');
89
+ return;
90
+ }
91
+
92
+ core.setOutput('pr_number', String(prNumber));
93
+ core.setOutput('head_sha', pullRequest.head.sha);
94
+
95
+ build:
96
+ needs: context
97
+ runs-on: ubuntu-latest
98
+ timeout-minutes: 10
99
+ permissions:
100
+ contents: read
101
+ outputs:
102
+ preview_version: ${{ steps.version.outputs.preview_version }}
103
+ steps:
104
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
105
+ with:
106
+ ref: ${{ needs.context.outputs.head_sha }}
107
+ fetch-depth: 0
108
+ persist-credentials: false
109
+
110
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
111
+ with:
112
+ python-version: "3.12"
113
+
114
+ - name: Install build tooling
115
+ uses: ./.github/actions/setup-hatch
116
+
117
+ - name: Install distribution validator
118
+ run: python -m pip install "twine>=4.0.0"
119
+
120
+ - name: Inject deterministic preview version
121
+ env:
122
+ PREVIEW_ID: ${{ github.run_id }}
123
+ RUN_ATTEMPT: ${{ github.run_attempt }}
124
+ run: |
125
+ PREVIEW_ID=$((PREVIEW_ID * 100 + RUN_ATTEMPT))
126
+ python .hooks/sync_version.py --dev --preview-id "$PREVIEW_ID" --skip-lock
127
+
128
+ - name: Read preview version
129
+ id: version
130
+ run: echo "preview_version=$(hatch version)" >> "$GITHUB_OUTPUT"
131
+
132
+ - name: Build and validate distributions
133
+ run: |
134
+ hatch build
135
+ python -m twine check dist/*
136
+
137
+ - name: Install and inspect wheel locally
138
+ run: |
139
+ python -m venv "$RUNNER_TEMP/preview-check"
140
+ "$RUNNER_TEMP/preview-check/bin/pip" install --no-deps dist/*.whl
141
+ "$RUNNER_TEMP/preview-check/bin/python" - <<'PY'
142
+ import compileall
143
+ import importlib.metadata
144
+ import pathlib
145
+ import sysconfig
146
+
147
+ distribution = importlib.metadata.distribution("socketsecurity")
148
+ entry_points = {entry_point.name for entry_point in distribution.entry_points}
149
+ assert "socketcli" in entry_points
150
+ package = pathlib.Path(sysconfig.get_paths()["purelib"]) / "socketsecurity"
151
+ assert compileall.compile_dir(package, quiet=1)
152
+ print("preview wheel smoke OK", distribution.version)
153
+ PY
154
+
155
+ - name: Upload preview distributions
156
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
157
+ with:
158
+ name: socketsecurity-preview-${{ github.run_id }}-${{ github.run_attempt }}
159
+ path: dist/*
160
+ if-no-files-found: error
161
+ retention-days: 14
162
+
163
+ publish-package:
164
+ needs: [context, build]
165
+ if: >-
166
+ github.event.label.name == 'publish-preview' ||
167
+ (github.event_name == 'workflow_dispatch' && inputs.publish_test_pypi)
168
+ runs-on: ubuntu-latest
169
+ timeout-minutes: 10
170
+ permissions:
171
+ contents: read
172
+ id-token: write
173
+ pull-requests: write
174
+ steps:
175
+ - name: Download preview distributions
176
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
177
+ with:
178
+ name: socketsecurity-preview-${{ github.run_id }}-${{ github.run_attempt }}
179
+ path: dist
180
+
181
+ - name: Publish to TestPyPI
182
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
183
+ with:
184
+ repository-url: https://test.pypi.org/legacy/
185
+ verbose: true
186
+
187
+ - name: Comment on pull request
188
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
189
+ env:
190
+ PREVIEW_VERSION: ${{ needs.build.outputs.preview_version }}
191
+ PR_NUMBER: ${{ needs.context.outputs.pr_number }}
192
+ with:
193
+ script: |
194
+ const marker = '<!-- socketsecurity-pr-preview -->';
195
+ const prNumber = Number(process.env.PR_NUMBER);
196
+ const version = process.env.PREVIEW_VERSION;
197
+ const body = `${marker}
198
+ 🚀 CLI preview published: \`socketsecurity==${version}\`
199
+
200
+ \`\`\`bash
201
+ pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple socketsecurity==${version}
202
+ \`\`\`
203
+
204
+ TestPyPI's package index can take several minutes to expose a newly uploaded version.`;
205
+ const {data: comments} = await github.rest.issues.listComments({
206
+ owner: context.repo.owner,
207
+ repo: context.repo.repo,
208
+ issue_number: prNumber,
209
+ });
210
+ const existing = comments.find(comment =>
211
+ comment.user.type === 'Bot' && comment.body.includes(marker)
212
+ );
213
+ if (existing) {
214
+ await github.rest.issues.updateComment({
215
+ owner: context.repo.owner,
216
+ repo: context.repo.repo,
217
+ comment_id: existing.id,
218
+ body,
219
+ });
220
+ } else {
221
+ await github.rest.issues.createComment({
222
+ owner: context.repo.owner,
223
+ repo: context.repo.repo,
224
+ issue_number: prNumber,
225
+ body,
226
+ });
227
+ }
228
+
229
+ publish-docker:
230
+ needs: [context, build]
231
+ if: >-
232
+ github.event.label.name == 'publish-docker-preview' ||
233
+ (github.event_name == 'workflow_dispatch' && inputs.publish_docker)
234
+ runs-on: ubuntu-latest
235
+ timeout-minutes: 15
236
+ permissions:
237
+ contents: read
238
+ pull-requests: write
239
+ steps:
240
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
241
+ with:
242
+ # Keep the Dockerfile and credential-handling action on trusted code.
243
+ # The pull request enters this job only through the built wheel.
244
+ ref: ${{ github.event.repository.default_branch }}
245
+ fetch-depth: 1
246
+ persist-credentials: false
247
+
248
+ - name: Download preview distributions
249
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
250
+ with:
251
+ name: socketsecurity-preview-${{ github.run_id }}-${{ github.run_attempt }}
252
+ path: dist
253
+
254
+ - name: Set up Docker publishing
255
+ uses: ./.github/actions/setup-docker
256
+ with:
257
+ enable-qemu: "false"
258
+ dockerhub-username: ${{ secrets.DOCKERHUB_USERNAME }}
259
+ dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }}
260
+
261
+ - name: Build and push Docker preview
262
+ uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
263
+ with:
264
+ file: Dockerfile.preview
265
+ push: true
266
+ pull: true
267
+ platforms: linux/amd64
268
+ tags: socketdev/cli:pr-${{ needs.context.outputs.pr_number }}
269
+ build-args: |
270
+ SDK_PREVIEW_VERSION=${{ inputs.sdk_preview_version }}
271
+
272
+ - name: Comment on pull request
273
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
274
+ env:
275
+ PR_NUMBER: ${{ needs.context.outputs.pr_number }}
276
+ with:
277
+ script: |
278
+ const marker = '<!-- socketsecurity-docker-preview -->';
279
+ const prNumber = Number(process.env.PR_NUMBER);
280
+ const body = `${marker}
281
+ 🐳 Docker preview published: \`socketdev/cli:pr-${prNumber}\`
282
+
283
+ This mutable tag is only created when a Docker preview is explicitly requested.`;
284
+ const {data: comments} = await github.rest.issues.listComments({
285
+ owner: context.repo.owner,
286
+ repo: context.repo.repo,
287
+ issue_number: prNumber,
288
+ });
289
+ const existing = comments.find(comment =>
290
+ comment.user.type === 'Bot' && comment.body.includes(marker)
291
+ );
292
+ if (existing) {
293
+ await github.rest.issues.updateComment({
294
+ owner: context.repo.owner,
295
+ repo: context.repo.repo,
296
+ comment_id: existing.id,
297
+ body,
298
+ });
299
+ } else {
300
+ await github.rest.issues.createComment({
301
+ owner: context.repo.owner,
302
+ repo: context.repo.repo,
303
+ issue_number: prNumber,
304
+ body,
305
+ });
306
+ }
@@ -79,17 +79,31 @@ jobs:
79
79
  env:
80
80
  VERSION: ${{ env.VERSION }}
81
81
  run: |
82
- for i in {1..30}; do
83
- if pip install socketsecurity==${VERSION}; then
82
+ # The first lookup can race PyPI's Simple-index propagation, and a delayed
83
+ # CDN purge can leave the index stale well after a successful upload.
84
+ # pip caches HTTP responses by default, so without --no-cache-dir every
85
+ # retry can reuse that initial stale response instead of checking whether
86
+ # the release has appeared. Budget: 30 minutes.
87
+ MAX_ATTEMPTS=60
88
+ for i in $(seq 1 "$MAX_ATTEMPTS"); do
89
+ if python -m pip install \
90
+ --no-cache-dir \
91
+ --index-url https://pypi.org/simple/ \
92
+ "socketsecurity==${VERSION}"; then
84
93
  echo "Package ${VERSION} is now available and installable on PyPI"
85
- pip uninstall -y socketsecurity
86
- echo "success=true" >> $GITHUB_OUTPUT
94
+ python -m pip uninstall -y socketsecurity
95
+ echo "success=true" >> "$GITHUB_OUTPUT"
87
96
  exit 0
88
97
  fi
89
- echo "Attempt $i: Package not yet installable, waiting 20s... (${i}/30)"
90
- sleep 20
98
+ if curl -s -f "https://pypi.org/pypi/socketsecurity/${VERSION}/json" > /dev/null; then
99
+ echo "Release ${VERSION} exists on PyPI (JSON API) but is not in the Simple index yet - CDN propagation delay"
100
+ fi
101
+ if [ "$i" -lt "$MAX_ATTEMPTS" ]; then
102
+ echo "Attempt $i: Package not yet installable, waiting 30s... (${i}/${MAX_ATTEMPTS})"
103
+ sleep 30
104
+ fi
91
105
  done
92
- echo "success=false" >> $GITHUB_OUTPUT
106
+ echo "success=false" >> "$GITHUB_OUTPUT"
93
107
  exit 1
94
108
 
95
109
  - name: Build & Push Docker
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env python3
2
- import subprocess
2
+ import json
3
3
  import pathlib
4
4
  import re
5
+ import subprocess
5
6
  import sys
6
7
  import urllib.request
7
- import json
8
8
 
9
9
  INIT_FILE = pathlib.Path("socketsecurity/__init__.py")
10
10
  PYPROJECT_FILE = pathlib.Path("pyproject.toml")
@@ -125,13 +125,45 @@ def run_uv_lock() -> bool:
125
125
  after = UV_LOCK_FILE.read_bytes() if UV_LOCK_FILE.exists() else b""
126
126
  return before != after
127
127
 
128
+
129
+ def read_preview_id():
130
+ if "--preview-id" not in sys.argv:
131
+ return None
132
+
133
+ option_index = sys.argv.index("--preview-id")
134
+ try:
135
+ preview_id = sys.argv[option_index + 1]
136
+ except IndexError:
137
+ print("❌ `--preview-id` requires a numeric value.")
138
+ sys.exit(1)
139
+
140
+ if not preview_id.isascii() or not preview_id.isdigit():
141
+ print("❌ `--preview-id` must contain ASCII digits only.")
142
+ sys.exit(1)
143
+ return preview_id
144
+
145
+
128
146
  def main():
129
147
  dev_mode = "--dev" in sys.argv
148
+ skip_lock = "--skip-lock" in sys.argv
149
+ preview_id = read_preview_id()
130
150
  current_version = read_version_from_init(INIT_FILE)
131
151
  previous_version = read_version_from_git("socketsecurity/__init__.py")
132
152
 
133
153
  print(f"Current: {current_version}, Previous: {previous_version}")
134
154
 
155
+ if preview_id is not None:
156
+ if not dev_mode:
157
+ print("❌ `--preview-id` can only be used with `--dev`.")
158
+ sys.exit(1)
159
+ base_version = current_version.split(".dev")[0]
160
+ new_version = f"{base_version}.dev{preview_id}"
161
+ inject_version(new_version)
162
+ if not skip_lock:
163
+ run_uv_lock()
164
+ print(f"✅ Prepared deterministic preview version {new_version}.")
165
+ sys.exit(0)
166
+
135
167
  if current_version == previous_version:
136
168
  if dev_mode:
137
169
  base_version = current_version.split(".dev")[0] if ".dev" in current_version else current_version
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.6.0
4
+
5
+ ### Changed: pin all Python dependencies
6
+
7
+ - Pinned every runtime dependency in `pyproject.toml` to an exact version;
8
+ several were previously unpinned or open ranges.
9
+ - Replaced the `bs4` shim package with a direct, pinned `beautifulsoup4`
10
+ dependency (the shim provided no version control over the actual library).
11
+ - Pinned the bundled `socketdev` SDK to `3.5.0` (previously `>=3.3.0,<4.0.0`).
12
+ - Docker images now install Python dependencies from the committed `uv.lock`
13
+ with pip hash verification (`--require-hashes`), so image builds no longer
14
+ resolve dependency versions from PyPI at build time. `pip check` validates
15
+ the environment after install.
16
+ - Pinned the `hatchling` build backend and the `uv` binary used in the
17
+ Dockerfile.
18
+
19
+ ### Changed: e2e reachability jobs retry transient empty results
20
+
21
+ - Reachability e2e runs that report success with no alerted components in the
22
+ facts file are retried up to three times as a suspected transient backend
23
+ failure. After retries, only the known zero-project backend signature is
24
+ classified as inconclusive — any other empty result still fails — and e2e
25
+ jobs upload their logs and reports as diagnostics on failure.
26
+
3
27
  ## 2.5.9
4
28
 
5
29
  ### Changed: bump pinned @coana-tech/cli to 15.10.3
@@ -0,0 +1,62 @@
1
+ # Contributing
2
+
3
+ ## Development setup
4
+
5
+ Use Python 3.11 or newer and install
6
+ [`uv`](https://docs.astral.sh/uv/getting-started/installation/). From the
7
+ repository root, create the environment and install all development
8
+ dependencies:
9
+
10
+ ```bash
11
+ uv sync --all-extras
12
+ ```
13
+
14
+ Before opening a pull request, run:
15
+
16
+ ```bash
17
+ make test
18
+ uv run hatch build
19
+ uv run python -m twine check dist/*
20
+ ```
21
+
22
+ To develop against a local SDK checkout, set `SOCKET_SDK_PATH` if it is not at
23
+ `../socketdev`, then run `make first-time-local-setup`.
24
+
25
+ ## Pull request validation
26
+
27
+ The `Package Check` workflow runs automatically for pull requests. It builds
28
+ and validates the distributions, smoke-tests the wheel, and uploads the
29
+ distributions as workflow artifacts. It does not publish a package or Docker
30
+ image.
31
+
32
+ ## Publishing pull request previews
33
+
34
+ Preview publication is intentionally opt-in. Only request previews for code
35
+ that is trusted to run with the repository's publishing permissions.
36
+
37
+ For a pull request from this repository, apply the label for the artifact that
38
+ needs testing:
39
+
40
+ - `publish-preview` publishes a uniquely versioned `socketsecurity` prerelease
41
+ to TestPyPI and adds or updates a pull request comment with the exact version
42
+ and installation command.
43
+ - `publish-docker-preview` publishes the mutable
44
+ `socketdev/cli:pr-<pull-request-number>` image to Docker Hub and adds or
45
+ updates a pull request comment with the image tag.
46
+
47
+ Both label-triggered and manually dispatched previews are limited to open pull
48
+ requests whose branches belong to this repository. Each label is handled as a
49
+ separate event, so applying both labels starts two workflow runs. Use manual
50
+ dispatch instead when both artifacts should be published in a single run.
51
+
52
+ The workflow reacts when a label is added; pushing another commit while the
53
+ label remains on the pull request does not publish a new preview. To publish the
54
+ new pull request head or retry a failed publication, remove the relevant label
55
+ and apply it again.
56
+
57
+ Maintainers can also open **Actions > Publish PR Preview > Run workflow**, run
58
+ it from the repository's default branch, enter the pull request number, and
59
+ choose whether to publish to TestPyPI, Docker Hub, or both. When testing the CLI
60
+ against an SDK preview, enter the exact TestPyPI `socketdev` prerelease in
61
+ `sdk_preview_version`; publish the SDK preview first and allow time for
62
+ TestPyPI to expose it before starting the CLI Docker preview.