socketsecurity 2.5.9__tar.gz → 2.6.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/actions/setup-docker/action.yml +5 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/workflows/dependency-review.yml +4 -1
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/workflows/e2e-test.yml +48 -1
- socketsecurity-2.6.1/.github/workflows/package-check.yml +66 -0
- socketsecurity-2.6.1/.github/workflows/pr-preview.yml +306 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/workflows/release.yml +21 -7
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.hooks/sync_version.py +34 -2
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/CHANGELOG.md +46 -0
- socketsecurity-2.6.1/CONTRIBUTING.md +62 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/Dockerfile +27 -7
- socketsecurity-2.6.1/Dockerfile.preview +68 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/PKG-INFO +12 -12
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/pyproject.toml +13 -13
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/__init__.py +1 -1
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/__init__.py +183 -30
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/core/conftest.py +21 -0
- socketsecurity-2.6.1/tests/core/test_diff_scan_polling.py +122 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/core/test_sdk_methods.py +26 -12
- socketsecurity-2.6.1/tests/e2e/reach-facts-probe.sh +19 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/e2e/validate-reachability.sh +19 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/uv.lock +16 -28
- socketsecurity-2.5.9/.github/workflows/pr-preview.yml +0 -169
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/CODEOWNERS +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/PULL_REQUEST_TEMPLATE/bug-fix.md +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/PULL_REQUEST_TEMPLATE/feature.md +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/PULL_REQUEST_TEMPLATE/improvement.md +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/actions/setup-hatch/action.yml +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/actions/setup-sfw/action.yml +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/dependabot.yml +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/workflows/docker-stable.yml +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/workflows/python-tests.yml +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/workflows/version-check.yml +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.github/zizmor.yml +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.gitignore +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.pre-commit-config.yaml +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/.python-version +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/LICENSE +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/Makefile +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/README.md +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/docs/ci-cd.md +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/docs/cli-reference.md +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/docs/development.md +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/docs/troubleshooting.md +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/examples/config/sarif-dashboard-parity.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/examples/config/sarif-dashboard-parity.toml +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/examples/config/sarif-diff-ci-cd.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/examples/config/sarif-diff-ci-cd.toml +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/examples/config/sarif-instance-detail.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/examples/config/sarif-instance-detail.toml +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/instructions/gitlab-commit-status/uat.md +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/pytest.ini +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/scripts/build_container.sh +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/scripts/build_container_flexible.sh +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/scripts/deploy-test-docker.sh +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/scripts/deploy-test-pypi.sh +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/scripts/docker-entrypoint.sh +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/scripts/run.sh +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/session.md +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socket.yml +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/config.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/alert_selection.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/classes.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/cli_client.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/cli_run.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/exceptions.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/git_interface.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/helper/__init__.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/helper/socket_facts_loader.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/lazy_file_loader.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/log_uploader.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/logging.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/messages.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/resource_utils.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/scm/__init__.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/scm/base.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/scm/client.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/scm/github.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/scm/gitlab.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/scm_comments.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/socket_config.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/streaming.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/tools/reachability.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/core/utils.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/fossa_compat.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/output.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/plugins/__init__.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/plugins/base.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/plugins/formatters/__init__.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/plugins/formatters/slack.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/plugins/jira.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/plugins/manager.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/plugins/slack.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/plugins/teams.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/plugins/webhook.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/socketsecurity/socketcli.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/__init__.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/core/create_diff_input.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/core/test_diff_alerts.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/core/test_diff_generation.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/core/test_facts_compression.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/core/test_has_manifest_files.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/core/test_package_and_alerts.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/core/test_supporting_methods.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/data/fullscans/create_response.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/data/fullscans/diff/stream_diff.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/data/fullscans/diff/stream_diff_full.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/data/fullscans/head_scan/metadata.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/data/fullscans/head_scan/stream_scan.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/data/fullscans/head_scan/stream_scan_full.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/data/fullscans/new_scan/metadata.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/data/fullscans/new_scan/stream_scan.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/data/repos/repo_info_error.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/data/repos/repo_info_no_head.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/data/repos/repo_info_success.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/data/settings/security-policy.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/e2e/fixtures/simple-npm/index.js +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/e2e/fixtures/simple-npm/package.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/e2e/fixtures/simple-pypi/requirements.txt +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/e2e/validate-gitlab.sh +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/e2e/validate-json.sh +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/e2e/validate-sarif.sh +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/e2e/validate-scan.sh +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/fixtures/fossa/README.md +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/fixtures/fossa/fossa-analyze-empty.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/fixtures/fossa/fossa-analyze-populated.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/fixtures/fossa/fossa-sbom-empty-deep.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/fixtures/fossa/fossa-sbom-populated.json +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/__init__.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_alert_selection.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_cli_config.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_cli_run.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_client.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_config.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_dependency_overview.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_disable_ignore.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_exclude_paths.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_fossa_compat.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_fossa_parity.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_full_scan_retry.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_gitlab_auth.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_gitlab_auth_fallback.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_gitlab_commit_status.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_gitlab_format.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_ignore_telemetry_filtering.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_include_dirs.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_log_uploader.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_output.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_reachability.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_slack_plugin.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_socketcli.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_streaming.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/tests/unit/test_tier1_finalize.py +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/workflows/bitbucket-pipelines.yml +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/workflows/buildkite.yml +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/workflows/github-actions.yml +0 -0
- {socketsecurity-2.5.9 → socketsecurity-2.6.1}/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:
|
|
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
|
-
|
|
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
|
-
|
|
83
|
-
|
|
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
|
-
|
|
90
|
-
|
|
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
|
|
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,51 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.6.1
|
|
4
|
+
|
|
5
|
+
### Changed: scan comparison now polls the diff-scans endpoints
|
|
6
|
+
|
|
7
|
+
- Diff mode no longer holds a single idle HTTP connection open while the API
|
|
8
|
+
computes the scan comparison. The CLI now creates a diff-scan resource
|
|
9
|
+
(`POST /orgs/{org}/diff-scans/from-ids`) and polls
|
|
10
|
+
`GET /orgs/{org}/diff-scans/{id}?cached=true` with short, bounded requests
|
|
11
|
+
until the comparison is ready (HTTP 200 instead of 202). This fixes
|
|
12
|
+
intermittent `Connection reset by peer` failures on the final comparison
|
|
13
|
+
step when scans take several minutes to compare and network middleboxes
|
|
14
|
+
(e.g. Azure NAT gateways, which default to a 4-minute TCP idle timeout)
|
|
15
|
+
reap the idle connection.
|
|
16
|
+
- Duplicate scan pairs are resolved after an HTTP 409 and then polled through
|
|
17
|
+
the same cached endpoint. This avoids automatically following the API's 302
|
|
18
|
+
duplicate redirect with an uncached, potentially long-lived GET request.
|
|
19
|
+
- The change is transparent: no flags or workflow changes are needed. If the
|
|
20
|
+
org API token is missing the `diff-scans:create`, `diff-scans:list` or
|
|
21
|
+
`full-scans:list` scopes — or the new flow fails for any other reason — the
|
|
22
|
+
CLI logs a warning and falls back to the legacy streaming comparison.
|
|
23
|
+
- Requires the pinned `socketdev==3.5.0` SDK.
|
|
24
|
+
|
|
25
|
+
## 2.6.0
|
|
26
|
+
|
|
27
|
+
### Changed: pin all Python dependencies
|
|
28
|
+
|
|
29
|
+
- Pinned every runtime dependency in `pyproject.toml` to an exact version;
|
|
30
|
+
several were previously unpinned or open ranges.
|
|
31
|
+
- Replaced the `bs4` shim package with a direct, pinned `beautifulsoup4`
|
|
32
|
+
dependency (the shim provided no version control over the actual library).
|
|
33
|
+
- Pinned the bundled `socketdev` SDK to `3.5.0` (previously `>=3.3.0,<4.0.0`).
|
|
34
|
+
- Docker images now install Python dependencies from the committed `uv.lock`
|
|
35
|
+
with pip hash verification (`--require-hashes`), so image builds no longer
|
|
36
|
+
resolve dependency versions from PyPI at build time. `pip check` validates
|
|
37
|
+
the environment after install.
|
|
38
|
+
- Pinned the `hatchling` build backend and the `uv` binary used in the
|
|
39
|
+
Dockerfile.
|
|
40
|
+
|
|
41
|
+
### Changed: e2e reachability jobs retry transient empty results
|
|
42
|
+
|
|
43
|
+
- Reachability e2e runs that report success with no alerted components in the
|
|
44
|
+
facts file are retried up to three times as a suspected transient backend
|
|
45
|
+
failure. After retries, only the known zero-project backend signature is
|
|
46
|
+
classified as inconclusive — any other empty result still fails — and e2e
|
|
47
|
+
jobs upload their logs and reports as diagnostics on failure.
|
|
48
|
+
|
|
3
49
|
## 2.5.9
|
|
4
50
|
|
|
5
51
|
### Changed: bump pinned @coana-tech/cli to 15.10.3
|