Skip to content

test(gem): restore production e2e after the 2026-08-18 catalog republish - #217

Merged
Mikola Lysenko (mikolalysenko) merged 2 commits into
mainfrom
test/gem-e2e-restore
Aug 19, 2026
Merged

test(gem): restore production e2e after the 2026-08-18 catalog republish#217
Mikola Lysenko (mikolalysenko) merged 2 commits into
mainfrom
test/gem-e2e-restore

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

What

Production republished the rubygems patch catalog on 2026-08-18 (15 free activestorage patches, 5.2.0→6.0.3, GHSA-m42x-37p3-fv5w / CVE-2020-8162), and the hosted registry's compact index now serves the full dependency list — the server defect that forced the temporary gem e2e shutdown is fixed. This PR restores the gem legs to full enforcement:

  • e2e_hosted_productionGEM_E2E_DISABLED kill switch deleted (const + all 3 check sites); pins updated to pkg:gem/activestorage@6.0.3 / 15e960b5-f432-4b6c-b8aa-534a2b419323; the probe-based install tolerance is deleted per its own auto-retire design (gem_registry_base/http_probe helpers were then dead — removed). The leg is renamed gem_bundler_hosted_install_proof and asserts the full chain unconditionally: redirect rewrite, CHECKSUMS pin swap to the patched sha, real bundle install through patch.socket.dev, per-file afterHash verification via /patch/view.
  • e2e_vendored_production — re-pinned. The platform_gem_unsupported tolerance is vestigial (the gap was fixed in fix(vendor): vendor pure-ruby (?platform=ruby) gems, gate on the purl not the staging dir #172; the leg's doc comment now says so and the success branch is the live path). The full delivery-proof upgrade is deferred to a stacked fix PR: the served gem-stub-gemspec artifact is currently invalid (missing summary/authors; every bundler major rejects the vendored path source — discovered live 2026-08-19, documented as a new OPEN section in the doc).
  • e2e_gem — the three #[ignore] lifecycle tests re-pinned to the republished 5.2.0 patch (efc8d8ca-78c5-43ae-ba1b-41bb1f9f3897, CVE-2020-8162). GEM_PURL now carries ?platform=ruby: get keys the manifest by the view response's qualified purl.
  • in_process_vendor — new hermetic test pinning the qualified-purl (?platform=ruby) path through scan --vendor, the exact regression that would silently re-open the fix(vendor): vendor pure-ruby (?platform=ruby) gems, gate on the purl not the staging dir #172 gap (manifest keyed by qualified purl, basePurl bare).
  • docs — both production-e2e docs re-pinned; retired defect sections converted to the — FIXED house style; new OPEN section for the invalid served stub gemspec.

Verification (live against production, 2026-08-19)

suite result
e2e_hosted_production (preflight + canary + gem install proof) 3/3 pass — verified 1 patched file(s) on disk against the published afterHash
e2e_vendored_production (preflight + gem leg) 2/2 pass (vendor succeeds; NOTE branch fires as designed)
e2e_gem --ignored lifecycle (real proxy) 3/3 pass
in_process_vendor (hermetic) 34/34 pass incl. the new test

Gates: cargo fmt --check clean on touched files; clippy -D warnings clean on all four touched test targets; all suites compile.

Beyond the host runs, hosted/agent/vendored modes were swept today against this patch in 9 hermetic container lanes (bundler 1.17.3 / 2.7.2 / 4.0.18 × 3 modes, 60 scenario cells) — the confirmed CLI defects from that sweep are being fixed in separate PRs (crawler flat-BUNDLE_PATH layout, hosted stale-install warning, hosted-state visibility, vendored stub hardening); none of them affect the legs this PR restores.

Review round 2 (2026-08-19, adversarial review)

Hardening applied on top of the restore:

  • Hosted gem leg — self-adapting UUID handling (GEM_UUIDS any-of set, the PYPI_UUIDS precedent): selection is server-ranked and the non-TTY scan auto-selects the top candidate, so the leg now parses the UUID actually wired into the rewritten Gemfile's patch-registry URL (…/patch-registry/gem/<grant>/<uuid>/ — second segment; the grant is UUID-shaped too), asserts it is in the pinned set, and fetches /patch/view for that UUID for the afterHash verification. A server-side reorder or a second published 6.0.3 patch can no longer red the required check while the proof stays exact.
  • Hosted gem leg — hard-asserted wipe: the pre-reinstall BUNDLE_PATH removal is now expect-ed and asserted gone (a partial wipe let bundler reuse the stale pristine install under --test-threads=4 and the leg misattributed it as a published-patch regression).
  • Hosted gem leg — converged-lock proof: new assertions that the rewritten lock's GEM section remote: is on the patch registry and DEPENDENCIES carries the activestorage (= 6.0.3)! source pin (the feat(gem): hosted CHECKSUMS locks converge — patch-registry GEM section + dependency pin, frozen-installable #212 converged shape), and the reinstall now runs BUNDLE_FROZEN=true — the deployment-mode contract production users actually run under. Verified live on the host before pushing.
  • mimemagic hazard hardening: every gem-installing leg in e2e_hosted_production.rs and e2e_gem.rs sets USE_FREEDESKTOP_PLACEHOLDER=true — the 6.0.3/5.2.0 closures pull marcel → mimemagic, whose ext build otherwise needs the system shared-mime-info DB that no workflow installs.
  • published_patch_advisory_counts gained the HTTP-status guard its siblings already had (a 503/404 no longer surfaces as "bad JSON").
  • Comment/doc truthing: the "flows strip purl qualifiers" claim was wrong — nothing client-side strips; the SERVER normalizes both spellings (verified live). Hosted doc's gem coverage row now states what this suite pins (one purl/UUID) instead of an unasserted catalog count; the vendored doc history now says the pin was REPLACED (7.0.2.2 / 2535d43d-… withdrawn 2026-08-14 → re-pinned to 6.0.3 / 15e960b5-…), keeping the old identifiers findable.
  • e2e_redirect_gem_build.rs module doc reframed as historical (the compact-index dependency defect was fixed by the 2026-08-18 republish; the hermetic red-arm pins the contract regardless of prod state) and the dangling is_known_defect pointer now points at the docs history section; same for the red-arm test's "today's production behavior" comment.
  • e2e_gem.rs: the list --json assertion accepts the advisory as the GHSA id OR cves membership (production may leave cves empty); run() now scrubs ALL ambient SOCKET_* vars and sets SOCKET_NO_CONFIG=true (previously only the two token vars — a socket-cli apiBaseUrl could silently repoint the suite); assert_after_hashes gained the delete-entry branch (no afterHash → file must be ABSENT), mirroring assert_before_hashes.
  • in_process_vendor.rs: the qualified-purl test now has full parity with its bare twin (lock PATH remote, stub-gemspec materialization, downloaded == 1, and a positive applied-event assertion instead of the vacuous .all(errorCode != …)); the by-package mocks for both gem tests pin the exact percent-encoded bare path (the scan_vendor_e2e npm model) so a change in the spelling the CLI queries goes red; new test scan_vendor_gem_detached_qualified_purl_reverts covers the qualified-keyed detached ledger entry through vendor --revert (no manifest fallback exists for detached entries).

Deliberate skips (documented, not fixed in this PR):

  • The bare→qualified catalog-transition double-vendor scenario — a pre-republish manifest keyed by the bare purl plus a qualified re-scan yielding two ledger entries, with a reconcile_dropped hazard — is a follow-up, not addressed here.
  • The preflight/canary production probes remain sequential.

Round-2 validation: hosted live 5/5 (preflight + 3 canaries + hardened install proof, frozen reinstall, afterHash-verified); e2e_gem live 3/3; vendored live preflight + gem leg (untouched, re-run) 2/2; in_process_vendor hermetic 37/37 including the 2 qualified-purl tests; cargo fmt --check and clippy -D warnings clean on all five touched test targets.

🤖 Generated with Claude Code


Note

Low Risk
Changes are limited to ignored production e2e tests, hermetic vendor tests, and documentation—no runtime CLI or library code in the diff. Risk is CI signal and pin drift if production unpublishes patches, not user-facing behavior.

Overview
After the 2026-08-18 rubygems catalog republish (activestorage 5.2.0→6.0.3, CVE-2020-8162 / GHSA-m42x-37p3-fv5w), this PR re-pins all gem production and lifecycle tests and drops the temporary gem e2e shutdown.

Hosted production (e2e_hosted_production) removes GEM_E2E_DISABLED and probe-based install tolerance (gem_registry_base / http_probe). Pins move to pkg:gem/activestorage@6.0.3 / 15e960b5-…. The leg becomes gem_bundler_hosted_install_proof: unconditional redirect checks, CHECKSUMS swap, real bundle install via patch.socket.dev, and on-disk afterHash verification from /patch/view.

Vendored production (e2e_vendored_production) re-pins the same gem; vendor success is the expected path after #172. Full fresh-dir bundle install delivery proof stays deferred (invalid production gem-stub gemspec — documented OPEN).

Lifecycle (e2e_gem) re-pins ignored tests to activestorage 5.2.0 patch efc8d8ca-… with GEM_PURL using ?platform=ruby (manifest key from view response).

Hermetic (in_process_vendor) adds scan_vendor_gem_qualified_platform_ruby_purl_vendors and parametrizes mock API mounting so ?platform=ruby vendoring matches bare purls.

Docs (hosted-production-e2e.md, vendored-production-e2e.md) align pins and mark the compact-index defect FIXED; vendored doc adds OPEN stub-gemspec issue.

Reviewed by Cursor Bugbot for commit bed9c1a. Configure here.

Production republished the rubygems patch catalog on 2026-08-18: 15 free
activestorage patches (5.2.0-6.0.3, GHSA-m42x-37p3-fv5w / CVE-2020-8162).
The old pin activestorage@7.0.2.2 (2535d43d-…) no longer exists, and the
hosted registry's compact index now serves the full dependency list — the
server defect that motivated the temporary gem shutdown is fixed.

- e2e_hosted_production: delete the GEM_E2E_DISABLED kill switch (all 3
  sites) and the probe-based install tolerance per its own auto-retire
  design (gem_registry_base/http_probe helpers now dead, removed); re-pin
  to activestorage@6.0.3 / 15e960b5-…; the leg is renamed
  gem_bundler_hosted_install_proof and asserts the full chain
  unconditionally (redirect rewrite, CHECKSUMS pin swap to the patched
  sha, real install through patch.socket.dev, per-file afterHash
  verification). Verified live: 3/3 green incl. preflight + canary.
- e2e_vendored_production: re-pin; the platform_gem_unsupported tolerance
  is vestigial (gap fixed in #172) and the leg's doc comment now says so.
  The full delivery-proof upgrade is deferred to a stacked fix PR: the
  served gem-stub-gemspec artifact is currently invalid (missing
  summary/authors; bundler rejects the path source — discovered
  2026-08-19). Verified live: preflight + gem leg green.
- e2e_gem: re-pin the 5.2.0 lifecycle tests to the republished patch
  (efc8d8ca-…, CVE-2020-8162); GEM_PURL now carries ?platform=ruby
  because `get` keys the manifest by the view response's qualified purl.
  Verified live: 3/3 green.
- in_process_vendor: new test pinning the qualified-purl
  (?platform=ruby) path through scan --vendor — the regression that
  would silently re-open the #172 gap (ledger keyed by qualified purl,
  basePurl bare).
- docs/testing/{hosted,vendored}-production-e2e.md: catalogs re-pinned,
  defect sections converted to FIXED-history style, new OPEN section for
  the invalid served stub gemspec.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…zen converged-lock install proof, hermeticity

Round-2 fixes on the gem e2e restoration:

* hosted gem leg: GEM_UUIDS any-of set (PYPI_UUIDS precedent) — parse the
  UUID actually wired into the rewritten Gemfile's patch-registry URL,
  assert membership, and afterHash-verify against that exact patch's
  /patch/view; hard-assert the BUNDLE_PATH wipe; reinstall under
  BUNDLE_FROZEN=true with converged-lock assertions (patch-registry GEM
  remote + `activestorage (= 6.0.3)!` DEPENDENCIES pin), verified live
* mimemagic hazard: USE_FREEDESKTOP_PLACEHOLDER=true on every
  gem-installing leg in e2e_hosted_production.rs and e2e_gem.rs
* published_patch_advisory_counts: HTTP-status guard like its siblings
* truthing: qualifiers are normalized by the SERVER, nothing client-side
  strips (consts comments + hosted doc coverage row + vendored doc
  REPLACED-pin history keeping the withdrawn 7.0.2.2/2535d43d ids findable)
* e2e_redirect_gem_build.rs: module doc reframed historical, dangling
  is_known_defect pointer fixed to the docs history section
* e2e_gem.rs: GHSA-or-CVE advisory assertion, full SOCKET_* scrub +
  SOCKET_NO_CONFIG, assert_after_hashes delete-entry branch
* in_process_vendor.rs: qualified gem test at full parity with its bare
  twin (PATH remote, stub gemspec, downloaded==1, positive applied event),
  exact percent-encoded by-package mock paths, new detached-qualified
  revert test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Aug 19, 2026
…c is invalid

Defense-in-depth for defect D4 from the 2026-08-19 gem live-matrix campaign
(verified 6/6 live across bundler 1.17/2.7/4.0): production's gem-stub-gemspec
secondary artifact omits the rubygems-required `summary` and `authors`
attributes (and `licenses`). The CLI sha512-verified the stub and wrote it
verbatim as the vendored path-source `<name>.gemspec`, and every bundler major
validates path-source gemspecs, so any post-vendor or fresh-checkout
`bundle install` exited 1 with `missing value for attribute summary`. A
depscan-side fix for the stub generator is in flight, but every
currently-published gem stub is invalid, so the CLI hardens now.

An INVALID served stub now follows the existing MISSING-stub policy, under its
own code (additive/MINOR):

- `--vendor-source auto`: loud `vendor_prebuilt_stub_invalid` warning naming
  the missing attributes, then fall back to the local build (installed gem +
  locally derived stub);
- `--vendor-source service` (explicit): refuse with
  `vendor_prebuilt_stub_invalid`, naming the attributes and the remedy, before
  anything is written (no partial artifacts).

Validation is a conservative textual heuristic (assignment-line presence for
`summary` / `authors`|`author`, obviously-empty spellings rejected — no ruby
parsing); a legitimate stub always passes and is still written byte-verbatim.
A missing `licenses` is only mentioned in the message (rubygems warns, not
fails). CLI_CONTRACT.md documents the new code in the fallback ladder and the
PatchAction vocabulary.

Tests:
- hermetic (wiremock, RED->GREEN): auto+invalid-stub falls back to the local
  build with the loud warning and the LOCAL stub on disk; service+invalid-stub
  refuses with `vendor_prebuilt_stub_invalid` leaving no partial artifacts and
  an untouched lock; the valid-stub byte-verbatim write is pinned (the
  service-success fixture now carries the required attributes); plus a unit
  table for the heuristic's spellings.
- live regression leg: `e2e_vendored_production.rs`'s gem leg is upgraded to
  `gem_bundler_vendored_install_proof` — a full fresh-dir frozen
  `bundle install` delivery proof with the failure tolerance and the
  `SOCKET_PATCH_VENDORED_E2E_GEM_STRICT` knob deleted. It passes against real
  production TODAY via the auto fallback (the served stub is still invalid),
  and exercises the service artifact directly once the depscan fix deploys and
  the artifacts rebuild. The leg installs in bundler's deployment layout
  (`vendor/bundle` inside the project) so the crawler-visible install can feed
  the local-build fallback its stub gemspec.

Verified live against production: scan --mode vendored applied=1 via the
fallback with the `vendor_prebuilt_stub_invalid` event, vendored gemspec
carries real summary/authors; --vendor-source service refuses with the new
code and leaves no .socket/vendor.

Stacked on #217 (test/gem-e2e-restore).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Aug 19, 2026
…oth-arm stub validation, truthful dead-ends, on-disk heal

Adversarial-review fix round for the D4 stub-hardening PR.

SECURITY (1): the local-stub derivation walked two parents up from
installed_dir unconditionally. For a registry auto-fetch staging dir
(<private tempdir>/<name>-<version>) that escapes into the SHARED temp
root, making $TMPDIR/specifications/<leaf>.gemspec a predictable,
attacker-plantable path whose contents would be committed and eval'd as
Ruby by every later `bundle install`. The derivation now requires
installed_dir's parent to be a literal `gems/` dir (a real gem-home
layout); staging dirs have no local stub. Test plants a valid spec at
the old derivation target and proves it is never consumed.

