Skip to content

fix(test): unflake the apply_lock orphaned-inode race; extend the hosted gem pin for production's fifth 6.0.3 patch - #232

Merged
Mikola Lysenko (mikolalysenko) merged 2 commits into
mainfrom
fix/apply-lock-orphan-test-race
Aug 25, 2026
Merged

fix(test): unflake the apply_lock orphaned-inode race; extend the hosted gem pin for production's fifth 6.0.3 patch#232
Mikola Lysenko (mikolalysenko) merged 2 commits into
mainfrom
fix/apply-lock-orphan-test-race

Conversation

@mikolalysenko

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

Copy link
Copy Markdown
Collaborator

Two test-only fixes for the two jobs currently failing every PR's CI (each fix alone would still be blocked by the other's failing job, so they ship together):

1. test (macos-latest): retry the apply_lock orphaned-inode choreography

patch::apply_lock::tests::waiter_does_not_lock_orphaned_inode_after_lock_file_deleted failed 3/3 attempts on PR #230's CI (a workflows/docs-only PR — Rust identical to main), in two distinct modes:

  1. Panic at apply_lock.rs:395 — the waiter's retry landed in the gap between the test's remove_file and its fresh acquire, when the lock was genuinely free. The waiter is a legitimate sole holder; the fresh try-once correctly returned Held and the test's .unwrap() blew up. Pure choreography bug: the test assumed the main thread always wins a race it can lose.
  2. Assert at apply_lock.rs:401 — the waiter opened the old inode, got descheduled across repair's drop+unlink, and flocked the orphan: the sanctioned microsecond open→flock window the module docs already accept. Re-opening per retry narrows it but can't close it.

Both need an unlucky deschedule, so they appear under loaded CI runners (2,540 parallel tests) and never locally in isolation.

Fix: retry the choreography up to 5 times; pass on the first clean iteration (fresh guard held while the waiter got Held). The clean outcome is unreachable under the regressed bug (a one-pre-loop-handle waiter always flocks its orphaned handle once the holder drops), so the bug still fails all 5 iterations; the benign races almost never repeat. 30 isolated + 3 full-suite parallel runs green locally.

2. hosted-e2e: extend GEM_UUIDS with production's fifth activestorage 6.0.3 patch

gem_bundler_hosted_install_proof fails deterministically since 2026-08-21T19:07Z: production extended the activestorage 6.0.3 set with a fifth advisoryGHSA-xr9x-r78c-5hrm / CVE-2026-66066 (libvips unfuzzed-operations arbitrary file read / RCE, CRITICAL) — and the server-ranked selection now wires its patch 9c2b4925-b413-4a3a-bb3a-9990440fb446, which the pinned any-of set predates. (Same class of failure as main's runs on 2026-08-21.)

Verified per the pin's own recipe before appending: /patch/view blobs fetched live 2026-08-24 — image_processing_transformer.rb (modified) and NEW lib/active_storage/vips.rb (backports Vips.block_untrusted(true)) both carry the Socket Community Patch header, git-blob-sha256-match their manifest afterHash entries, and contain no unexpected code. The gem leg passes against live production locally with the extended set.

Unblocks #230 (its test (macos-latest) check needs a re-run after this merges).

🤖 Generated with Claude Code

…te its two benign races

waiter_does_not_lock_orphaned_inode_after_lock_file_deleted failed 3/3
attempts on CI's macos-latest (PR #230's runs) in two distinct modes,
both scheduler races in the TEST, not the lock:

- the waiter's retry landed between remove_file and the test's fresh
  acquire, while the lock was genuinely free — the waiter is a
  legitimate sole holder and the fresh try-once .unwrap() panicked
  (apply_lock.rs:395);
- the waiter opened the old inode, was descheduled across repair's
  drop+unlink, and flocked the orphan — the sanctioned microsecond
  open->flock window the module docs accept for a fresh acquire
  (apply_lock.rs:401).

The regressed bug (one pre-loop handle re-flocked forever) double-holds
on essentially every iteration, while the benign losses need an unlucky
deschedule and almost never repeat — so retry the choreography up to 5
times, pass on the first clean iteration (fresh guard held, waiter got
Held — unreachable under the bug), and fail only if no iteration is
clean. 30 isolated runs + 3 full-suite (2540-test parallel) runs green
locally.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…orage 6.0.3 patch

hosted-e2e's gem_bundler_hosted_install_proof fails on every PR since
2026-08-21T19:07Z: production extended the activestorage 6.0.3 patch set
with a fifth advisory — GHSA-xr9x-r78c-5hrm / CVE-2026-66066 (libvips
unfuzzed-operations arbitrary file read / RCE) — and the server-ranked
selection now wires its patch 9c2b4925-b413-4a3a-bb3a-9990440fb446,
which the pinned any-of set predates.

Verified per the pin's own recipe before appending: /patch/view blobs
fetched live 2026-08-24 — image_processing_transformer.rb (modified) and
NEW lib/active_storage/vips.rb (backports Vips.block_untrusted) both
carry the Socket Community Patch header, git-blob-sha256-match their
manifest afterHash entries, and contain no unexpected code. The gem leg
passes against live production locally with the extended set.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mikolalysenko Mikola Lysenko (mikolalysenko) changed the title fix(test): retry the apply_lock orphaned-inode choreography to tolerate its two benign races fix(test): unflake the apply_lock orphaned-inode race; extend the hosted gem pin for production's fifth 6.0.3 patch Aug 24, 2026
@mikolalysenko
Mikola Lysenko (mikolalysenko) merged commit 2343d26 into main Aug 25, 2026
62 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the fix/apply-lock-orphan-test-race branch August 25, 2026 16:40
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