Uh oh!
There was an error while loading. Please reload this page.
fix(purl): expose fail-open batch params and harden dedupe - #98
Conversation
purl.post() defaulted to the batch API's fail-open behavior with no way to
opt out: unresolved input purls are silently omitted from the response, so
callers could not tell "clean" from "dropped". Add typed poll/timeout_sec/
alerts/purl_errors params (None => omit, preserving the fail-open default for
existing callers) plus a strict=True guard that raises APIPartialResponse when
requested purls are missing from the response.
Also harden Dedupe.consolidate_and_merge_alerts to use .get() for
key/type/severity/action so synthetic pendingScan/notFound status rows (built
server-side from a minimal {type, key} base) no longer raise KeyError.
Bump 3.3.0 -> 3.4.0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: lelia <2418071+lelia@users.noreply.github.com>🚀 Preview package published! Install with: pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple socketdev==3.4.0.dev7 |
lelia
commented
Aug 5, 2026
bugbot run |
Skipping Bugbot: Bugbot is disabled for this repository. Visit the Bugbot dashboard to update your settings. |
Eric Hibbs (flowstate)
commented
Aug 5, 2026
ai@cursor: Two things before merge. Everything else looks good — unit suite is green (137 passed / 1 skipped) and the dedupe hardening does what it says on the tin.
|
lelia
commented
Aug 5, 2026
Thanks — both are legitimate public-contract questions, and I agree they should be resolved intentionally before this class ships. I pushed Some motivation/context: this PR came from an internal Socket Basics core-tool-watch workflow, not a customer report. A newly published package version was silently omitted while analysis was still pending, and the workflow's existing fail-closed completeness guard went red. That exposed the broader issue: the batch PURL endpoint defaults fail-open, while the SDK did not expose the server's polling/status controls or offer a first-class completeness assertion. The planned rollout is SDK first, then explicit companion changes in the Python CLI and Basics. Exact PURL matchingAgreed that the guarantee needed to be stated and regression-tested in this PR. The API contract defines The updated docstring now explains that contract, and the new regression test covers the concrete Retry classificationI agree with the point that the behavior should be explicit now, rather than accidentally inherited and changed after release. Where I'm pushing back is on The motivating omission happened because analysis was pending, but For this endpoint, I added an explicit The same commit bumps the package to |
# Conflicts: # pyproject.toml # socketdev/version.py # uv.lock
lelia
commented
Aug 5, 2026
bugbot run |
Uh oh!
There was an error while loading. Please reload this page.
lelia
commented
Aug 5, 2026
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 1623690. Configure here.
Uh oh!
There was an error while loading. Please reload this page.
What & why
purl.post()inherited the batch purl API's fail-open behavior with no way to opt out: input purls whose resolution/analysis hasn't finished are silently omitted from the response, so a caller can't tell "this version is clean" from "this version was dropped." This bit socket-basicscore-tool-watch(2026-07-29): a Dependabot bump tosocketdev==3.3.0was scored, its row was silently omitted, and the fail-closed guard turned that into a red build across main.Changes (all backward-compat)
purl.post():poll,timeout_sec(→timeoutSec),alerts,purl_errors(→purlErrors).None= omit the param, so existing callers keep the server's fail-open default.**kwargspassthrough retained.alerts=true" gotcha, and the syntheticpendingScan/notFoundalert types.Dedupe.consolidate_and_merge_alertsnow uses.get()forkey/type/severity/action(identity tuples + consolidated dict), so synthetic status rows (built server-side from a minimal{type, key}base) no longer raiseKeyError.strict=Truemode — compares requested component purls against returnedinputPurl/purland raises the newAPIPartialResponse(missing=[...])when inputs are absent; a first-class "partial batch" signal even withoutalerts=true.version.py,pyproject.toml,uv.lock).Tests
5 new unit tests (query-string per param, unset-param omission, synthetic
pendingScanNDJSON parse, strict raise + pass). Full unit suite: 127 passed, 1 skipped.Release plan
Publish one v3.4.2 release after this PR merges. It bundles the unreleased changes from #99 and #101 with this PR instead of publishing 3.4.0, 3.4.1, and 3.4.2 separately.
Todos
v3.4.2to PyPI.socketdevfloor + migratescripts/check_core_tools.pyoff the stringly-typed kwargs workaround.purl.post()still swallows non-raised non-200s intolog.error + return []; consider raising given Add transient-error classification to APIFailure #93.Fixes CE-360
Note
Medium Risk
Changes core batch purl client behavior and dedupe paths used by all purl scoring; opt-in strict mode can break callers that relied on silent omissions, but defaults preserve fail-open semantics.
Overview
purl.post()now exposes first-class query options for the batch API’s fail-open behavior:poll,timeout_sec,alerts, andpurl_errors(omitted whenNoneso defaults stay unchanged). A newstrict=Truemode compares requested componentpurlstrings to returnedinputPurl/purl(andpurlErrorstream values) and raisesAPIPartialResponsewith amissinglist when the response drops inputs.NDJSON handling splits
purlError/summarystream records from artifact rows so errors are not deduped away;Dedupeuses.get()on alert fields so syntheticpendingScan/notFoundrows no longer triggerKeyError. Version bumps to 3.4.2 with expanded unit tests.Reviewed by Cursor Bugbot for commit 1623690. Configure here.