yamine 0.21.0 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/README.md +4 -3
- data/lib/yamine/database.rb +1 -0
- data/lib/yamine/proxy.rb +28 -2
- data/lib/yamine/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8e920f5f6d29a92e0a6e81ca671bccf62e0a264ec453f9b5bc4d42d4e56980d3
|
|
4
|
+
data.tar.gz: cc06342930ee7c882cf30fd2818f1a60495c8a59e44ec6779cc666f569493ac0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4164dabf9bd5537023ad59d426a958a5e284a90f0226cc83e0533cf635edf0c65acc16dd311d58a88df83d7abdcdfb92034703ecda06d89af08bb5ec96c73635
|
|
7
|
+
data.tar.gz: 1e3af2b55e54885fe8aeed98856c4371eab280ec981cd2644ebb75aba0206752ae44307c0252f51188a778426efbb882ef2285c63f142def39f4e876f77302d6
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.21.1] — 2026-09-29
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Claiming a per-worktree database no longer raises `NoMethodError`
|
|
10
|
+
on Ruby 3.2/3.3.** The claim stamps the state file with
|
|
11
|
+
`Time#iso8601`, but `lib/yamine/database.rb` never required the
|
|
12
|
+
stdlib `time` library, and on 3.2/3.3 nothing else loads it
|
|
13
|
+
implicitly — so every claim raised (34 unit errors on those rubies
|
|
14
|
+
in CI). 0.21.0 is affected. One `require "time"`, alongside the
|
|
15
|
+
stdlibs that file already pulls in.
|
|
16
|
+
- **A closed WebSocket upgrade no longer leaks a thread on Linux.**
|
|
17
|
+
`pipe_both` tore each end down with `close` from the sibling
|
|
18
|
+
thread, and a close from another thread does not interrupt that
|
|
19
|
+
copy's blocking read on Linux (it does on macOS) — so every closed
|
|
20
|
+
upgrade parked a thread forever, `handle` never unwound, and they
|
|
21
|
+
accumulated in the root daemon. Teardown is now symmetric
|
|
22
|
+
`shutdown(2)`, which wakes the parked read with EOF; both sockets
|
|
23
|
+
still close exactly once, and no timeout was added to the
|
|
24
|
+
unbounded upgrade path.
|
|
25
|
+
|
|
5
26
|
## [0.21.0] — 2026-09-28
|
|
6
27
|
|
|
7
28
|
### Security
|
data/README.md
CHANGED
|
@@ -508,10 +508,11 @@ bundle exec rake test
|
|
|
508
508
|
self-signed, and there is no buffering or rate limiting.
|
|
509
509
|
|
|
510
510
|
|
|
511
|
-
The `
|
|
511
|
+
The `test/fixtures/apps/` fixture fleet exercises
|
|
512
512
|
detection, inference, and boot across Rails variants, Roda, Sinatra,
|
|
513
|
-
bare Rack, Jekyll, compound Procfiles, and a monorepo.
|
|
514
|
-
|
|
513
|
+
bare Rack, Jekyll, compound Procfiles, and a monorepo. It ships with
|
|
514
|
+
the repo and runs as part of the unit suite across the Ruby matrix —
|
|
515
|
+
no sibling checkout, no separate CI job.
|
|
515
516
|
|
|
516
517
|
## License
|
|
517
518
|
|
data/lib/yamine/database.rb
CHANGED
data/lib/yamine/proxy.rb
CHANGED
|
@@ -566,25 +566,51 @@ module Yamine
|
|
|
566
566
|
# the other. Deliberately outside the idle bound: an idle websocket
|
|
567
567
|
# is legitimate traffic (silence is the normal state), and framing
|
|
568
568
|
# no longer applies once the connection is hijacked.
|
|
569
|
+
#
|
|
570
|
+
# Whichever direction reaches EOF first tears down BOTH ends, and it
|
|
571
|
+
# has to do that with shutdown before close. The sibling copy is
|
|
572
|
+
# parked in a blocking read on the socket being torn down, and a
|
|
573
|
+
# close from another thread does not interrupt that read on linux (it
|
|
574
|
+
# does on macOS) — so close-only left the parked copy alive forever
|
|
575
|
+
# and `t1.join` never returned: one leaked thread per closed upgrade,
|
|
576
|
+
# plus a `handle` that never unwound, in the root daemon. shutdown(2)
|
|
577
|
+
# changes the socket's kernel state instead of dropping the fd, so
|
|
578
|
+
# the parked read comes back with EOF at once — deterministic, and
|
|
579
|
+
# with no timeout added to a path that must stay unbounded.
|
|
569
580
|
def pipe_both(client, backend)
|
|
570
581
|
t1 = Thread.new do
|
|
571
582
|
IO.copy_stream(client, backend)
|
|
572
583
|
rescue IOError, SystemCallError
|
|
573
584
|
nil
|
|
574
585
|
ensure
|
|
575
|
-
backend
|
|
586
|
+
teardown_half(backend)
|
|
576
587
|
end
|
|
577
588
|
t2 = Thread.new do
|
|
578
589
|
IO.copy_stream(backend, client)
|
|
579
590
|
rescue IOError, SystemCallError
|
|
580
591
|
nil
|
|
581
592
|
ensure
|
|
582
|
-
client
|
|
593
|
+
teardown_half(client)
|
|
583
594
|
end
|
|
584
595
|
t1.join
|
|
585
596
|
t2.join
|
|
586
597
|
end
|
|
587
598
|
|
|
599
|
+
# End one end of a hijacked connection: unblock the sibling copy
|
|
600
|
+
# first, then close. Runs from an ensure, so it swallows everything
|
|
601
|
+
# — an exception escaping here would unwind into the acceptor.
|
|
602
|
+
def teardown_half(sock)
|
|
603
|
+
# An SSLSocket (the TLS client's socket) has no #shutdown; its
|
|
604
|
+
# kernel socket is one level down, and that is the fd the parked
|
|
605
|
+
# read is sitting on.
|
|
606
|
+
io = sock.respond_to?(:shutdown) ? sock : sock.to_io
|
|
607
|
+
io.shutdown(Socket::SHUT_RDWR)
|
|
608
|
+
rescue StandardError
|
|
609
|
+
nil
|
|
610
|
+
ensure
|
|
611
|
+
sock.close rescue nil
|
|
612
|
+
end
|
|
613
|
+
|
|
588
614
|
# DNS-rebinding boundary: the proxy binds loopback, so any website
|
|
589
615
|
# that tricks a browser into requesting 127.0.0.1 reaches us. A
|
|
590
616
|
# foreign Host (outside our TLDs) gets a bare 404 that names nothing —
|
data/lib/yamine/version.rb
CHANGED