From 7c3199115e0967c0015500b776432cba79fcfcf7 Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Wed, 8 Apr 2026 17:10:47 -0400 Subject: [PATCH 1/8] Backfill changelog for v2.2.74+ releases Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --- CHANGELOG.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 683e0ad..441189c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,44 @@ # Changelog +## [Unreleased] + +- Migrated license enrichment PURL lookup to the org-scoped endpoint (`POST /v0/orgs/{slug}/purl`) from the deprecated global endpoint (`POST /v0/purl`). + +## 2.2.80 + +- Hardened GitHub Actions workflows. +- Fixed broken links on PyPI page. + +## 2.2.79 + +- Updated minimum required Python version. +- Tweaked CI checks. + +## 2.2.78 + +- Fixed reachability filtering. +- Added config file support. + +## 2.2.77 + +- Fixed `has_manifest_files` failing to match root-level manifest files. + +## 2.2.76 + +- Added SARIF file output support. +- Improved reachability filtering. + +## 2.2.75 + +- Fixed `workspace` flag regression by updating SDK dependency. + +## 2.2.74 + +- Added `--workspace` flag to CLI args. +- Added GitLab branch protection flag. +- Added e2e tests for full scans and full scans with reachability. +- Bumped dependencies: `cryptography`, `virtualenv`, `filelock`, `urllib3`. + ## 2.2.71 - Added `strace` to the Docker image for debugging purposes. From f4f0a99724970ef4a5b5eac12e013d83b21d410c Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Wed, 8 Apr 2026 17:12:15 -0400 Subject: [PATCH 2/8] Migrate license enrichment to org-scoped endpoint Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --- .gitignore | 2 ++ socketsecurity/core/__init__.py | 1 + tests/core/test_package_and_alerts.py | 39 +++++++++++++++++++++- tests/e2e/fixtures/simple-npm/package.json | 2 +- 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index e01bafe..990cbcc 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,8 @@ test.py *.cpython-312.pyc` file_generator.py .coverage +.coverage.* +htmlcov/ .env.local Pipfile test/ diff --git a/socketsecurity/core/__init__.py b/socketsecurity/core/__init__.py index edd2814..154caf9 100644 --- a/socketsecurity/core/__init__.py +++ b/socketsecurity/core/__init__.py @@ -835,6 +835,7 @@ def get_license_text_via_purl(self, packages: dict[str, Package], batch_size: in results = self.sdk.purl.post( license=True, components=batch_components, + org_slug=self.config.org_slug, licenseattrib=True, licensedetails=True ) diff --git a/tests/core/test_package_and_alerts.py b/tests/core/test_package_and_alerts.py index 09a8455..f616479 100644 --- a/tests/core/test_package_and_alerts.py +++ b/tests/core/test_package_and_alerts.py @@ -228,4 +228,41 @@ def test_get_new_alerts_with_readded(self): # With ignore_readded=False new_alerts = Core.get_new_alerts(added_alerts, removed_alerts, ignore_readded=False) - assert len(new_alerts) == 1 + assert len(new_alerts) == 1 + + def test_get_license_text_via_purl_uses_org_scoped_endpoint(self, core, mock_sdk): + """Test license enrichment calls the org-scoped PURL SDK method.""" + core.sdk.purl = Mock() + core.sdk.purl.post.return_value = [ + { + "type": "npm", + "name": "lodash", + "version": "4.18.1", + "licenseAttrib": [{"name": "MIT"}], + "licenseDetails": [{"license": "MIT"}], + } + ] + + packages = { + "npm/lodash@4.18.1": Package( + id="pkg:npm/lodash@4.18.1", + type="npm", + name="lodash", + version="4.18.1", + score={}, + alerts=[], + topLevelAncestors=[], + ) + } + + result = core.get_license_text_via_purl(packages) + + core.sdk.purl.post.assert_called_once_with( + license=True, + components=[{"purl": "pkg:/npm/lodash@4.18.1"}], + org_slug="test-org", + licenseattrib=True, + licensedetails=True, + ) + assert result["npm/lodash@4.18.1"].licenseAttrib == [{"name": "MIT"}] + assert result["npm/lodash@4.18.1"].licenseDetails == [{"license": "MIT"}] diff --git a/tests/e2e/fixtures/simple-npm/package.json b/tests/e2e/fixtures/simple-npm/package.json index cf70416..3dd5fa9 100644 --- a/tests/e2e/fixtures/simple-npm/package.json +++ b/tests/e2e/fixtures/simple-npm/package.json @@ -4,7 +4,7 @@ "description": "Test fixture for reachability analysis", "main": "index.js", "dependencies": { - "lodash": "4.17.23", + "lodash": "4.18.1", "express": "4.22.0", "axios": "1.13.5" }, From 641e427d9a974cc60779fbe710047947beea6f79 Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Wed, 8 Apr 2026 17:21:32 -0400 Subject: [PATCH 3/8] Fix github project homepage on PyPI Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d401856..2a44c06 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ socketcli = "socketsecurity.socketcli:cli" socketclidev = "socketsecurity.socketcli:cli" [project.urls] -Homepage = "https://socket.dev" +Homepage = "https://github.com/SocketDev/socket-python-cli" [tool.coverage.run] source = ["socketsecurity"] From 2cc4bdded0ff8796ee4c1bcb8aca7e7914058a06 Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Wed, 8 Apr 2026 17:22:18 -0400 Subject: [PATCH 4/8] Bump version for release Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --- pyproject.toml | 2 +- socketsecurity/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2a44c06..3529ff4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "socketsecurity" -version = "2.2.78" +version = "2.2.79" requires-python = ">= 3.10" license = {"file" = "LICENSE"} dependencies = [ diff --git a/socketsecurity/__init__.py b/socketsecurity/__init__.py index 987c20b..e56db94 100644 --- a/socketsecurity/__init__.py +++ b/socketsecurity/__init__.py @@ -1,3 +1,3 @@ __author__ = 'socket.dev' -__version__ = '2.2.78' +__version__ = '2.2.79' USER_AGENT = f'SocketPythonCLI/{__version__}' From b0af1ae20117b5fcf6afc3e61d7e46bb3edf0852 Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Wed, 8 Apr 2026 17:27:54 -0400 Subject: [PATCH 5/8] Properly bump version Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --- pyproject.toml | 2 +- socketsecurity/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 67ba827..3a6e9c7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "socketsecurity" -version = "2.2.80" +version = "2.2.81" requires-python = ">= 3.11" license = {"file" = "LICENSE"} dependencies = [ diff --git a/socketsecurity/__init__.py b/socketsecurity/__init__.py index 92eb029..d4a1870 100644 --- a/socketsecurity/__init__.py +++ b/socketsecurity/__init__.py @@ -1,3 +1,3 @@ __author__ = 'socket.dev' -__version__ = '2.2.80' +__version__ = '2.2.81' USER_AGENT = f'SocketPythonCLI/{__version__}' From 2e25468748e90d77ac5d6aec6bc8258b1f8d8276 Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Thu, 21 May 2026 14:14:07 -0400 Subject: [PATCH 6/8] bump SDK version to stage CLI release Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6090b4f..81b9d87 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ dependencies = [ 'GitPython', 'packaging', 'python-dotenv', - "socketdev>=3.0.33,<4.0.0", + "socketdev>=3.1.0,<4.0.0", "bs4>=0.0.2", "markdown>=3.10", ] diff --git a/uv.lock b/uv.lock index 1fce21b..ec4b94f 100644 --- a/uv.lock +++ b/uv.lock @@ -1155,15 +1155,15 @@ wheels = [ [[package]] name = "socketdev" -version = "3.0.33" +version = "3.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/19/8c/b4608637bda66dd32cf9a421cee66e93d429f7445c8bd709032772e0f4ca/socketdev-3.0.33.tar.gz", hash = "sha256:704d672649f27390733cef4cbdad9ce8dc994794a4af56f77d2f2dc815bfe762", size = 172013, upload-time = "2026-04-24T17:02:48.616Z" } +sdist = { url = "https://files.pythonhosted.org/packages/95/3e/50f05942e23d12043028d71c0e502c0d02c470686afc3dfbab0d1931e5c1/socketdev-3.1.0.tar.gz", hash = "sha256:a9534189d50c9f6c39e802280cc2317f830dd0c9970677e8cde843a69daa84ed", size = 172581, upload-time = "2026-05-21T17:14:03.607Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/78/4408ba21724ce0648e39bd17854b19186ab77f6baedbb8b98721d6dd287a/socketdev-3.0.33-py3-none-any.whl", hash = "sha256:642eebd0b01b884c6aba8b5264e749ff71310147104e8e8de02ab24e4eab5837", size = 66975, upload-time = "2026-04-24T17:02:46.439Z" }, + { url = "https://files.pythonhosted.org/packages/df/76/4fb37245468dd9c67137059ce6833db97d76c808bf0d10397f1b5a2943d1/socketdev-3.1.0-py3-none-any.whl", hash = "sha256:e9245916d423952aba4f0018bea2bca28740530ec30308089c48dddb2133e38a", size = 67255, upload-time = "2026-05-21T17:14:01.873Z" }, ] [[package]] @@ -1221,7 +1221,7 @@ requires-dist = [ { name = "python-dotenv" }, { name = "requests" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.3.0" }, - { name = "socketdev", specifier = ">=3.0.33,<4.0.0" }, + { name = "socketdev", specifier = ">=3.1.0,<4.0.0" }, { name = "twine", marker = "extra == 'dev'" }, { name = "uv", marker = "extra == 'dev'", specifier = ">=0.1.0" }, ] From ce33da64e3fd6054499372cbad0c126a7f3442af Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Thu, 21 May 2026 14:38:38 -0400 Subject: [PATCH 7/8] fix e2e reachability tests, respect --disable-blocking when set Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --- socketsecurity/core/__init__.py | 4 +++ tests/e2e/validate-reachability.sh | 54 +++++++++++++++++++----------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/socketsecurity/core/__init__.py b/socketsecurity/core/__init__.py index 25013e4..0a6b827 100644 --- a/socketsecurity/core/__init__.py +++ b/socketsecurity/core/__init__.py @@ -947,6 +947,8 @@ def get_added_and_removed_packages( ) except APIFailure as e: log.error(f"API Error: {e}") + if self.cli_config and self.cli_config.disable_blocking: + sys.exit(0) sys.exit(1) except Exception as e: import traceback @@ -1124,6 +1126,8 @@ def create_new_diff( os.unlink(temp_file) except OSError: pass + if self.cli_config and self.cli_config.disable_blocking: + sys.exit(0) sys.exit(1) except Exception as e: import traceback diff --git a/tests/e2e/validate-reachability.sh b/tests/e2e/validate-reachability.sh index e6e365e..e32f004 100755 --- a/tests/e2e/validate-reachability.sh +++ b/tests/e2e/validate-reachability.sh @@ -27,31 +27,47 @@ else exit 1 fi -# 3. Run SARIF with --sarif-reachability all -socketcli \ - --target-path tests/e2e/fixtures/simple-npm \ - --reach \ - --sarif-file /tmp/sarif-all.sarif \ - --sarif-scope full \ - --sarif-reachability all \ - --disable-blocking \ - 2>/dev/null +FACTS_PATH="tests/e2e/fixtures/simple-npm/.socket.facts.json" +if [ ! -f "$FACTS_PATH" ]; then + echo "FAIL: Expected reachability facts at $FACTS_PATH after initial scan" + exit 1 +fi +echo "PASS: Reachability facts file present at $FACTS_PATH" + +# 3-4. Build SARIF from the facts file produced by the initial --reach run. +# Avoid re-running reach + full scan here; duplicate API scans are slow and flaky in CI. +uv run python -c " +import json +from pathlib import Path -# 4. Run SARIF with --sarif-reachability reachable (filtered) -socketcli \ - --target-path tests/e2e/fixtures/simple-npm \ - --reach \ - --sarif-file /tmp/sarif-reachable.sarif \ - --sarif-scope full \ - --sarif-reachability reachable \ - --disable-blocking \ - 2>/dev/null +from socketsecurity.core.alert_selection import load_components_with_alerts +from socketsecurity.core.messages import Messages + +target = 'tests/e2e/fixtures/simple-npm' +facts_file = '.socket.facts.json' +components = load_components_with_alerts(target, facts_file) +if not components: + raise SystemExit('FAIL: no components with alerts in .socket.facts.json') + +for outfile, reach_filter in [ + ('/tmp/sarif-all.sarif', 'all'), + ('/tmp/sarif-reachable.sarif', 'reachable'), +]: + sarif = Messages.create_security_comment_sarif_from_facts( + components, + reachability_filter=reach_filter, + grouping='instance', + ) + Path(outfile).write_text(json.dumps(sarif, indent=2)) + count = len(sarif['runs'][0]['results']) + print(f'PASS: Wrote {outfile} ({count} results, filter={reach_filter})') +" # 5. Verify reachable-only results are a subset of all results test -f /tmp/sarif-all.sarif test -f /tmp/sarif-reachable.sarif -python3 -c " +uv run python -c " import json with open('/tmp/sarif-all.sarif') as f: all_data = json.load(f) From 8cfbd86d14936cfef15c566ac618dcc4b092dcff Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Thu, 21 May 2026 14:40:22 -0400 Subject: [PATCH 8/8] document --disable-blocking exit behavior Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --- docs/cli-reference.md | 2 +- socketsecurity/config.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/cli-reference.md b/docs/cli-reference.md index bef8a5a..c26c3a4 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -305,7 +305,7 @@ The CLI will automatically install `@coana-tech/cli` if not present. Use `--reac | Parameter | Required | Default | Description | |:-------------------------|:---------|:--------|:----------------------------------------------------------------------| | `--ignore-commit-files` | False | False | Ignore commit files | -| `--disable-blocking` | False | False | Disable blocking mode | +| `--disable-blocking` | False | False | Non-blocking CI mode: the CLI always exits **0**, even when blocking alerts are present (including with `--strict-blocking`). Also exits 0 on uncaught runtime errors and Socket API failures, so the job is treated as successful while findings and errors are still logged. Takes precedence over `--strict-blocking`. | | `--disable-ignore` | False | False | Disable support for `@SocketSecurity ignore` commands in PR comments. When set, alerts cannot be suppressed via comments and ignore instructions are hidden from comment output. | | `--strict-blocking` | False | False | Fail on ANY security policy violations (blocking severity), not just new ones. Only works in diff mode. See [Strict Blocking Mode](#strict-blocking-mode) for details. | | `--enable-diff` | False | False | Enable diff mode even when using `--integration api` (forces diff mode without SCM integration) | diff --git a/socketsecurity/config.py b/socketsecurity/config.py index 1d18c6a..1e2717c 100644 --- a/socketsecurity/config.py +++ b/socketsecurity/config.py @@ -695,7 +695,11 @@ def create_argument_parser() -> argparse.ArgumentParser: "--disable-blocking", dest="disable_blocking", action="store_true", - help="Disable blocking mode" + help=( + "Non-blocking CI mode: always exit 0, even when blocking alerts are present " + "(including with --strict-blocking), on uncaught errors, or on Socket API failures. " + "Findings and errors are still logged. Overrides --strict-blocking." + ), ) advanced_group.add_argument( "--disable_blocking",