test(gem): hermetic hosted capstone + CHECKSUMS/transitive/scan --vendor coverage; gems.rb + CRLF redirect fixes - #177
Conversation
|
Polish pass for the adversarial review findings (commit 8479fb0): Major — gems.rb divergence one-way trap: FIXED. The guard now judges divergence on a redirect-footprint residue ( Minor — TS-twin / golden-fixture coupling: documented, fixtures deliberately NOT landed. depscan's Minor — docs/ecosystems.md gem row: FIXED. Hosted cell now notes gems.rb/gems.locked editing (bundler's preference order) and the fail-closed divergence warning; vendored cell notes the Gemfile-spelling-only asymmetry (a gems.rb project cannot vendor yet). Tests: 🤖 Generated with Claude Code |
8479fb0 to
7195b64
Compare
|
Rebased onto the updated base Conflict resolution (one textual conflict, in
Verification on the rebased tip (union of both sides' behavior):
🤖 Generated with Claude Code |
…sts hardened ULTRACODE review + full test matrix over the gem/bundler ecosystem (vendored and hosted modes, every configuration). 24 findings survived adversarial verification; the 13 well-scoped ones are fixed here, each pinned by a test that fails without its fix. Hosted redirect (patch/redirect/mod.rs, gem section): - splice the Gemfile edit by regex byte range: a commented-out duplicate of the gem line no longer gets rewritten instead of the live line - grant-agnostic idempotency guard: re-running scan --mode hosted with a rotated grant token refreshes the source URL in place instead of nesting a second source block (new edit kind redirect_gemfile_source_url) - fail closed on gem-level git:/github:/path:/source: options (they override the enclosing source block, making the redirect an attested no-op); warn redirect_gem_source_option and skip the dep - fail closed on platform-suffixed CHECKSUMS siblings (redirect_gem_platform_unsupported) instead of inserting a duplicate bare-coordinate pin - recognize paren/tab/multi-space gem declarations; gate the append-branch on the gem being genuinely undeclared (no more duplicate declarations bundler rejects) - never pin the lock CHECKSUMS when the Gemfile source redirect did not land (mixed state guaranteed a checksum failure) - warn that a redirected pair breaks frozen/deployment installs - record the upstream sha256 line as original on the CHECKSUMS edit so a future revert can restore it (golden fixture updated) Vendored backend (vendor/gem.rs): - insert new PATH sections at bundler's sorted position (identifier order, verified against real bundler 4.0.15 bundle lock) — two or more vendored gems no longer churn the committed lock - fail closed on platform-suffixed GEM-specs siblings on no-CHECKSUMS locks (mirrors the existing CHECKSUMS guard) - re-vendor on a patch UPDATE (new uuid, same purl): recognize our own path: wiring and rewire in place instead of refusing with gemfile_declaration_not_editable — the documented automatic re-vendor contract now actually works for gem Auto-fetch (vendor/registry_fetch.rs): - stage fetched gems into the canonical <name>-<version> leaf instead of a dir literally named "gem", which vendor_gem refused as platform_gem_unsupported — lockfile auto-fetch for gems was dead Crawler (crawlers/ruby_crawler.rs): - parse_dir_name_version prefers the last dotted-version boundary, so http-2-1.0.1 parses as (http-2, 1.0.1) instead of the ghost (http, 2) - vendor/bundle discovery enumerates engine dirs (jruby, truffleruby) instead of hardcoding ruby/ Scan/get plumbing: - run_nested_apply now threads --ecosystems: scan --ecosystems gem --sync no longer applies (or mutates) other ecosystems' patches - scan --vendor --dry-run --vex no longer writes the VEX file nor exits 1 on not-yet-vendored state Test hardening: - e2e_gem lifecycle harness: BUNDLE_PATH replaces bundle install --path (removed in bundler 3+; all 3 lifecycle tests green under 4.0.15) - e2e_hosted_production gem leg now asserts the CHECKSUMS digest CHANGED after redirect (client-verifiable today) and, in the success arm, verifies installed content against the published afterHashes — an inert gem patch can no longer stay green (the npm minimist blindspot) - docker_e2e_gem serves the true git-blob beforeHash so the chain exercises the default non-forced apply path, not just --force - setup_matrix_gem module doc: the with-setup Docker cases ARE still a baseline gap (bootstrap deadlock: plugin registration evaluates plugins.rb before any gems land; exit-semantics twin), doc corrected Verified: core 2460/0, cli lib 350/0, clippy+fmt clean; e2e_gem 11/11 (incl. live lifecycle under bundler 4.0.15), e2e_vendor_gem_build 6/6 (incl. real-bundler capstone), docker_e2e_gem 2/2, docker_e2e_vendor_gem 1/1, hosted production gem leg green (redirect verified; install still blocked by the known depscan#23630 compact-index 404 — server-side). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ll scan arms Addresses both Bugbot findings on #175: - The grant-agnostic Gemfile idempotency guard required LF (`do\n`), so a core.autocrlf checkout of a previously-redirected Gemfile was not recognized and the indented gem line inside the block got wrapped in a second, nested source block on re-run. The recognizer now accepts `do\r?\n`; pinned by gemfile_rerun_on_crlf_checkout_never_nests (verified red without the fix). - The dry-run VEX skip only covered the vendor JSON arm; the interactive `scan --vendor --dry-run --vex` path (embed_vex_human) and the JSON `scan --apply --dry-run --vex` path (embed_vex_into_json at the apply fall-through) still generated the document — exiting 1 on a not-yet-vendored project or writing the attestation during --dry-run. The guard now lives at the top of both embed helpers, covering every scan arm; pinned by scan_vendor_dry_run_with_vex_interactive_* and scan_apply_json_dry_run_with_vex_* (both verified red without it). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
d063cb1 to
99f9cd0
Compare
…or coverage; gems.rb + CRLF redirect fixes Closes the gem audit's top coverage gaps with hardened, independent-oracle tests, plus the two small redirect fixes the new tests exercise. Redirect fixes (patch/redirect/mod.rs gem section + hosted.rs candidates): - gems.rb/gems.locked support end-to-end: the candidate list now reads the modern pair and the gem rewriter keys on whichever pair bundler reads (gems.rb wins when both spellings exist — verified on bundler 4.0.15; same order as setup::gem). Diverging spellings fail closed with redirect_gem_gemfile_spellings_diverge. Before: a gems.rb project was a silent hosted-mode no-op. - CRLF Gemfile.lock tolerance: the CHECKSUMS matchers accept \r-terminated lines and edits preserve the file's CRLF endings byte-for-byte. Before: a CRLF lock (legal to bundler — verified via bundle check/frozen install) was misdiagnosed as bundler <2.6 (redirect_gem_no_checksums_section). New coverage: - e2e_redirect_gem_build.rs — FULLY HERMETIC hosted gem capstone: authored gems built with real `gem build`, one wiremock playing the upstream compact index, the Socket patch-registry compact index (production's /patch-registry/gem/<token>/<uuid>/ shape, real /versions md5s and /info checksums), and the patches API. scan --mode hosted, then a REAL fresh-checkout `bundle install` (host bundler) pulls the patched .gem: bytes match afterHash, the runtime dep installs because /info declares it, require probe + post-install verified VEX. A gems.rb twin pins the modern spelling end-to-end. A deps red-arm pins the compact-index dependency contract the production server currently violates: a deps-less /info breaks the install with bundler's APIResponseMismatchError (the live-CI signature). A KNOWN-LIMITATION canary pins that on a CHECKSUMS lock (bundler >= 4 default) the current rewrite makes the prescribed unfrozen install fail with "mismatched checksums" (empirically verified; the converged-lock fix shape that a frozen install accepts is documented in the test). - docker_e2e_vendor_gem.rs — lockfile_checksums twin (bundler 2.7 in the image, `bundle lock --add-checksums`): vendor swaps the registry sha256= CHECKSUMS line for bundler's bare path-gem form, a frozen --network none install accepts the rewritten lock byte-stably, and revert restores the registry sha256= line VERBATIM (the exit-16 hazard). - e2e_vendor_gem_build.rs — TRANSITIVE-dep capstone: vendoring rack via a rack-test project appends the managed block + sorted `rack (= v)!` DEPENDENCIES pin, a real frozen fresh-checkout install accepts the pair byte-stably, require probe through the dependent, revert round-trip. - in_process_vendor.rs — gem through `scan --vendor` (mock-proxy API, hermetic bundler layout, no ruby needed): JSON-arm end-to-end (pair edit + artifact + stub gemspec + already_vendored rerun), manifest-drop reconcile byte-restore, and the --detached variant (no manifest, embedded record, vendor --revert exit path). Every rewriter behavior change is pinned by unit tests that fail on the base commit (gems.rb pair routing, diverging-spelling fail-closed, CRLF pin-in-place/insert byte-preservation, CRLF rerun no-op); the gems.rb e2e leg fails without the candidate-list entry. Bundler behaviors (gems.rb preference, lockfile naming, compact-index formats, checksum enforcement, CRLF acceptance) were validated against real bundler 4.0.15 and the image's 2.7.2 before being baked into fixtures. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rint residue, not raw bytes Run 1 on byte-identical gems.rb/Gemfile twins edits only gems.rb (the file bundler reads), so the raw-byte divergence guard trapped every later run — the rotated-grant URL refresh included — behind redirect_gem_gemfile_spellings_diverge, a divergence the rewriter itself created. Compare redirect-footprint residues instead: erase the managed Socket source block (rotating grant segments wildcarded) and the dep's own gem declaration line from both spellings before judging. Rebased onto d063cb1 (CRLF-tolerant block recognizer): the residue eraser now accepts `do\r?\n … end\r?` too, mirroring the recognizer — a core.autocrlf checkout rewrites run 1's LF block to CRLF, and a block the recognizer accepts must also be erased here or the re-run is trapped behind the divergence warning before it can reach the recognizer. Pinned by gems_rb_crlf_twins_rerun_is_no_op_and_rotated_grant_refreshes (verified red with an LF-only residue eraser). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
7195b64 to
707bbf8
Compare
|
Rebased Conflicts: none — the rebase applied cleanly with zero textual conflicts and zero content drift (interdiff of old tip vs new tip is exactly the base-side change). The two files both sides touch were checked semantically: Verification (all green):
Pre-existing note (not from this PR): 🤖 Generated with Claude Code |
…dening Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Conflict: crates/socket-patch-core/src/vendor/mod.rs — both sides widened adjacent re-export lines. Resolved as a union: * main (#174) exports state::carry_forward_wiring, the extracted re-vendor ledger reconciliation persist_vendor_entry now calls; * this branch exports verify::artifact_is_file_shaped and verify::compute_dir_inventory, which the CLI needs because verify is pub(crate). Both hunks are kept verbatim; neither side's symbol set changes. The gem sibling (#177) was already in this branch's base, so main brings only pnpm/redirect work. carry_forward_wiring reconciles wiring, pnpm meta and the go-takeover flag and never touches entry.artifact, so the new fileInventory on a re-vendor keeps the freshly computed inventory — no interaction. Main added no VendorArtifact literal, so the mechanical file_inventory field addition stays complete. Verified: core lib 2215/0, cli lib 376/0, repair_vendor_e2e 24/0, in_process_vendor 30/0, e2e_vex_vendor 8/0, setup_contract_gaps 10/0, e2e_gem 8/0, in_process_gem_apply 7/0, e2e_vendor_gem_build 5/0, e2e_vendor_pnpm_build 6/0. vendor/mod.rs is rustfmt-clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
STACKED on PR #175 (
fix/gem-bundler-audit) — base branch isfix/gem-bundler-audit, not main.Closes the gem audit's top coverage gaps with hardened tests, plus the two small verified redirect fixes the new tests exercise.
Product fixes (both pinned by tests that fail on the base commit)
REDIRECT_CANDIDATE_FILES(clihosted.rs) now reads the modern pair, andrewrite_gemkeys on whichever pair bundler actually reads: gems.rb wins when both spellings exist (verified empirically on bundler 4.0.15, matchingsetup::gem::discover_bundler_project); byte-identical twins proceed on gems.rb; spellings that diverge beyond the redirect's own footprint fail closed with the newredirect_gem_gemfile_spellings_divergewarning. Divergence is judged on a residue (gem_spelling_residue) with Socket's managed source blocks (rotating grant token/uuid wildcarded) and the redirected deps' owngemlines erased — a raw-byte comparison would trap every re-run behind the divergence run 1 itself creates on identical twins, permanently blocking the rotated-grant URL refresh and hosted record refresh (review finding, fixed in the polish commit). Ledger edit paths carry the real filenames. Before:scan --mode hostedwas a silent no-op on gems.rb projects.gems_rb_pair_is_rewritten_with_modern_paths,gems_rb_beats_identical_gemfile,gems_rb_and_gemfile_diverging_fail_closed,gems_rb_identical_twins_rerun_is_a_no_op_not_a_diverge_trap,gems_rb_identical_twins_rerun_refreshes_rotated_grant_url,gems_rb_identical_twins_rerun_after_appended_block_is_no_op,gems_rb_divergence_only_in_redirected_dep_line_proceeds(unit, RED on base / RED on a raw-byte guard) +gem_hosted_gems_rb_spelling_redirects_and_installs(e2e, RED without the candidate-list entry — verified).\r-terminated lines and both the pin-in-place and the insert-after-header edits preserve the file's CRLF endings byte-for-byte (real bundler accepts CRLF locks — verified viabundle check+ frozen install on 4.0.15). Before: a CRLF lock was misdiagnosed as bundler <2.6 (redirect_gem_no_checksums_section) and never pinned.gem_crlf_lock_checksum_pinned_preserving_crlf,gem_crlf_lock_checksums_header_gains_crlf_entry(byte-exact, incl. CRLF rerun no-op; RED on base).New coverage
tests/e2e_redirect_gem_build.rs— hermetic hosted gem capstone (4 tests,#[ignore]-gated likee2e_vendor_gem_build). Fully hermetic: fixture gems authored in-test and built with the realgem build; ONE wiremock plays the upstream compact index, the Socket patch-registry compact index (production's/patch-registry/gem/<token>/<uuid>/base, real per-info md5 digests in/versions,checksum:sha256s in/info), and the patches API. Chain:scan --mode hosted --vex→ fresh checkout → REALbundle install→ installed bytes byte-match afterHash, runtime dep installs, require probe, post-install hash-verified VEX./infodeclares it; the red-arm test (…without_deps_breaks_install_like_production) proves a deps-less/info(today's prod shape:not_builtindex / zero-byte deps API) breaks the install with bundler'sAPIResponseMismatchError … dependencies not in the API— the exact live-CI signature.gem_hosted_checksums_lock_pins_patched_sha_but_bundler_refuses_mixed_state): on a CHECKSUMS lock (bundler ≥ 4 writes one by default), the current rewrite (Gemfile source block + CHECKSUMS pin, GEM section left on upstream) makes the prescribed unfrozen install fail with "Bundler found mismatched checksums" (exit 37) — bundler still attributes the gem to the upstream source and refuses the lockfile-vs-upstream-API disagreement. Empirically verified on 4.0.15; also verified the fix target: the fully converged lock (patch-registry GEM section +name (= ver)!DEPENDENCIES pin + patched CHECKSUMS sha) passes even a FROZEN install. That fix must land in the TS twin + shared golden fixtures together, so it is out of scope here; the canary makes the breakage visible and self-documents the flip when fixed.docker_e2e_vendor_gem.rs— lockfile_checksums twin (replaces the module-doc TODO):bundle lock --add-checksumson the image's bundler 2.7, vendor swaps the registrysha256=line for bundler's bare path-gem CHECKSUMS form, frozen--network nonefresh-checkout install accepts the rewritten lock byte-stably (the exit-16 hazard), revert restores the registrysha256=line VERBATIM, re-vendor re-bares it. Host-side oracle re-asserts from the mounted files. The existing no-CHECKSUMS test is unchanged (both flavors covered).e2e_vendor_gem_build.rs— transitive-dep capstone: rack vendored as a TRANSITIVE dep of rack-test; the managed block (# >>> socket-patch vendor (managed) >>>…) is byte-asserted with hand-pinned marker constants, the DEPENDENCIES pin inserts at bundler's sorted position, and — for the first time — that pair is fed to a REAL frozenbundle install(byte-stable lock, probe through the rack-test require chain), then revert round-trips byte-identically. Lock shape pinned to no-CHECKSUMS on every host (lockfile_checksums false) so bundler 2.5 (CI pin) and 4.x agree; the CHECKSUMS flavor is the docker twin's job.in_process_vendor.rs— gem throughscan --vendor(hermetic bundler layout, no ruby needed): JSON-arm end-to-end (manifest written, pair edit + patched artifact + stub gemspec fromspecifications/, pristine installed tree,already_vendoredrerun) + manifest-drop reconcile byte-restore +--detachedvariant (no manifest, embedded record,vendor --revertexit path).Empirical validation (before baking into fixtures/code)
Against real bundler 4.0.15 (host) and 2.7.2 (docker image): gems.rb-beats-Gemfile + gems.locked naming; compact-index
/versionsmd5 +/infodeps/checksum grammar (a hand-built index accepted by a realbundle install); checksum enforcement (lock pin vs served bytes); CRLF lock acceptance; bundler-4 CHECKSUMS-by-default vs 2.7 opt-in;bundle lock --add-checksumsavailability; the deps-less/infofailure signature; and the converged-lock frozen-install fix shape.Test results
e2e_redirect_gem_build(new): 4 passed (hermetic, ~6s)docker_e2e_vendor_gem: 2 passed (both flavors, real bundler 2.7 in docker)e2e_vendor_gem_build --ignored: 2 passed (incl. new transitive capstone, real bundler 4.0.15)in_process_vendor: 29 passed (2 new gem tests)socket-patch-corefull suite: all green (incl.redirect_golden— classic-spelling output byte-unchanged),patch::redirect73 passedin_process_redirect,in_process_redirect_pnpm,e2e_vex_redirect,scan_vendor_e2e,cli_parse_scan,e2e_redirect_rush_sim --ignored, cli--lib): all greencargo fmt+cargo clippy --all-targets(both crates, with features): cleanFollow-ups / out of scope (not in my owned files)
TS-twin port of this PR's two redirect fixes + the shared golden fixtures (depscan
registry-rewritegem rewriter +golden.test.ts): gems.rb/gems.locked pair routing, the residue-basedredirect_gem_gemfile_spellings_divergeguard (warning-code parity included), and CRLF Gemfile.lock CHECKSUMS tolerance are CLI-side only for now — the backend twin still silently no-ops on a gems.rb project and misdiagnoses a CRLF lock as bundler <2.6. The shared golden cases (gems.rb pair, diverge fail-closed, CRLF lock) must land TOGETHER with the TS port: depscan'sgolden.test.tsruns every fixture case with no skip list (verified), so fixtures added here first would break depscan CI at the next submodule bump. depscan has GitHub issues disabled — needs a depscan PR/internal ticket.ci.yml e2e matrix entry for the new
e2e_redirect_gem_buildsuite (needs setup-ruby with bundler ≥ 2.6 pinned; the existing gem leg pins 2.5 fore2e_vendor_gem_build). Until added, the suite runs only via--ignoredlocally.CHECKSUMS-lock hosted redirect fix (the canary finding): needs the converged-lock rewrite in the gem rewriter + the TS twin + shared golden fixtures moving together. Alternative shapes verified: removing the pinned line also unblocks (bundler re-records the patched sha from the registry API) but loses first-fetch enforcement.
The hosted-production e2e gem leg (
e2e_hosted_production.rs) can adopt theAPIResponseMismatchErrorred-arm once the prod compact index is rebuilt.🤖 Generated with Claude Code
Note
Medium Risk
Changes gem hosted redirect lockfile rewriting (
rewrite_gem), which affects howscan --mode hostededits Gemfiles and locks; risk is mitigated by broad new e2e coverage rather than large unrelated refactors.Overview
Hosted gem redirect now reads
gems.rb/gems.locked(candidate list + rewriter). The rewriter edits the pair bundler actually uses (gems.rbwhen both spellings exist and match); divergingGemfilevsgems.rbcontent fails closed withredirect_gem_gemfile_spellings_diverge. Ledger edit paths use the real filenames. CRLFGemfile.lockis handled for CHECKSUMS pinning without mis-firingredirect_gem_no_checksums_section.Tests close major gem gaps: hermetic
e2e_redirect_gem_build(wiremock compact index +scan --mode hosted→ freshbundle install→ VEX), includinggems.rbspelling, a deps-less/infored-arm (APIResponseMismatchError), and a CHECKSUMS-lock canary documenting today’s mixed-state install failure until a converged-lock rewrite lands. Dockerlockfile_checksumstwin for vendor CHECKSUMS rewrite/revert; host transitive rack vendoring + frozen install; in-processscan --vendorfor gem (reconcile + detached).Reviewed by Cursor Bugbot for commit b17172b. Configure here.