Skip to content

Commit 00d9224

Browse files
mikolalysenkoclaude
andcommitted
Merge origin/main (#257) into fix/profiling-correctness-bugs
#257 landed the X1b deferred pristine fetch, which already refuses a not-installed gem in `--vendor-source build` with `gem_spec_missing` BEFORE downloading it, under the same scope this branch's gate had (verifiable lock entry, no ledger entry). Take main's gate and drop this branch's copy; keep the scope-guard suite, adapted to main's behavior (the backend's own detail text, and the already-vendored fresh-clone re-run now makes no registry request at all). The other three fixes still apply and are ported onto #257's code: * js7: the in-memory stager's view fetches now run through `ordered_concurrent`; the per-file `needs_blob` rule and the per-package drop reasons fold into that loop unchanged. The dropped records never reach `vendor_records`, so they stay out of the exact service-download plan and the group commit too (new test). * order: `filter_to_installed_releases` still drains a HashMap on main; the purl sort now also orders #257's view prefetch plan, which is built from the same selection. * req: untouched by #257. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2 parents 5f59843 + 8c381ec commit 00d9224

266 files changed

Lines changed: 72435 additions & 7297 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.gitattributes‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,9 @@ crates/socket-patch-core/tests/fixtures/pdm-native/*.lock -text
1010
# refuse CRLF by design (vendor_lockfile_crlf_unsupported), and the tests
1111
# derive their CRLF variants from the LF bytes themselves.
1212
crates/socket-patch-core/tests/fixtures/pnpm-hosted/** -text
13+
14+
# The legacy vendor ledgers are what the base binary wrote, byte for byte:
15+
# vendor_ledger_schema_e2e replays them through `vendor --revert` and
16+
# compares the result byte for byte, so a CRLF checkout would change both
17+
# the replayed wiring files and the expected revert.
18+
crates/socket-patch-cli/tests/fixtures/legacy-ledgers/** -text

‎.github/workflows/ci.yml‎

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1455,9 +1455,45 @@ jobs:
14551455
SOCKET_PATCH_CARGO_E2E_LOCK_VERSION: ${{ matrix.lock }}
14561456
run: |
14571457
set -euo pipefail
1458-
cargo test -p socket-patch-cli --test e2e_redirect_cargo_build --test e2e_vendor_cargo_build --test mode_migration_cargo
1458+
cargo test -p socket-patch-cli --test e2e_redirect_cargo_build --test e2e_redirect_cargo_shapes --test e2e_vendor_cargo_build --test mode_migration_cargo
14591459
cargo test -p socket-patch-cli --test e2e_safety_cargo_build -- --ignored
14601460
1461+
# Manifest `[patch]` + the tagged detached lock (the v5 vendored cargo
1462+
# wiring) on cargo 1.41 and 1.56 — below / at the 1.56 floor of
1463+
# config-file `[patch]`. The old-toolchain tests prefer the local
1464+
# `rust:1.41-slim` / `rust:1.56-slim` docker images (run `--network none`;
1465+
# they build AND run the consumer) and skip when no old cargo is
1466+
# available; this leg pulls both images and requires them.
1467+
cargo-old-toolchains:
1468+
name: cargo old toolchains (manifest [patch])
1469+
needs: test
1470+
runs-on: ubuntu-latest
1471+
timeout-minutes: 30
1472+
steps:
1473+
- name: Checkout
1474+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
1475+
with:
1476+
persist-credentials: false
1477+
- name: Install Rust
1478+
run: rustup show
1479+
- name: Pull the old cargos under test
1480+
run: |
1481+
docker pull rust:1.41-slim
1482+
docker pull rust:1.56-slim
1483+
- name: Cache cargo
1484+
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
1485+
with:
1486+
key: cargo-old-toolchains
1487+
save-if: ${{ github.ref == 'refs/heads/main' }}
1488+
- name: Vendored manifest [patch] on old cargo
1489+
shell: bash
1490+
env:
1491+
SOCKET_PATCH_CARGO_E2E_REQUIRED: '1'
1492+
SOCKET_PATCH_CARGO_OLD_TOOLCHAINS_REQUIRED: '1'
1493+
run: |
1494+
set -euo pipefail
1495+
cargo test -p socket-patch-cli --test e2e_vendor_cargo_build -- old_toolchain --nocapture
1496+
14611497
# ----------------------------------------------------------------------
14621498
# Experimental `setup`-flow matrix (NON-BLOCKING).
14631499
#

‎CHANGELOG.md‎

Lines changed: 525 additions & 15 deletions
Large diffs are not rendered by default.

‎Cargo.lock‎

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

‎Cargo.toml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,20 @@ sha1 = "=0.10.6"
2121
hex = "=0.4.3"
2222
reqwest = { version = "=0.12.28", features = ["rustls-tls", "json"], default-features = false }
2323
tokio = { version = "=1.50.0", features = ["full"] }
24+
futures-util = { version = "=0.3.32", default-features = false, features = ["std"] }
2425
thiserror = "=2.0.18"
2526
walkdir = "=2.5.0"
2627
uuid = { version = "=1.21.0", features = ["v4"] }
2728
console = "=0.15.11"
2829
dialoguer = "=0.11.0"
2930
tempfile = "=3.26.0"
3031
regex = "=1.12.3"
32+
aho-corasick = "=1.1.4"
3133
glob = "=0.3.4"
3234
toml_edit = "=0.25.12"
3335
once_cell = "=1.21.3"
3436
qbsdiff = "=1.4.4"
37+
rayon = "=1.12.0"
3538
tar = "=0.4.46"
3639
flate2 = "=1.1.9"
3740
zip = { version = "=8.6.0", default-features = false, features = ["deflate"] }

‎README.md‎

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,40 @@ warning — it never breaks a command or pollutes `--json` output. `socket-patch
531531
cloned repo must never be able to redirect where patches come from or spend your token.
532532
(Full rationale: [docs/design/configuration.md](docs/design/configuration.md).)
533533
534+
One more env-only knob tunes *pacing* rather than routing. `scan` queries the patch API
535+
with several requests in flight: against the authenticated endpoint, a quarter of the
536+
requests a step has to make, between 8 and 32 (so a step with 128 or more requests runs
537+
32 at once, one with 32 or fewer runs 8); against the public proxy, which shares one
538+
server-side limit across anonymous callers, 4. The patch-record fetches behind `vex` and
539+
`scan --vex` run up to 10 at once (4 on the proxy).
540+
`SOCKET_API_CONCURRENCY=<n>` overrides that, clamped to `1`-`32`; on the public proxy it
541+
can only lower it. Set it when an endpoint in front of the API caps in-flight requests
542+
per client — a self-hosted `--api-url`, a corporate reverse proxy, a WAF or a CDN — and
543+
a scan starts reporting fewer patches than it should because some requests are being
544+
rejected. `SOCKET_API_CONCURRENCY=1` sends one request at a time, the slowest and most
545+
conservative setting. An unset, empty or non-numeric value leaves the defaults in place.
546+
547+
A throttled patch API is retried, within bounds. An HTTP `429` or `503` answer to any
548+
patch-API query (batch search, patch lists, patch views, VEX record fetches, hosted
549+
package references) is retried up to 3 times, waiting as long as the server's
550+
`Retry-After` asks (seconds or an HTTP date; a request asked to wait more than 30 s gives
551+
up at once) or, without one, 0.5 s, 1 s, 2 s with jitter. All retries in one run must
552+
finish within 60 s of the run's first retry (wall-clock: requests waiting in parallel
553+
don't add up), so a heavily throttled run gives up instead of hanging. `SOCKET_API_MAX_RETRIES=<n>` changes
554+
the per-request count (`0`-`10`; `0` turns retries off). Other errors are never retried.
555+
A query still throttled after its retries is reported, never dropped: a failed batch
556+
prints `Warning: API batch <n> of <total> failed: …` (under `--json`, a top-level
557+
`warnings[]` entry with code `api_batch_failed`), a failed patch-list lookup prints
558+
`Warning: could not fetch details for <purl>: …` (`--json`: `patch_details_failed`), and
559+
if every query fails the scan exits 1 with an error, as before.
560+
561+
The crawl has a pacing knob too. Its directory walks (`node_modules`, and the Maven
562+
repository with its POM parse) run on a small pool of threads: 4 by default (fewer on a machine with fewer performance cores), because the walk is bound
563+
by the kernel's directory cache and more threads only add system time.
564+
`SOCKET_WALK_THREADS=<n>` overrides that, clamped to `1`-`16` and to the machine's CPU
565+
count; an unset, empty or non-numeric value leaves the default in place. A soft open-file
566+
limit below 128 still runs the walk on one thread, whatever the knob says.
567+
534568
The sections below list only each command's **command-specific** flags.
535569
536570
### `scan`
@@ -566,7 +600,7 @@ socket-patch scan [options]
566600
| `--mode <hosted\|vendored\|agent>` | — | Selects one of the three [patch modes](#three-patch-modes), summarized above. Combining `--mode` with a legacy boolean flag of a *different* mode is an error (exit 2); the same mode spelled both ways is accepted. |
567601
| `--prune` | — | Garbage-collect after the scan: remove manifest entries for packages no longer present in the crawl (installed trees + lockfiles — a wiped `node_modules` alone doesn't prune lockfile-listed entries) and delete orphan blob/diff/package-archive files. Off by default. [Vendored](#vendor) packages are exempt from the crawl-based prune (an absent installed copy is their normal state), but a vendored entry whose dependency has left the lockfile is reverted (and any manifest entry it still had dropped). Orthogonal to `--mode` — combines with any mode. |
568602
| `--detached` | — | Hidden compatibility no-op. Vendored mode is manifest-free by default: the vendor ledger (`.socket/vendor/state.json`) embeds the patch records and `.socket/manifest.json` is never written, so this former opt-in changes nothing. Still an error without `--mode vendored`. |
569-
| `--batch-size <n>` | `SOCKET_BATCH_SIZE` | Packages per API request (default: `100`). |
603+
| `--batch-size <n>` | `SOCKET_BATCH_SIZE` | Packages per API request (default: `500` on the authenticated API, `100` on the public proxy). A request whose body would exceed 256 KiB is split into smaller ones. |
570604
| `--all-releases` | `SOCKET_ALL_RELEASES` | Store patches for every release/distribution variant, not just the installed one — PyPI wheel/sdist, RubyGems platform, Maven classifier. Makes the manifest portable across environments (e.g. cross-platform CI caches). |
571605
| `--vex <path>` | `SOCKET_VEX` | On a successful scan, also write an OpenVEX 0.2.0 document to this path. See [Inline VEX generation](#inline-vex-on-apply--scan--vendor). |
572606
| `--vex-product`, `--vex-no-verify`, `--vex-doc-id`, `--vex-compact` | `SOCKET_VEX_*` | Passthrough to the embedded VEX builder; mirror the standalone [`vex`](#vex) knobs. Inert unless `--vex` is set. |
@@ -1246,7 +1280,7 @@ Behavior worth knowing:
12461280
| pnpm | `pnpm-lock.yaml` (all generations), `shrinkwrap.yaml` (pnpm 1/2), Rush locks | Aliased / nested `resolution` shapes are diagnosed, not attested; `overrides` alone prove nothing |
12471281
| yarn | `yarn.lock` (classic + berry) | Berry vendored entries also need the root `package.json` `resolutions` mapping; member locks are not read |
12481282
| bun | `bun.lock`, else `bun.lockb` | A hosted entry that Bun < 1.3.10 re-saved without its sha512 attests only after install |
1249-
| cargo | `Cargo.lock`, `Cargo.toml`, `.cargo/config[.toml]` | Root manifest + project config only (no `$CARGO_HOME` / parent configs); a lockless hosted pin needs the redirect ledger's record |
1283+
| cargo | `Cargo.lock`, `Cargo.toml`, `.cargo/config[.toml]` | Root manifest + project config only (no `$CARGO_HOME` / parent configs); vendored `[patch.crates-io]` entries are read from `Cargo.toml` first (v5), the project config for pre-v5 projects, and must agree with the detached lock entry's tagged version `<version>+socket.<uuid>` (a tag for another uuid — in the lock or in the copy's own `Cargo.toml` — is dead wiring; an untagged detached entry counts only beside an untagged, pre-tag copy); a manifest entry cargo ignores (a same-key project-config item, or a URL-spelled crates.io `[patch]` table) is not attested; a lockless hosted pin needs the redirect ledger's record |
12501284
| golang | `go.mod`, `go.work`, `go.sum`, `go.work.sum` | A replace that `require` no longer selects is inert; `vendor/modules.txt` is not read |
12511285
| pypi | `uv.lock`, `*.py.lock`, `pylock*.toml`, `poetry.lock`, `pdm.lock`, `Pipfile.lock`, `requirements.txt` (+ `-r` includes), `pyproject.toml` / `hatch.toml` | A `uv.lock` beside a `pyproject.toml` must agree with its `[tool.uv.sources]`; PDM 3.1 / 4.0–4.2 locks are refused; a Pipenv project needs `--product` (or a git remote) |
12521286
| gem | `Gemfile.lock`, `gems.locked` | Platform gems unsupported; a Gemfile-only (pre-bundler-2.6, not yet locked) wiring needs the redirect ledger |

0 commit comments

Comments
 (0)