Skip to content

Commit 0445421

Browse files
leliaflowstate
andauthored
Migrate license enrichment to org-scoped endpoint (#180)
* Backfill changelog for v2.2.74+ releases Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * Migrate license enrichment to org-scoped endpoint Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * Fix github project homepage on PyPI Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * Bump version for release Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * Properly bump version Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * bump SDK version to stage CLI release Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * fix e2e reachability tests, respect --disable-blocking when set Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * document --disable-blocking exit behavior Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --------- Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> Co-authored-by: Eric Hibbs <eric@socket.dev>
1 parent 0d19e64 commit 0445421

10 files changed

Lines changed: 134 additions & 31 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ test.py
2424
*.cpython-312.pyc`
2525
file_generator.py
2626
.coverage
27+
.coverage.*
28+
htmlcov/
2729
.env.local
2830
Pipfile
2931
test/

CHANGELOG.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,48 @@
11
# Changelog
22

3+
## 2.2.90
4+
5+
- Migrated license enrichment PURL lookup to the org-scoped endpoint (`POST /v0/orgs/{slug}/purl`) from the deprecated global endpoint (`POST /v0/purl`).
6+
37
## 2.2.83
48

59
- Fixed branch detection in detached-HEAD CI checkouts. When `git name-rev --name-only HEAD` returned an output with a suffix operator (e.g. `remotes/origin/master~1`, `master^0`), the `~N`/`^N` was previously passed through as the branch name and rejected by the Socket API as an invalid Git ref. The suffix is now stripped before the prefix split, producing the bare branch name.
610

11+
## 2.2.80
12+
13+
- Hardened GitHub Actions workflows.
14+
- Fixed broken links on PyPI page.
15+
16+
## 2.2.79
17+
18+
- Updated minimum required Python version.
19+
- Tweaked CI checks.
20+
21+
## 2.2.78
22+
23+
- Fixed reachability filtering.
24+
- Added config file support.
25+
26+
## 2.2.77
27+
28+
- Fixed `has_manifest_files` failing to match root-level manifest files.
29+
30+
## 2.2.76
31+
32+
- Added SARIF file output support.
33+
- Improved reachability filtering.
34+
35+
## 2.2.75
36+
37+
- Fixed `workspace` flag regression by updating SDK dependency.
38+
39+
## 2.2.74
40+
41+
- Added `--workspace` flag to CLI args.
42+
- Added GitLab branch protection flag.
43+
- Added e2e tests for full scans and full scans with reachability.
44+
- Bumped dependencies: `cryptography`, `virtualenv`, `filelock`, `urllib3`.
45+
746
## 2.2.71
847

948
- Added `strace` to the Docker image for debugging purposes.

docs/cli-reference.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ The CLI will automatically install `@coana-tech/cli` if not present. Use `--reac
305305
| Parameter | Required | Default | Description |
306306
|:-------------------------|:---------|:--------|:----------------------------------------------------------------------|
307307
| `--ignore-commit-files` | False | False | Ignore commit files |
308-
| `--disable-blocking` | False | False | Disable blocking mode |
308+
| `--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`. |
309309
| `--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. |
310310
| `--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. |
311311
| `--enable-diff` | False | False | Enable diff mode even when using `--integration api` (forces diff mode without SCM integration) |

pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
66

77
[project]
88
name = "socketsecurity"
9-
version = "2.2.89"
9+
version = "2.2.90"
1010
requires-python = ">= 3.11"
1111
license = {"file" = "LICENSE"}
1212
dependencies = [
@@ -16,7 +16,7 @@ dependencies = [
1616
'GitPython',
1717
'packaging',
1818
'python-dotenv',
19-
"socketdev>=3.0.33,<4.0.0",
19+
"socketdev>=3.1.0,<4.0.0",
2020
"bs4>=0.0.2",
2121
"markdown>=3.10",
2222
]
@@ -57,7 +57,7 @@ socketcli = "socketsecurity.socketcli:cli"
5757
socketclidev = "socketsecurity.socketcli:cli"
5858

5959
[project.urls]
60-
Homepage = "https://socket.dev"
60+
Homepage = "https://github.com/SocketDev/socket-python-cli"
6161

6262
[tool.coverage.run]
6363
source = ["socketsecurity"]

socketsecurity/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
__author__ = 'socket.dev'
2-
__version__ = '2.2.89'
2+
__version__ = '2.2.90'
33
USER_AGENT = f'SocketPythonCLI/{__version__}'

socketsecurity/config.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,11 @@ def create_argument_parser() -> argparse.ArgumentParser:
695695
"--disable-blocking",
696696
dest="disable_blocking",
697697
action="store_true",
698-
help="Disable blocking mode"
698+
help=(
699+
"Non-blocking CI mode: always exit 0, even when blocking alerts are present "
700+
"(including with --strict-blocking), on uncaught errors, or on Socket API failures. "
701+
"Findings and errors are still logged. Overrides --strict-blocking."
702+
),
699703
)
700704
advanced_group.add_argument(
701705
"--disable_blocking",

socketsecurity/core/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,7 @@ def get_license_text_via_purl(self, packages: dict[str, Package], batch_size: in
898898
results = self.sdk.purl.post(
899899
license=True,
900900
components=batch_components,
901+
org_slug=self.config.org_slug,
901902
licenseattrib=True,
902903
licensedetails=True
903904
)
@@ -946,6 +947,8 @@ def get_added_and_removed_packages(
946947
)
947948
except APIFailure as e:
948949
log.error(f"API Error: {e}")
950+
if self.cli_config and self.cli_config.disable_blocking:
951+
sys.exit(0)
949952
sys.exit(1)
950953
except Exception as e:
951954
import traceback
@@ -1123,6 +1126,8 @@ def create_new_diff(
11231126
os.unlink(temp_file)
11241127
except OSError:
11251128
pass
1129+
if self.cli_config and self.cli_config.disable_blocking:
1130+
sys.exit(0)
11261131
sys.exit(1)
11271132
except Exception as e:
11281133
import traceback

tests/core/test_package_and_alerts.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,41 @@ def test_get_new_alerts_with_readded(self):
228228

229229
# With ignore_readded=False
230230
new_alerts = Core.get_new_alerts(added_alerts, removed_alerts, ignore_readded=False)
231-
assert len(new_alerts) == 1
231+
assert len(new_alerts) == 1
232+
233+
def test_get_license_text_via_purl_uses_org_scoped_endpoint(self, core, mock_sdk):
234+
"""Test license enrichment calls the org-scoped PURL SDK method."""
235+
core.sdk.purl = Mock()
236+
core.sdk.purl.post.return_value = [
237+
{
238+
"type": "npm",
239+
"name": "lodash",
240+
"version": "4.18.1",
241+
"licenseAttrib": [{"name": "MIT"}],
242+
"licenseDetails": [{"license": "MIT"}],
243+
}
244+
]
245+
246+
packages = {
247+
"npm/lodash@4.18.1": Package(
248+
id="pkg:npm/lodash@4.18.1",
249+
type="npm",
250+
name="lodash",
251+
version="4.18.1",
252+
score={},
253+
alerts=[],
254+
topLevelAncestors=[],
255+
)
256+
}
257+
258+
result = core.get_license_text_via_purl(packages)
259+
260+
core.sdk.purl.post.assert_called_once_with(
261+
license=True,
262+
components=[{"purl": "pkg:/npm/lodash@4.18.1"}],
263+
org_slug="test-org",
264+
licenseattrib=True,
265+
licensedetails=True,
266+
)
267+
assert result["npm/lodash@4.18.1"].licenseAttrib == [{"name": "MIT"}]
268+
assert result["npm/lodash@4.18.1"].licenseDetails == [{"license": "MIT"}]

tests/e2e/validate-reachability.sh

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,31 +27,47 @@ else
2727
exit 1
2828
fi
2929

30-
# 3. Run SARIF with --sarif-reachability all
31-
socketcli \
32-
--target-path tests/e2e/fixtures/simple-npm \
33-
--reach \
34-
--sarif-file /tmp/sarif-all.sarif \
35-
--sarif-scope full \
36-
--sarif-reachability all \
37-
--disable-blocking \
38-
2>/dev/null
30+
FACTS_PATH="tests/e2e/fixtures/simple-npm/.socket.facts.json"
31+
if [ ! -f "$FACTS_PATH" ]; then
32+
echo "FAIL: Expected reachability facts at $FACTS_PATH after initial scan"
33+
exit 1
34+
fi
35+
echo "PASS: Reachability facts file present at $FACTS_PATH"
36+
37+
# 3-4. Build SARIF from the facts file produced by the initial --reach run.
38+
# Avoid re-running reach + full scan here; duplicate API scans are slow and flaky in CI.
39+
uv run python -c "
40+
import json
41+
from pathlib import Path
3942
40-
# 4. Run SARIF with --sarif-reachability reachable (filtered)
41-
socketcli \
42-
--target-path tests/e2e/fixtures/simple-npm \
43-
--reach \
44-
--sarif-file /tmp/sarif-reachable.sarif \
45-
--sarif-scope full \
46-
--sarif-reachability reachable \
47-
--disable-blocking \
48-
2>/dev/null
43+
from socketsecurity.core.alert_selection import load_components_with_alerts
44+
from socketsecurity.core.messages import Messages
45+
46+
target = 'tests/e2e/fixtures/simple-npm'
47+
facts_file = '.socket.facts.json'
48+
components = load_components_with_alerts(target, facts_file)
49+
if not components:
50+
raise SystemExit('FAIL: no components with alerts in .socket.facts.json')
51+
52+
for outfile, reach_filter in [
53+
('/tmp/sarif-all.sarif', 'all'),
54+
('/tmp/sarif-reachable.sarif', 'reachable'),
55+
]:
56+
sarif = Messages.create_security_comment_sarif_from_facts(
57+
components,
58+
reachability_filter=reach_filter,
59+
grouping='instance',
60+
)
61+
Path(outfile).write_text(json.dumps(sarif, indent=2))
62+
count = len(sarif['runs'][0]['results'])
63+
print(f'PASS: Wrote {outfile} ({count} results, filter={reach_filter})')
64+
"
4965

5066
# 5. Verify reachable-only results are a subset of all results
5167
test -f /tmp/sarif-all.sarif
5268
test -f /tmp/sarif-reachable.sarif
5369

54-
python3 -c "
70+
uv run python -c "
5571
import json
5672
with open('/tmp/sarif-all.sarif') as f:
5773
all_data = json.load(f)

uv.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)