From 3f4bee2c47e942c34b96707f2fc8aa5cd86f1c86 Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Tue, 2 Jun 2026 23:06:36 -0400 Subject: [PATCH 1/3] ci: report e2e-* checks on fork and Dependabot PRs The e2e job is skipped on PRs that can't access repository secrets (forks and Dependabot). Because it's skipped via a job-level `if`, its matrix never expands, so the required e2e-* check contexts are never created and branch protection waits on them indefinitely, blocking merge. Add an e2e-bypass job whose `if` is the exact negation of the e2e job's run condition. It emits the same e2e-* check names with a passing status for fork/Dependabot PRs, satisfying branch protection without running the real tests. The two jobs are mutually exclusive and exhaustive: every PR runs exactly one. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --- .github/workflows/e2e-test.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index f233115..1dab8a8 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -104,3 +104,34 @@ jobs: env: SOCKET_SECURITY_API_KEY: ${{ secrets.SOCKET_CLI_API_TOKEN }} run: bash ${{ matrix.validate }} + + # Branch protection requires the e2e-* checks, but the `e2e` job above is + # skipped on PRs that can't access repository secrets -- fork PRs and + # Dependabot PRs. A job skipped via a job-level `if` never expands its + # matrix, so the e2e-* check contexts are never created and the required + # checks sit at "Expected -- Waiting for status to be reported" forever, + # permanently blocking merge. + # + # This bypass reports a green status under the SAME e2e-* check names for + # exactly those PRs, satisfying branch protection without running the real + # tests (which need SOCKET_CLI_API_TOKEN). Its `if` is the precise negation + # of the e2e job's run condition, so the two are mutually exclusive: any + # given PR runs one or the other, never both, and never neither. + # + # Dependency-bump risk on these PRs is still covered by dependency-review.yml's + # Socket Firewall smoke jobs, which run without repository secrets. + e2e-bypass: + if: >- + github.event_name == 'pull_request' && + (github.event.pull_request.head.repo.full_name != github.repository || + github.event.pull_request.user.login == 'dependabot[bot]') + runs-on: ubuntu-latest + strategy: + matrix: + name: [scan, sarif, reachability, gitlab, json, pypi] + name: e2e-${{ matrix.name }} + steps: + - name: Report skip status + run: | + echo "Skipping e2e-${{ matrix.name }} for a PR without repository secrets" + echo "(fork or Dependabot). Dependency risk is covered by dependency-review.yml." From 14acbba1b44548f1fad17e1b49c4f86cccf1daba Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:35:12 -0400 Subject: [PATCH 2/3] ci: add dependency-review-gate aggregator check The Socket Firewall enterprise smoke job is the most meaningful supply-chain check for maintainer-added dependencies, but it can't be required directly: it's conditional (per-manifest, and free-vs-enterprise per author), so on most PRs it's legitimately skipped -- and a required check whose job is skipped sits at "Expected -- Waiting for status" forever, blocking merge (the same trap that stranded Dependabot PRs on the e2e-* checks). Add a dependency-review-gate job that always runs and collapses every smoke job into one pass/fail signal: it fails iff any job that ran ended in failure or was cancelled; success and skipped both pass. This is the single check intended to be marked required later -- it satisfies Dependabot/fork PRs (which run Firewall-free) and maintainer PRs (Firewall-enterprise) alike, and turns a Socket Firewall BLOCK into a merge-blocking failure instead of a non-required job nobody is forced to run. Scaffolding only: the gate is not yet added to branch protection's required checks (deferred until it's merged to main and observed reporting). Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --- .github/workflows/dependency-review.yml | 65 +++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 58c3f39..a39694f 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -586,3 +586,68 @@ jobs: echo "This PR changes workflow, composite-action, or dependabot config files." echo "Require explicit human review before merge." } >> "$GITHUB_STEP_SUMMARY" + + # Single required status check that aggregates the conditional smoke jobs + # above. Branch protection can't require those jobs individually: each is + # conditional (per-manifest, and Firewall-free vs -enterprise per author), so + # on any given PR most are legitimately skipped -- and a required check whose + # job is skipped sits at "Expected -- Waiting for status to be reported" + # forever, blocking merge (the same trap that stranded Dependabot PRs on the + # e2e-* checks). + # + # This gate always runs (if: always(), so it reports even when upstream jobs + # are skipped or fail) and collapses them into one pass/fail signal: it FAILS + # if any smoke job that ran ended in failure or was cancelled, and passes when + # everything either succeeded or was not applicable. 'skipped' is expected and + # allowed -- it just means the job didn't apply to this PR. + # + # Mark THIS check (dependency-review-gate) required in branch protection. It + # satisfies Dependabot/fork PRs (which run the Firewall-free job) and + # maintainer PRs (which run Firewall-enterprise) alike, and -- crucially -- a + # Socket Firewall BLOCK now fails the gate and blocks merge, instead of living + # in a non-required enterprise job that nobody is forced to run. + dependency-review-gate: + needs: + - inspect + - python-sfw-smoke-free + - python-sfw-smoke-enterprise + - fixture-npm-sfw-smoke-free + - fixture-npm-sfw-smoke-enterprise + - fixture-pypi-sfw-smoke-free + - fixture-pypi-sfw-smoke-enterprise + - dockerfile-smoke + if: always() + runs-on: ubuntu-latest + timeout-minutes: 2 + steps: + - name: Verify no smoke job failed + env: + RESULTS: ${{ toJSON(needs) }} + run: | + echo "Upstream job results:" + printf '%s\n' "$RESULTS" | python3 -m json.tool + + # Fail the gate if any needed job ended in failure or was cancelled. + # 'success' and 'skipped' both pass: skipped means the job did not + # apply to this PR (wrong manifest, or free-vs-enterprise mismatch). + failed="$(printf '%s\n' "$RESULTS" | python3 -c " + import json, sys + data = json.load(sys.stdin) + bad = [name for name, info in data.items() + if info.get('result') in ('failure', 'cancelled')] + print(' '.join(sorted(bad))) + ")" + + if [ -n "$failed" ]; then + echo "::error::dependency-review smoke job(s) failed: $failed" + { + echo "## Dependency Review Gate: FAILED" + echo "The following smoke job(s) failed or were cancelled: \`$failed\`" + echo "If a Socket Firewall job is listed, it likely BLOCKED an install --" + echo "inspect its uploaded sfw-artifacts/ report before merging." + } >> "$GITHUB_STEP_SUMMARY" + exit 1 + fi + + echo "All dependency-review smoke jobs passed or were not applicable." + echo "## Dependency Review Gate: PASSED" >> "$GITHUB_STEP_SUMMARY" From 9449d14086c180840dd1dbf4d6e8e0d418deea4a Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Wed, 3 Jun 2026 14:13:08 -0400 Subject: [PATCH 3/3] chore: bump CLI to 2.4.5 and require socketdev>=3.2.1 Follows the 2.4.4 release (SDK >=3.2.0) by picking up socketdev 3.2.1. Regenerates uv.lock to the published 3.2.1 release; no CLI logic changes. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --- CHANGELOG.md | 7 +++++++ pyproject.toml | 4 ++-- socketsecurity/__init__.py | 2 +- uv.lock | 10 +++++----- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57d25bb..b2ea93d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 2.4.5 + +### Changed: Bump required SDK version to `>=3.2.1` + +- Picks up `socketdev 3.2.1`. +- No CLI logic changes. + ## 2.4.4 ### Changed: Bump required SDK version to `>=3.2.0` diff --git a/pyproject.toml b/pyproject.toml index fdbc17e..12955b8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "socketsecurity" -version = "2.4.4" +version = "2.4.5" requires-python = ">= 3.11" license = {"file" = "LICENSE"} dependencies = [ @@ -16,7 +16,7 @@ dependencies = [ 'GitPython', 'packaging', 'python-dotenv', - "socketdev>=3.2.0,<4.0.0", + "socketdev>=3.2.1,<4.0.0", "bs4>=0.0.2", "markdown>=3.10", "brotli>=1.0.9; platform_python_implementation == 'CPython'", diff --git a/socketsecurity/__init__.py b/socketsecurity/__init__.py index 4bda66b..de36ffe 100644 --- a/socketsecurity/__init__.py +++ b/socketsecurity/__init__.py @@ -1,3 +1,3 @@ __author__ = 'socket.dev' -__version__ = '2.4.4' +__version__ = '2.4.5' USER_AGENT = f'SocketPythonCLI/{__version__}' diff --git a/uv.lock b/uv.lock index dde139a..0a53c6b 100644 --- a/uv.lock +++ b/uv.lock @@ -1257,20 +1257,20 @@ wheels = [ [[package]] name = "socketdev" -version = "3.2.0" +version = "3.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/05/0748d1a357a743f968475aecfad4d53ce109ae65fc418d177faecbb25754/socketdev-3.2.0.tar.gz", hash = "sha256:d8743e1a83135f17e8713539c656b4847ada1450315b05e48ec8df1ed984c307", size = 178440, upload-time = "2026-06-03T02:47:26.696Z" } +sdist = { url = "https://files.pythonhosted.org/packages/21/65/07df2bf6e490c56544fb06e4cfde059b2572fdd5b02ff352c766b1d5f7ce/socketdev-3.2.1.tar.gz", hash = "sha256:7db910a98628473e8ec06822deb01b6bd465b385e9e8ea405f2b7526e8258074", size = 179279, upload-time = "2026-06-03T18:08:19.806Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/b5/6a3b2bcec759d5d306f416e1b167b985f44f89e990afcd25569a2e591ffd/socketdev-3.2.0-py3-none-any.whl", hash = "sha256:e4b97bdc22ec8e12899f218c8089eaa8e9696f7556930e13f05996ad210718af", size = 67267, upload-time = "2026-06-03T02:47:24.76Z" }, + { url = "https://files.pythonhosted.org/packages/53/01/fff70923755b3a187ca971189fb078a2aaedcad42d682abfdd06f3445def/socketdev-3.2.1-py3-none-any.whl", hash = "sha256:6dc762d78baea8011dc22f2afe49c84c926e640a6879bd7b58c3abdd4e29e8bb", size = 67266, upload-time = "2026-06-03T18:08:18.029Z" }, ] [[package]] name = "socketsecurity" -version = "2.4.4" +version = "2.4.5" source = { editable = "." } dependencies = [ { name = "brotli", marker = "platform_python_implementation == 'CPython'" }, @@ -1327,7 +1327,7 @@ requires-dist = [ { name = "python-dotenv" }, { name = "requests" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.3.0" }, - { name = "socketdev", specifier = ">=3.2.0,<4.0.0" }, + { name = "socketdev", specifier = ">=3.2.1,<4.0.0" }, { name = "twine", marker = "extra == 'dev'" }, { name = "uv", marker = "extra == 'dev'", specifier = ">=0.1.0" }, ]