Scanner rewrite (2): comment-stripping at `#` truncated inside string
literals (s.summary = "#1 Ruby web server" judged missing → valid stubs
refused under service). The scanner now examines raw lines anchored to
the line start (receiver ident + .attr + assignment), where a preceding
comment marker is impossible. The emptiness policy is now EMPIRICAL,
verified against rubygems 3.3/3.5/3.6 in the bundler 1.17/2.7/4.0 era
images: summary hard-fails only when never assigned (nil/"" are
writer-coerced, warning at most); authors hard-fails when never
assigned or collapsing to no String elements ([], nil, [nil], %w[] —
while [""] passes). The old code refused rubygems-tolerated stubs and
passed %w[] which hard-fails.

Both-arm validation (3): the local-build arm wrote the local stub
verbatim; it now validates at the same write choke point and refuses
`gem_spec_invalid` naming the file (new CLI_CONTRACT vocabulary row).
The GEMSPEC/GEMSPEC_318/GEMSPEC_PUMA and CLI-suite fixtures now carry
summary+authors like every healthy rubygems-written stub.

Truthful dead-end (4): auto + invalid served stub + gem not installed
used to refuse gem_spec_missing with circular advice ("use
--vendor-source=service" <-> service says "use auto") and the D4
diagnostic never reached the envelope (Refused carries no warnings).
The FallBack variant now carries the served-stub defect; the refusal is
`vendor_prebuilt_stub_invalid`, names the defect, and advises
installing the gem. Tests cover auto and service, both not-installed.

Heal existing victims (5): the idempotent hot path only checked the
vendored gemspec EXISTS, silently re-blessing pre-fix invalid stubs.
copy_ok now re-validates the on-disk stub; invalid routes into the
existing artifact-only rebuild (test: pre-seeded invalid stub on disk →
re-scan rewrites a valid one, pair edit + ledger untouched).

Dedupe (11 + addendum B): one shared attr_mention line-scanner under
both gemspec_declares_extensions and the attr checks; the miss closure
widened with the (hard code, remedy) pair instead of a re-implemented
branch; licenses/license alias fan-out folded into the alias-list
helper; stub_text bound once.

e2e leg robustness (6-10): bundler invocations scrub ambient
BUNDLE_*/GEM_*/RUBYOPT (sibling-suite pattern) and set
USE_FREEDESKTOP_PLACEHOLDER=true (mimemagic shared-mime-info hazard,
mirrors #217 round 2); delivery proof asserts canonicalized
starts_with(fresh-dir) provenance and compares installed bytes against
captured pristine bytes; a route-attribution assertion requires exactly
one of {vendor_prebuilt_downloaded, vendor_prebuilt_stub_invalid} so
the leg auto-retires the fallback expectation when the depscan stub fix
deploys; applied/failed/idempotency/revert assertions are scoped to the
activestorage purl so future catalog additions cannot red the leg;
stale doc comments fixed.

Contract (addendum A): documented why the service-mode refusal on an
invalid stub rides a MINOR — the prior exit-0 wrote a stub bundler
rejects (an uninstallable project); the refusal is the bug fix.

Rebased on test/gem-e2e-restore @ 63531d9 (PR #217 review round 2).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mikolalysenko
Mikola Lysenko (mikolalysenko) merged commit 739fd2c into main Aug 19, 2026
62 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the test/gem-e2e-restore branch August 19, 2026 19:17
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Aug 19, 2026
…c is invalid

Defense-in-depth for defect D4 from the 2026-08-19 gem live-matrix campaign
(verified 6/6 live across bundler 1.17/2.7/4.0): production's gem-stub-gemspec
secondary artifact omits the rubygems-required `summary` and `authors`
attributes (and `licenses`). The CLI sha512-verified the stub and wrote it
verbatim as the vendored path-source `<name>.gemspec`, and every bundler major
validates path-source gemspecs, so any post-vendor or fresh-checkout
`bundle install` exited 1 with `missing value for attribute summary`. A
depscan-side fix for the stub generator is in flight, but every
currently-published gem stub is invalid, so the CLI hardens now.

An INVALID served stub now follows the existing MISSING-stub policy, under its
own code (additive/MINOR):

- `--vendor-source auto`: loud `vendor_prebuilt_stub_invalid` warning naming
  the missing attributes, then fall back to the local build (installed gem +
  locally derived stub);
- `--vendor-source service` (explicit): refuse with
  `vendor_prebuilt_stub_invalid`, naming the attributes and the remedy, before
  anything is written (no partial artifacts).

Validation is a conservative textual heuristic (assignment-line presence for
`summary` / `authors`|`author`, obviously-empty spellings rejected — no ruby
parsing); a legitimate stub always passes and is still written byte-verbatim.
A missing `licenses` is only mentioned in the message (rubygems warns, not
fails). CLI_CONTRACT.md documents the new code in the fallback ladder and the
PatchAction vocabulary.

Tests:
- hermetic (wiremock, RED->GREEN): auto+invalid-stub falls back to the local
  build with the loud warning and the LOCAL stub on disk; service+invalid-stub
  refuses with `vendor_prebuilt_stub_invalid` leaving no partial artifacts and
  an untouched lock; the valid-stub byte-verbatim write is pinned (the
  service-success fixture now carries the required attributes); plus a unit
  table for the heuristic's spellings.
- live regression leg: `e2e_vendored_production.rs`'s gem leg is upgraded to
  `gem_bundler_vendored_install_proof` — a full fresh-dir frozen
  `bundle install` delivery proof with the failure tolerance and the
  `SOCKET_PATCH_VENDORED_E2E_GEM_STRICT` knob deleted. It passes against real
  production TODAY via the auto fallback (the served stub is still invalid),
  and exercises the service artifact directly once the depscan fix deploys and
  the artifacts rebuild. The leg installs in bundler's deployment layout
  (`vendor/bundle` inside the project) so the crawler-visible install can feed
  the local-build fallback its stub gemspec.

Verified live against production: scan --mode vendored applied=1 via the
fallback with the `vendor_prebuilt_stub_invalid` event, vendored gemspec
carries real summary/authors; --vendor-source service refuses with the new
code and leaves no .socket/vendor.

Stacked on #217 (test/gem-e2e-restore).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Aug 19, 2026
…oth-arm stub validation, truthful dead-ends, on-disk heal

Adversarial-review fix round for the D4 stub-hardening PR.

SECURITY (1): the local-stub derivation walked two parents up from
installed_dir unconditionally. For a registry auto-fetch staging dir
(<private tempdir>/<name>-<version>) that escapes into the SHARED temp
root, making $TMPDIR/specifications/<leaf>.gemspec a predictable,
attacker-plantable path whose contents would be committed and eval'd as
Ruby by every later `bundle install`. The derivation now requires
installed_dir's parent to be a literal `gems/` dir (a real gem-home
layout); staging dirs have no local stub. Test plants a valid spec at
the old derivation target and proves it is never consumed.

Scanner rewrite (2): comment-stripping at `#` truncated inside string
literals (s.summary = "#1 Ruby web server" judged missing → valid stubs
refused under service). The scanner now examines raw lines anchored to
the line start (receiver ident + .attr + assignment), where a preceding
comment marker is impossible. The emptiness policy is now EMPIRICAL,
verified against rubygems 3.3/3.5/3.6 in the bundler 1.17/2.7/4.0 era
images: summary hard-fails only when never assigned (nil/"" are
writer-coerced, warning at most); authors hard-fails when never
assigned or collapsing to no String elements ([], nil, [nil], %w[] —
while [""] passes). The old code refused rubygems-tolerated stubs and
passed %w[] which hard-fails.

Both-arm validation (3): the local-build arm wrote the local stub
verbatim; it now validates at the same write choke point and refuses
`gem_spec_invalid` naming the file (new CLI_CONTRACT vocabulary row).
The GEMSPEC/GEMSPEC_318/GEMSPEC_PUMA and CLI-suite fixtures now carry
summary+authors like every healthy rubygems-written stub.

Truthful dead-end (4): auto + invalid served stub + gem not installed
used to refuse gem_spec_missing with circular advice ("use
--vendor-source=service" <-> service says "use auto") and the D4
diagnostic never reached the envelope (Refused carries no warnings).
The FallBack variant now carries the served-stub defect; the refusal is
`vendor_prebuilt_stub_invalid`, names the defect, and advises
installing the gem. Tests cover auto and service, both not-installed.

Heal existing victims (5): the idempotent hot path only checked the
vendored gemspec EXISTS, silently re-blessing pre-fix invalid stubs.
copy_ok now re-validates the on-disk stub; invalid routes into the
existing artifact-only rebuild (test: pre-seeded invalid stub on disk →
re-scan rewrites a valid one, pair edit + ledger untouched).

Dedupe (11 + addendum B): one shared attr_mention line-scanner under
both gemspec_declares_extensions and the attr checks; the miss closure
widened with the (hard code, remedy) pair instead of a re-implemented
branch; licenses/license alias fan-out folded into the alias-list
helper; stub_text bound once.

e2e leg robustness (6-10): bundler invocations scrub ambient
BUNDLE_*/GEM_*/RUBYOPT (sibling-suite pattern) and set
USE_FREEDESKTOP_PLACEHOLDER=true (mimemagic shared-mime-info hazard,
mirrors #217 round 2); delivery proof asserts canonicalized
starts_with(fresh-dir) provenance and compares installed bytes against
captured pristine bytes; a route-attribution assertion requires exactly
one of {vendor_prebuilt_downloaded, vendor_prebuilt_stub_invalid} so
the leg auto-retires the fallback expectation when the depscan stub fix
deploys; applied/failed/idempotency/revert assertions are scoped to the
activestorage purl so future catalog additions cannot red the leg;
stale doc comments fixed.

Contract (addendum A): documented why the service-mode refusal on an
invalid stub rides a MINOR — the prior exit-0 wrote a stub bundler
rejects (an uninstallable project); the refusal is the bug fix.

Rebased on test/gem-e2e-restore @ 63531d9 (PR #217 review round 2).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Aug 19, 2026
…c is invalid (#221)

* test(gem): restore production e2e after the 2026-08-18 catalog republish

Production republished the rubygems patch catalog on 2026-08-18: 15 free
activestorage patches (5.2.0-6.0.3, GHSA-m42x-37p3-fv5w / CVE-2020-8162).
The old pin activestorage@7.0.2.2 (2535d43d-…) no longer exists, and the
hosted registry's compact index now serves the full dependency list — the
server defect that motivated the temporary gem shutdown is fixed.

- e2e_hosted_production: delete the GEM_E2E_DISABLED kill switch (all 3
  sites) and the probe-based install tolerance per its own auto-retire
  design (gem_registry_base/http_probe helpers now dead, removed); re-pin
  to activestorage@6.0.3 / 15e960b5-…; the leg is renamed
  gem_bundler_hosted_install_proof and asserts the full chain
  unconditionally (redirect rewrite, CHECKSUMS pin swap to the patched
  sha, real install through patch.socket.dev, per-file afterHash
  verification). Verified live: 3/3 green incl. preflight + canary.
- e2e_vendored_production: re-pin; the platform_gem_unsupported tolerance
  is vestigial (gap fixed in #172) and the leg's doc comment now says so.
  The full delivery-proof upgrade is deferred to a stacked fix PR: the
  served gem-stub-gemspec artifact is currently invalid (missing
  summary/authors; bundler rejects the path source — discovered
  2026-08-19). Verified live: preflight + gem leg green.
- e2e_gem: re-pin the 5.2.0 lifecycle tests to the republished patch
  (efc8d8ca-…, CVE-2020-8162); GEM_PURL now carries ?platform=ruby
  because `get` keys the manifest by the view response's qualified purl.
  Verified live: 3/3 green.
- in_process_vendor: new test pinning the qualified-purl
  (?platform=ruby) path through scan --vendor — the regression that
  would silently re-open the #172 gap (ledger keyed by qualified purl,
  basePurl bare).
- docs/testing/{hosted,vendored}-production-e2e.md: catalogs re-pinned,
  defect sections converted to FIXED-history style, new OPEN section for
  the invalid served stub gemspec.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(gem): adversarial-review hardening — self-adapting UUID pin, frozen converged-lock install proof, hermeticity

Round-2 fixes on the gem e2e restoration:

* hosted gem leg: GEM_UUIDS any-of set (PYPI_UUIDS precedent) — parse the
  UUID actually wired into the rewritten Gemfile's patch-registry URL,
  assert membership, and afterHash-verify against that exact patch's
  /patch/view; hard-assert the BUNDLE_PATH wipe; reinstall under
  BUNDLE_FROZEN=true with converged-lock assertions (patch-registry GEM
  remote + `activestorage (= 6.0.3)!` DEPENDENCIES pin), verified live
* mimemagic hazard: USE_FREEDESKTOP_PLACEHOLDER=true on every
  gem-installing leg in e2e_hosted_production.rs and e2e_gem.rs
* published_patch_advisory_counts: HTTP-status guard like its siblings
* truthing: qualifiers are normalized by the SERVER, nothing client-side
  strips (consts comments + hosted doc coverage row + vendored doc
  REPLACED-pin history keeping the withdrawn 7.0.2.2/2535d43d ids findable)
* e2e_redirect_gem_build.rs: module doc reframed historical, dangling
  is_known_defect pointer fixed to the docs history section
* e2e_gem.rs: GHSA-or-CVE advisory assertion, full SOCKET_* scrub +
  SOCKET_NO_CONFIG, assert_after_hashes delete-entry branch
* in_process_vendor.rs: qualified gem test at full parity with its bare
  twin (PATH remote, stub gemspec, downloaded==1, positive applied event),
  exact percent-encoded by-package mock paths, new detached-qualified
  revert test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(vendor): fall back to local build when the served gem stub gemspec is invalid

Defense-in-depth for defect D4 from the 2026-08-19 gem live-matrix campaign
(verified 6/6 live across bundler 1.17/2.7/4.0): production's gem-stub-gemspec
secondary artifact omits the rubygems-required `summary` and `authors`
attributes (and `licenses`). The CLI sha512-verified the stub and wrote it
verbatim as the vendored path-source `<name>.gemspec`, and every bundler major
validates path-source gemspecs, so any post-vendor or fresh-checkout
`bundle install` exited 1 with `missing value for attribute summary`. A
depscan-side fix for the stub generator is in flight, but every
currently-published gem stub is invalid, so the CLI hardens now.

An INVALID served stub now follows the existing MISSING-stub policy, under its
own code (additive/MINOR):

- `--vendor-source auto`: loud `vendor_prebuilt_stub_invalid` warning naming
  the missing attributes, then fall back to the local build (installed gem +
  locally derived stub);
- `--vendor-source service` (explicit): refuse with
  `vendor_prebuilt_stub_invalid`, naming the attributes and the remedy, before
  anything is written (no partial artifacts).

Validation is a conservative textual heuristic (assignment-line presence for
`summary` / `authors`|`author`, obviously-empty spellings rejected — no ruby
parsing); a legitimate stub always passes and is still written byte-verbatim.
A missing `licenses` is only mentioned in the message (rubygems warns, not
fails). CLI_CONTRACT.md documents the new code in the fallback ladder and the
PatchAction vocabulary.

Tests:
- hermetic (wiremock, RED->GREEN): auto+invalid-stub falls back to the local
  build with the loud warning and the LOCAL stub on disk; service+invalid-stub
  refuses with `vendor_prebuilt_stub_invalid` leaving no partial artifacts and
  an untouched lock; the valid-stub byte-verbatim write is pinned (the
  service-success fixture now carries the required attributes); plus a unit
  table for the heuristic's spellings.
- live regression leg: `e2e_vendored_production.rs`'s gem leg is upgraded to
  `gem_bundler_vendored_install_proof` — a full fresh-dir frozen
  `bundle install` delivery proof with the failure tolerance and the
  `SOCKET_PATCH_VENDORED_E2E_GEM_STRICT` knob deleted. It passes against real
  production TODAY via the auto fallback (the served stub is still invalid),
  and exercises the service artifact directly once the depscan fix deploys and
  the artifacts rebuild. The leg installs in bundler's deployment layout
  (`vendor/bundle` inside the project) so the crawler-visible install can feed
  the local-build fallback its stub gemspec.

Verified live against production: scan --mode vendored applied=1 via the
fallback with the `vendor_prebuilt_stub_invalid` event, vendored gemspec
carries real summary/authors; --vendor-source service refuses with the new
code and leaves no .socket/vendor.

Stacked on #217 (test/gem-e2e-restore).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(vendor): review round — gem-home guard, empirical rubygems bar, both-arm stub validation, truthful dead-ends, on-disk heal

Adversarial-review fix round for the D4 stub-hardening PR.

SECURITY (1): the local-stub derivation walked two parents up from
installed_dir unconditionally. For a registry auto-fetch staging dir
(<private tempdir>/<name>-<version>) that escapes into the SHARED temp
root, making $TMPDIR/specifications/<leaf>.gemspec a predictable,
attacker-plantable path whose contents would be committed and eval'd as
Ruby by every later `bundle install`. The derivation now requires
installed_dir's parent to be a literal `gems/` dir (a real gem-home
layout); staging dirs have no local stub. Test plants a valid spec at
the old derivation target and proves it is never consumed.

Scanner rewrite (2): comment-stripping at `#` truncated inside string
literals (s.summary = "#1 Ruby web server" judged missing → valid stubs
refused under service). The scanner now examines raw lines anchored to
the line start (receiver ident + .attr + assignment), where a preceding
comment marker is impossible. The emptiness policy is now EMPIRICAL,
verified against rubygems 3.3/3.5/3.6 in the bundler 1.17/2.7/4.0 era
images: summary hard-fails only when never assigned (nil/"" are
writer-coerced, warning at most); authors hard-fails when never
assigned or collapsing to no String elements ([], nil, [nil], %w[] —
while [""] passes). The old code refused rubygems-tolerated stubs and
passed %w[] which hard-fails.

Both-arm validation (3): the local-build arm wrote the local stub
verbatim; it now validates at the same write choke point and refuses
`gem_spec_invalid` naming the file (new CLI_CONTRACT vocabulary row).
The GEMSPEC/GEMSPEC_318/GEMSPEC_PUMA and CLI-suite fixtures now carry
summary+authors like every healthy rubygems-written stub.

Truthful dead-end (4): auto + invalid served stub + gem not installed
used to refuse gem_spec_missing with circular advice ("use
--vendor-source=service" <-> service says "use auto") and the D4
diagnostic never reached the envelope (Refused carries no warnings).
The FallBack variant now carries the served-stub defect; the refusal is
`vendor_prebuilt_stub_invalid`, names the defect, and advises
installing the gem. Tests cover auto and service, both not-installed.

Heal existing victims (5): the idempotent hot path only checked the
vendored gemspec EXISTS, silently re-blessing pre-fix invalid stubs.
copy_ok now re-validates the on-disk stub; invalid routes into the
existing artifact-only rebuild (test: pre-seeded invalid stub on disk →
re-scan rewrites a valid one, pair edit + ledger untouched).

Dedupe (11 + addendum B): one shared attr_mention line-scanner under
both gemspec_declares_extensions and the attr checks; the miss closure
widened with the (hard code, remedy) pair instead of a re-implemented
branch; licenses/license alias fan-out folded into the alias-list
helper; stub_text bound once.

e2e leg robustness (6-10): bundler invocations scrub ambient
BUNDLE_*/GEM_*/RUBYOPT (sibling-suite pattern) and set
USE_FREEDESKTOP_PLACEHOLDER=true (mimemagic shared-mime-info hazard,
mirrors #217 round 2); delivery proof asserts canonicalized
starts_with(fresh-dir) provenance and compares installed bytes against
captured pristine bytes; a route-attribution assertion requires exactly
one of {vendor_prebuilt_downloaded, vendor_prebuilt_stub_invalid} so
the leg auto-retires the fallback expectation when the depscan stub fix
deploys; applied/failed/idempotency/revert assertions are scoped to the
activestorage purl so future catalog additions cannot red the leg;
stale doc comments fixed.

Contract (addendum A): documented why the service-mode refusal on an
invalid stub rides a MINOR — the prior exit-0 wrote a stub bundler
rejects (an uninstallable project); the refusal is the bug fix.

Rebased on test/gem-e2e-restore @ 63531d9 (PR #217 review round 2).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants