sandbox-provider 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 012300e69a3b0389101f1d843340008aab5e7cc0ef0173227187e7a0f889ec52
4
- data.tar.gz: 10e39f638d1aec981f651a0ed391a07834fbb0a900944ae8ddcff6996a726cea
3
+ metadata.gz: c4be6ee4a326cae728dfa5986e371fb23a3b51a34646c3fc26d0c79e95647a7b
4
+ data.tar.gz: fd8ec5fda4686750696ea0e7ea14bdc317eeef2a90b6156ccee3c5ee91595e3b
5
5
  SHA512:
6
- metadata.gz: 12d574beb0f49b05519c9ff95fae5de37d5c54baf0fa034b1d0d64d138e99d6925531ea48d449e02d7ca4adbfe4a7d64597067a750e73b57a358de96388d66e5
7
- data.tar.gz: 7370726a28469cf76d5d55d55a20fc226928bea484e9739be9cba51f6e88bc32ab0b75b4787f6ce421f8486bd2ee22d27fcd1c354e78a434885c7c5436286f4d
6
+ metadata.gz: f874cc33545840d4a68b082858285aa9824f61743db170c38fa82a7b208ed646028be1750069f4a77a38707c306d54ebd52c191fd6b0f9a79d8f7c01beb9bbc5
7
+ data.tar.gz: 8b6d3e75a0e01167d9a83950b0d481abbf2267e3491283cdb82f84137594d441b971c1dab46c7182addd9c8a1fa87fc2482ddc95749f5c0e90e03e10d460fdde
@@ -0,0 +1,59 @@
1
+ # An SSH transport whose token another process can revoke by minting a new one. A command refused before
2
+ # it printed anything is tried once more with the store's current token.
3
+ class Sandbox::Provider::Daytona::Link
4
+ RETRY = [ *Sandbox::Adapter::Ssh::CONNECTION_ERRORS, Net::SSH::AuthenticationFailed ].freeze
5
+
6
+ def initialize(access, host_key: nil, on_host_key: nil)
7
+ @access = access
8
+ @host_key = host_key
9
+ @on_host_key = on_host_key
10
+ @ssh = build(access.call(nil))
11
+ end
12
+
13
+ def address = @ssh.address
14
+ def host = @ssh.host
15
+ def port = @ssh.port
16
+ def user = @ssh.user
17
+ def key = @ssh.key
18
+ def connection_errors = Sandbox::Adapter::Ssh::CONNECTION_ERRORS
19
+ def reattaches? = true
20
+
21
+ def exec(command, &block)
22
+ printed = false
23
+ begin
24
+ @ssh.exec(command) do |line|
25
+ printed = true
26
+ block&.call(line)
27
+ end
28
+ rescue *RETRY
29
+ raise if printed
30
+
31
+ refresh
32
+ @ssh.exec(command, &block)
33
+ end
34
+ end
35
+
36
+ def upload(path, io)
37
+ @ssh.upload(path, io)
38
+ rescue *RETRY
39
+ io.rewind if io.respond_to?(:rewind)
40
+ refresh
41
+ @ssh.upload(path, io)
42
+ end
43
+
44
+ def download(path)
45
+ @ssh.download(path)
46
+ rescue *RETRY
47
+ refresh
48
+ @ssh.download(path)
49
+ end
50
+
51
+ private
52
+
53
+ def refresh = @ssh = build(@access.call(@ssh.user))
54
+
55
+ def build(access)
56
+ Sandbox::Adapter::Ssh.new(host: access.host, port: access.port, user: access.token, key: nil,
57
+ host_key: @host_key, on_host_key: ->(key) { @host_key = key; @on_host_key&.call(key) })
58
+ end
59
+ end
@@ -15,9 +15,25 @@ class Sandbox::Provider::Daytona < Sandbox::Adapter::SandboxVm
15
15
  # An SSH token and where it lands, good until `until`.
16
16
  Access = Data.define(:host, :port, :token, :until)
17
17
  # One token per sandbox, kept until it nears expiry: minting a new one revokes the previous, so every
18
- # transport to the same sandbox (root or the deploy user) shares it. A fork gets its own.
19
- TOKENS = {}
20
- TOKENS_LOCK = Mutex.new
18
+ # transport to the same sandbox shares it, across processes when the store is shared. A fork gets its own.
19
+ # A store answers read(id), write(id, access), delete(id) and synchronize(id) { }.
20
+ class Tokens
21
+ def initialize
22
+ @tokens = {}
23
+ @lock = Monitor.new
24
+ end
25
+
26
+ def read(id) = @tokens[id]
27
+ def write(id, access) = @tokens[id] = access
28
+ def delete(id) = @tokens.delete(id)
29
+ def synchronize(_id, &) = @lock.synchronize(&)
30
+ end
31
+
32
+ class << self
33
+ attr_writer :tokens
34
+
35
+ def tokens = @tokens ||= Tokens.new
36
+ end
21
37
 
22
38
  def initialize(token, client: Client.new(token), **)
23
39
  super(token, **)
@@ -150,7 +166,7 @@ to: Time.current.utc.iso8601 })
150
166
 
151
167
  # A parent with live forks cannot go: the error says so.
152
168
  def destroy(m)
153
- TOKENS_LOCK.synchronize { TOKENS.delete(m.id) }
169
+ self.class.tokens.synchronize(m.id) { self.class.tokens.delete(m.id) }
154
170
  @client.delete("/sandbox/#{m.id}", force: true)
155
171
  rescue Error => e
156
172
  raise unless e.status == 404
@@ -165,19 +181,18 @@ to: Time.current.utc.iso8601 })
165
181
  end
166
182
 
167
183
  def transport(m, key: nil, host_key: nil, on_host_key: nil)
168
- access = TOKENS_LOCK.synchronize do
169
- kept = TOKENS[m.id]
170
- kept = nil if kept.nil? || kept.until < Time.current
171
- kept || (TOKENS[m.id] = mint(m.id))
184
+ Link.new(-> (stale) { access(m.id, stale:) }, host_key:, on_host_key:)
185
+ end
186
+
187
+ # The sandbox's token from the store, minted when there is none, it nears expiry, or it is `stale`: the
188
+ # one a refused connection used. Another process may have replaced it already; then that one is kept.
189
+ def access(id, stale: nil)
190
+ tokens = self.class.tokens
191
+ tokens.synchronize(id) do
192
+ kept = tokens.read(id)
193
+ kept = nil if kept.nil? || kept.until < Time.current || kept.token == stale
194
+ kept || mint(id).tap { |minted| tokens.write(id, minted) }
172
195
  end
173
- Sandbox::Adapter::Ssh.new(
174
- host: access.host,
175
- port: access.port,
176
- user: access.token,
177
- key: nil,
178
- host_key:,
179
- on_host_key:
180
- )
181
196
  end
182
197
 
183
198
  # Their preview link for the port: a host at their edge and a token it wants in a header. The token rotates
@@ -1,5 +1,5 @@
1
1
  module Sandbox
2
2
  module Provider
3
- VERSION = "0.1.1"
3
+ VERSION = "0.1.2"
4
4
  end
5
5
  end
@@ -12,6 +12,7 @@ require_relative "sandbox/provider/hetzner"
12
12
  require_relative "sandbox/provider/hetzner/client"
13
13
  require_relative "sandbox/provider/daytona"
14
14
  require_relative "sandbox/provider/daytona/client"
15
+ require_relative "sandbox/provider/daytona/link"
15
16
  require_relative "sandbox/provider/e2b"
16
17
  require_relative "sandbox/provider/e2b/client"
17
18
  require_relative "sandbox/provider/e2b/envd"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sandbox-provider
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - nvoi
@@ -52,6 +52,7 @@ files:
52
52
  - lib/sandbox/provider/cloud_init.rb
53
53
  - lib/sandbox/provider/daytona.rb
54
54
  - lib/sandbox/provider/daytona/client.rb
55
+ - lib/sandbox/provider/daytona/link.rb
55
56
  - lib/sandbox/provider/e2b.rb
56
57
  - lib/sandbox/provider/e2b/client.rb
57
58
  - lib/sandbox/provider/e2b/envd.rb