Skip to content

feat(scan): serve socket scan view from cached results with 202 polling (SURF-742) - #1425

Open
John-David Dalton (jdalton) wants to merge 1 commit into
v1.xfrom
jdalton/surf-742-add-support-for-the-cached-flag-in-the-sdkcli-for-full-scans
Open

feat(scan): serve socket scan view from cached results with 202 polling (SURF-742)#1425
John-David Dalton (jdalton) wants to merge 1 commit into
v1.xfrom
jdalton/surf-742-add-support-for-the-cached-flag-in-the-sdkcli-for-full-scans

Conversation

@jdalton

@jdalton John-David Dalton (jdalton) commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

What this does

socket scan view shows the results of a full scan. Today it asks the API to compute those results from scratch every time. This change makes it read a pre-computed (cached) copy instead, which is faster and cheaper.

It does that by adding ?cached=true to the request. The server has two possible answers:

  • 200 OK — the cached results are ready. The body is the usual ndjson (one JSON object per line), and we parse and show it exactly like before.
  • 202 Accepted — the cached results aren't ready yet. The server has kicked off a background job to build them and returns {"status":"processing"}. When this happens the CLI waits a moment and asks again, backing off a little each time (1s, then 2s, … up to 10s, giving up after 10 minutes). The user never sees the "processing" state — they just wait a bit longer and get the finished scan.

Which modes change: the default view and --json (the non-streaming modes that already buffer the whole response). The live --stream --json path is intentionally left untouched.

Why it's safe to ship on its own

This is self-contained. It uses the CLI's own HTTP helper (queryApiSafeTextWithStatus) and does not call the Socket SDK for this path, so it stays on the currently-pinned @socketsecurity/sdk (1.4.96) and needs no SDK release. CI is green on its own.

The separate effort to move socket-cli v1.x onto the latest SDK (4.x) is tracked as SURF-1446 — that is not required by, and does not block, this PR.

Implementation detail & parity with main
  • New helper queryApiSafeTextWithStatus in utils/api.mts returns { status, text } so the caller can tell a 202 apart from a 200 (the existing queryApiSafeText swallowed the status). queryApiSafeText now delegates to it, so its behavior is unchanged for every other caller.
  • fetchScan builds the ?cached=true request, runs the 202→200 backoff loop, and parses the 200 ndjson via an exported parseArtifactsNdjson.
  • This mirrors how main's CLI already does cached scan reads (commits e5fb60b1 + f6741d2d), adapted to the older v1.x layout. It deliberately does not use the SDK's cached getFullScan, because that method returns scan metadata, not the artifact list scan view renders.
  • --stream --json still calls the streaming full-scan method unchanged.
Verification
  • tsgo, eslint, oxlint, biome: clean.
  • vitest src/commands/scan/fetch-scan.test.mts: 5 tests via nock against the real HTTP path — 200 cache hit, 202→200 poll, 404 error, plus parseArtifactsNdjson valid/invalid line cases. No owned-module mocking.
  • vitest src/utils/api.test.mts: 10 tests, no regression from the queryApiSafeText refactor.

Linear: SURF-742. Do not merge yet.

cursor[bot]

This comment was marked as resolved.

@jdalton
John-David Dalton (jdalton) force-pushed the jdalton/surf-742-add-support-for-the-cached-flag-in-the-sdkcli-for-full-scans branch from b784521 to c57dc34 Compare July 24, 2026 12:57
@jdalton John-David Dalton (jdalton) changed the title feat(scan): cached full-scan reads with 202 polling in scan view feat(scan): cached full-scan reads with 202 polling in scan view (v1.x backport) Jul 24, 2026
@jdalton

Copy link
Copy Markdown
Collaborator Author

Withdrawing — the cached scan-view behavior (SURF-742) will land as part of bumping socket-cli v1.x to the latest @socketsecurity/sdk (4.x) under SURF-1446, rather than a bespoke direct-API poll. Superseding this branch.

@jdalton John-David Dalton (jdalton) changed the title feat(scan): cached full-scan reads with 202 polling in scan view (v1.x backport) feat(scan): serve socket scan view from cached results with 202 polling (SURF-742) Jul 24, 2026
Backports the cached scan-view behavior from main (e5fb60b, f6741d2)
to the v1.x line. socket scan view (default and --json non-stream) now
reads pre-computed results from the immutable scan store: fetchScan hits
...full-scans/{id}?cached=true, polls on 202 ({status:'processing'}) with
exponential backoff and a 10 minute deadline, then parses the 200 ndjson.
The --stream --json live-stream path is unchanged.

Uses the direct API via a new queryApiSafeTextWithStatus helper (which
surfaces the HTTP status so the 202 poll loop can see it) — no SDK
dependency, so no @socketsecurity/sdk release is required.
@jdalton
John-David Dalton (jdalton) force-pushed the jdalton/surf-742-add-support-for-the-cached-flag-in-the-sdkcli-for-full-scans branch from c57dc34 to 800e362 Compare July 24, 2026 21:49

@bcomnes Bret Comnes (bcomnes) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should definitely validate this on real data before releasing, and also this seems preferable to live in the SDK, so all clients benefit from the improvement, but otherwise on target. Please break out additional tickets for the SDK if you think thats a reasonable direction to take and even consider landing it via that approach, but if you want to just get this out as an intermediate step that also seems fine.

// callers only ever observe the final scan.
const path = `orgs/${orgSlug}/full-scans/${encodeURIComponent(scanId)}?cached=true`
const deadline = Date.now() + CACHED_POLL_TIMEOUT_MS
let delayMs = CACHED_POLL_INITIAL_DELAY_MS

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should double check this against what the actual full scan timeout is in depscan.

// 200 carries the ndjson body, a 202 means the server enqueued a background
// job to compute them — poll with backoff until the results are ready, so
// callers only ever observe the final scan.
const path = `orgs/${orgSlug}/full-scans/${encodeURIComponent(scanId)}?cached=true`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason this isn't implemented in the SDK and then just consumed in the CLI? Clients of that shouldn't need to implement this logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants