Skip to content

The public-proxy per-package fallback runs 10 requests in flight, ignoring SOCKET_API_CONCURRENCY and the proxy cap of 4 #614

Description

[agent] Filed by the scheduled architecture audit routine (CLI and core). Register: discussion #560 register.

Kind: bug. Source: new finding, register row C38 (related to C15 and C16: one HTTP pacing and retry policy).

Problem

utils::concurrent is meant to be the one pacing policy for patch-API fan-out:

  • the public proxy gets PROXY_API_CONCURRENCY = 4, because it "serializes anonymous callers behind one shared server-side semaphore — stay polite there";
  • SOCKET_API_CONCURRENCY is the operator's escape hatch "for an endpoint that caps in-flight requests per client", and on the proxy it "can only LOWER the cap".

See utils/concurrent.rs#L48-L59 and #L85-L106.

Every CLI window goes through it, including scan's batch windows, discovery, get, vendor, the hosted views, and even the vex record fetch and the hosted wheel-metadata window, which both document "SOCKET_API_CONCURRENCY applies here like every other patch-API window" (vex_sources.rs#L111-L120, [`scan/hosted.rs#L45-L56`](https://github.com/SocketDev/socket-patch/blob/045d7ec783d788bf3c5a1310724b51e09fb6505d/crates/socket-patch-cli/src/commands/scan/hosted.rs#L45-L56)).``

The API client's own per-package fallback doesn't. It has a private constant and semaphore:

search_patches_batch takes this path on the public proxy whenever POST /patch/batch is missing or rejects a chunk's validation (#L744-L755). One exotic PURL in a chunk is enough to trigger it on a current proxy.

Reproduced twice on 045d7ec with a temporary test beside proxy_batch_path_cap_tests (not committed):

  • wiremock answers POST /patch/batch with a 400, and GET /patch/by-package/* after 300 ms;
  • the client is on the public proxy, SOCKET_API_CONCURRENCY=1, and one search_patches_batch call has 10 PURLs.

Output: api_concurrency(proxy)=1 api_concurrency_for(proxy,10)=1 peak_by_package_in_flight=10. Without the override, the policy says 4 and this path still runs 10. The existing test concurrent_batches_share_the_legacy_fallback_cap pins the peak at exactly 10.

A related leftover in the same module: registry_concurrency() (concurrent.rs#L75-L83) has no caller at all, so its documented registry cap and tight-RLIMIT_NOFILE rule apply nowhere.

Symptoms

No existing issue. An operator behind a per-client in-flight limit (WAF, corporate proxy) who sets SOCKET_API_CONCURRENCY=1 still gets 10 parallel GETs on this path, and those can 429 or be dropped. Under a tight fd limit, the api_concurrency rule that forces 1 is bypassed too.

Impact

Medium. The proxy fallback is live for any chunk the batch validator rejects, and it is the one patch-API window that the shared knob doesn't reach. The fix is small and removes a duplicate pacing constant.

Proposed change

  • Size proxy_batch_slots and the chunking from utils::concurrent instead of PROXY_BATCH_PATH_CONCURRENCY. Read the policy at client construction with api_concurrency(use_public_proxy), so the env override and the fd-limit rule apply; for the proxy that is 4, or lower when the override asks.
  • Delete PROXY_BATCH_PATH_CONCURRENCY.
  • Delete registry_concurrency() and REGISTRY_CONCURRENCY, or wire them into the pristine-registry fetch they describe. Deleting is preferred unless a caller exists by then.

Size and scope

api/client.rs (constant, constructor, fallback loop, test) and utils/concurrent.rs: about 20 production lines, plus an updated test. Out of scope: unifying the retry systems (C15) and batch-size limits (C16).

Acceptance criteria

  • concurrent_batches_share_the_legacy_fallback_cap asserts that the peak equals api_concurrency(true) (4), not 10.
  • A new test: with SOCKET_API_CONCURRENCY=1 (serial), the per-package fallback's peak in flight is 1.
  • No pacing constant for patch-API requests remains outside utils::concurrent.
  • cargo test -p socket-patch-core api::client and proxy_batch_e2e stay green.

Dependencies

Touches api/client.rs, which open PRs #607 and #610 also edit, in different functions. Blocks nothing.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:triagedarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)bugSomething isn't workingpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions