kobako 0.12.1-x64-mingw-ucrt → 0.12.2-x64-mingw-ucrt
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/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +11 -0
- data/README.md +1 -1
- data/crates/kobako-runtime/CHANGELOG.md +8 -0
- data/crates/kobako-runtime/README.md +34 -0
- data/crates/kobako-wasmtime/CHANGELOG.md +8 -0
- data/crates/kobako-wasmtime/README.md +32 -0
- data/data/kobako.wasm +0 -0
- data/lib/kobako/3.3/kobako.so +0 -0
- data/lib/kobako/3.4/kobako.so +0 -0
- data/lib/kobako/4.0/kobako.so +0 -0
- data/lib/kobako/catalog/handles.rb +3 -3
- data/lib/kobako/catalog/namespaces.rb +4 -0
- data/lib/kobako/catalog/snippets.rb +4 -0
- data/lib/kobako/codec/encoder.rb +5 -1
- data/lib/kobako/codec/factory.rb +41 -13
- data/lib/kobako/codec/handle_walk.rb +4 -0
- data/lib/kobako/errors.rb +18 -16
- data/lib/kobako/sandbox.rb +20 -18
- data/lib/kobako/sandbox_options.rb +25 -9
- data/lib/kobako/snapshot.rb +7 -13
- data/lib/kobako/transport/dispatcher.rb +2 -2
- data/lib/kobako/transport/response.rb +14 -14
- data/lib/kobako/transport/run.rb +2 -6
- data/lib/kobako/transport/yield.rb +1 -1
- data/lib/kobako/transport/yielder.rb +2 -2
- data/lib/kobako/version.rb +1 -1
- data/release-please-config.json +48 -3
- data/sig/kobako/codec/factory.rbs +3 -0
- data/sig/kobako/errors.rbs +7 -14
- data/sig/kobako/runtime.rbs +8 -3
- data/sig/kobako/sandbox.rbs +2 -2
- data/sig/kobako/sandbox_options.rbs +4 -2
- data/sig/kobako/snapshot.rbs +0 -3
- data/sig/kobako/transport/dispatcher.rbs +1 -1
- data/sig/kobako/transport/run.rbs +2 -2
- data/sig/kobako/transport/yielder.rbs +2 -2
- data/sig/kobako/transport.rbs +8 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4d5c8eb184e2525162c2ef24fee65a8b318fd0fd217cd4e57e7a440ffcfc29e6
|
|
4
|
+
data.tar.gz: b7b9797cb9d05410aaaf3f4535776022a48c55c027b6035448bcfa65047a67d7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ac65b5c77069b576c4a4660bfeabaec7f76f2aee21321322be340efa72758e33085953bebdc3cb76da566f55c3e2b3a4511b7175db508e611089978b0d3f2914
|
|
7
|
+
data.tar.gz: 2a8ca4897259c068094e2ddfa8b1a4f7f73e677d45530b42d33d948fde9ae17060bc31d73c894252320d14ef634df1c2729a9fcabe7e79493e577c2b5c1d5534
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{".":"0.12.
|
|
1
|
+
{".":"0.12.2","wasm/kobako-core":"0.6.1","wasm/kobako":"0.6.1","wasm/kobako-io":"0.6.1","wasm/kobako-json":"0.6.1","wasm/kobako-regexp":"0.6.1","wasm/kobako-baker":"0.6.1","crates/kobako-runtime":"0.6.1","crates/kobako-wasmtime":"0.6.1"}
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.12.2](https://github.com/elct9620/kobako/compare/v0.12.1...v0.12.2) (2026-07-02)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **codec:** bound ext-envelope nesting to keep deep Fault chains off the native stack ([7bed2b2](https://github.com/elct9620/kobako/commit/7bed2b2f43a63538aa60610c82d2eb65bcce7b15))
|
|
9
|
+
* **guest:** size collection conversions by C array length, not #length ([90ecbd0](https://github.com/elct9620/kobako/commit/90ecbd0cb6a990b8c5a1e5deec3a10df4eaa37df))
|
|
10
|
+
* **io:** enforce the fd allowlist at the write syscall ([1b300df](https://github.com/elct9620/kobako/commit/1b300df7bee8f87b701f76b42300163a8899b93e))
|
|
11
|
+
* **release:** advance last-release-sha past the unparseable fork merge ([d06117d](https://github.com/elct9620/kobako/commit/d06117d462eea0ae5648e5bdd6886b735765f3b3))
|
|
12
|
+
* **sandbox:** honor nil to disable the output caps, and validate them ([51d1e90](https://github.com/elct9620/kobako/commit/51d1e900e3d7d659ffd432ff3d613786e9073b05))
|
|
13
|
+
|
|
3
14
|
## [0.12.1](https://github.com/elct9620/kobako/compare/v0.12.0...v0.12.1) (2026-06-27)
|
|
4
15
|
|
|
5
16
|
|
data/README.md
CHANGED
|
@@ -127,7 +127,7 @@ end
|
|
|
127
127
|
|---------------------------------|----------------|------------------------------------------------------|
|
|
128
128
|
| `Kobako::TimeoutError` | `TrapError` | Per-invocation `timeout` exhausted |
|
|
129
129
|
| `Kobako::MemoryLimitError` | `TrapError` | Per-invocation `memory_limit` exhausted |
|
|
130
|
-
| `Kobako::
|
|
130
|
+
| `Kobako::HandleExhaustedError` | `SandboxError` | Handle counter reached its 2³¹ − 1 cap |
|
|
131
131
|
| `Kobako::BytecodeError` | `SandboxError` | `#preload(binary:)` failed RITE validation at replay |
|
|
132
132
|
|
|
133
133
|
`SandboxError` and `ServiceError` carry structured `origin` / `klass` / `backtrace_lines` / `details` fields when the guest produced a panic envelope.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# kobako-runtime
|
|
2
|
+
|
|
3
|
+
Engine-neutral host runtime contract for
|
|
4
|
+
[kobako](https://github.com/elct9620/kobako), an in-process Wasm
|
|
5
|
+
sandbox for running untrusted mruby scripts.
|
|
6
|
+
|
|
7
|
+
A kobako host drives a Guest Binary through a wasm engine; this crate
|
|
8
|
+
is the surface where the two meet, free of any engine or frontend
|
|
9
|
+
type, so the engine stays swappable:
|
|
10
|
+
|
|
11
|
+
- `runtime` — the `Runtime` trait: one guest invocation on a fresh
|
|
12
|
+
instance in, its observable `Snapshot` out
|
|
13
|
+
- `snapshot` — the per-invocation observables: `Completion` (outcome
|
|
14
|
+
or trap), the two output `Capture`s, and resource `Usage`, uniform
|
|
15
|
+
across success and trap
|
|
16
|
+
- `error` — the neutral failure channels: `Trap` (engine fault) and
|
|
17
|
+
`SetupError` (the invocation never started)
|
|
18
|
+
- `dispatch` / `yielder` — the `DispatchHandler` and `Yielder` traits
|
|
19
|
+
a frontend supplies for guest→host dispatch and block-yield re-entry
|
|
20
|
+
|
|
21
|
+
Engine implementations (such as `kobako-wasmtime`) implement
|
|
22
|
+
`Runtime`; host frontends (such as the kobako Ruby gem's native ext)
|
|
23
|
+
map the neutral types onto their own language surface.
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
```toml
|
|
28
|
+
[dependencies]
|
|
29
|
+
kobako-runtime = "0.6.1" # x-release-please-version
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## License
|
|
33
|
+
|
|
34
|
+
Apache-2.0
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# kobako-wasmtime
|
|
2
|
+
|
|
3
|
+
The [wasmtime](https://wasmtime.dev) implementation of the
|
|
4
|
+
[kobako](https://github.com/elct9620/kobako) host runtime contract
|
|
5
|
+
([`kobako-runtime`](https://crates.io/crates/kobako-runtime)).
|
|
6
|
+
|
|
7
|
+
`Driver` implements the contract's `Runtime` trait over wasmtime and
|
|
8
|
+
owns every engine-bound mechanic, so frontends see only the neutral
|
|
9
|
+
contract surface:
|
|
10
|
+
|
|
11
|
+
- process-wide Engine and compiled-Module caches with an on-disk AOT
|
|
12
|
+
(`.cwasm`) artifact cache keyed by Guest Binary content
|
|
13
|
+
- a pre-linked `InstancePre` per guest path; every invocation runs on
|
|
14
|
+
a fresh instance and discards its Store afterwards
|
|
15
|
+
- the epoch-based wall-clock timeout and the per-invocation
|
|
16
|
+
linear-memory cap
|
|
17
|
+
- ambient denial: frozen WASI clocks and a constant RNG, so a guest
|
|
18
|
+
observes no real time and no real entropy
|
|
19
|
+
|
|
20
|
+
The kobako Ruby gem's native ext is the first frontend; a Rust host
|
|
21
|
+
SDK consumes the same surface.
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```toml
|
|
26
|
+
[dependencies]
|
|
27
|
+
kobako-wasmtime = "0.6.1" # x-release-please-version
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## License
|
|
31
|
+
|
|
32
|
+
Apache-2.0
|
data/data/kobako.wasm
CHANGED
|
Binary file
|
data/lib/kobako/3.3/kobako.so
CHANGED
|
Binary file
|
data/lib/kobako/3.4/kobako.so
CHANGED
|
Binary file
|
data/lib/kobako/4.0/kobako.so
CHANGED
|
Binary file
|
|
@@ -38,7 +38,7 @@ module Kobako
|
|
|
38
38
|
# for it. +object+ is any host-side Ruby object to bind. Returns a
|
|
39
39
|
# freshly-allocated +Kobako::Handle+ whose +#id+ falls in
|
|
40
40
|
# +[Kobako::Handle::MIN_ID, Kobako::Handle::MAX_ID]+. Raises
|
|
41
|
-
# +Kobako::
|
|
41
|
+
# +Kobako::HandleExhaustedError+ if the next ID would exceed the
|
|
42
42
|
# cap. The cap is anchored on +Kobako::Handle+ — the wire codec
|
|
43
43
|
# and the allocator share the same invariant.
|
|
44
44
|
#
|
|
@@ -96,12 +96,12 @@ module Kobako
|
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
# Guard {#alloc} against issuing an ID past the cap. Returns +nil+
|
|
99
|
-
# on success; raises +Kobako::
|
|
99
|
+
# on success; raises +Kobako::HandleExhaustedError+ at exhaustion.
|
|
100
100
|
def ensure_capacity!
|
|
101
101
|
cap = Kobako::Handle::MAX_ID
|
|
102
102
|
return unless @next_id > cap
|
|
103
103
|
|
|
104
|
-
raise
|
|
104
|
+
raise HandleExhaustedError,
|
|
105
105
|
"Out of handle allocations: too many host objects were referenced " \
|
|
106
106
|
"in a single invocation (limit #{cap})"
|
|
107
107
|
end
|
|
@@ -82,6 +82,10 @@ module Kobako
|
|
|
82
82
|
# first invocation, so the preamble is exactly the bindings that
|
|
83
83
|
# existed at that moment — a bind reaching a +Kobako::Namespace+
|
|
84
84
|
# after the seal raises +ArgumentError+ and never alters Frame 1.
|
|
85
|
+
# The memo is gated on the seal rather than dropped per mutation (the
|
|
86
|
+
# +Catalog::Snippets#encode+ approach) because a +Member+ bind lands
|
|
87
|
+
# on a child +Kobako::Namespace+, invisible to this collection; only
|
|
88
|
+
# the seal guarantees nothing further can change.
|
|
85
89
|
def encode
|
|
86
90
|
return @encoded if @encoded
|
|
87
91
|
|
|
@@ -44,6 +44,10 @@ module Kobako
|
|
|
44
44
|
# The bytes are memoized — the table is replayed verbatim on every
|
|
45
45
|
# invocation after sealing, so Frame 3 never changes between
|
|
46
46
|
# encodes; {#register} drops the memo while the table is still open.
|
|
47
|
+
# Unlike +Catalog::Namespaces#encode+, which gates its memo on the
|
|
48
|
+
# seal, this one can fill eagerly and invalidate in +#register+
|
|
49
|
+
# because every mutation funnels through that single method — there is
|
|
50
|
+
# no out-of-sight child object to change the result behind its back.
|
|
47
51
|
def encode
|
|
48
52
|
return @encoded if @encoded
|
|
49
53
|
|
data/lib/kobako/codec/encoder.rb
CHANGED
|
@@ -26,7 +26,11 @@ module Kobako
|
|
|
26
26
|
# mapping is a closed set, and anything outside it is rejected by
|
|
27
27
|
# the msgpack gem itself (arbitrary objects raise +NoMethodError+
|
|
28
28
|
# from missing +to_msgpack+, integers outside i64..u64 raise
|
|
29
|
-
# +RangeError+).
|
|
29
|
+
# +RangeError+). The +NoMethodError+ catch is deliberately broad:
|
|
30
|
+
# MessagePack signals "no wire representation" only through that error,
|
|
31
|
+
# so there is no narrower discriminator — a packer-internal
|
|
32
|
+
# +NoMethodError+ is likewise reported as +UnsupportedType+ rather than
|
|
33
|
+
# propagating.
|
|
30
34
|
def self.encode(value)
|
|
31
35
|
Factory.dump(value)
|
|
32
36
|
rescue ::RangeError, ::NoMethodError => e
|
data/lib/kobako/codec/factory.rb
CHANGED
|
@@ -48,6 +48,16 @@ module Kobako
|
|
|
48
48
|
EXT_ERRENV = 0x02
|
|
49
49
|
private_constant :EXT_SYMBOL, :EXT_HANDLE, :EXT_ERRENV
|
|
50
50
|
|
|
51
|
+
# An ext 0x02 (Fault) envelope nests through its +details+ field, and
|
|
52
|
+
# each level re-enters the codec with a fresh +MessagePack+ unpacker
|
|
53
|
+
# whose built-in stack guard resets — so ext-envelope depth is tracked
|
|
54
|
+
# here instead. The cap matches the wire's overall nesting bound and
|
|
55
|
+
# keeps a nested chain from exhausting the native stack: an over-deep
|
|
56
|
+
# chain fails as a clean wire error, never a stack-level trap.
|
|
57
|
+
MAX_EXT_DEPTH = 128
|
|
58
|
+
EXT_DEPTH_KEY = :__kobako_codec_ext_depth__
|
|
59
|
+
private_constant :MAX_EXT_DEPTH, :EXT_DEPTH_KEY
|
|
60
|
+
|
|
51
61
|
# Instance-level pass-through onto the wrapped +MessagePack::Factory+.
|
|
52
62
|
# Spelled +def_instance_delegators+ rather than +def_delegators+ because
|
|
53
63
|
# the class also extends +SingleForwardable+ (see the +extend+ block
|
|
@@ -129,9 +139,13 @@ module Kobako
|
|
|
129
139
|
# Encode the inner ext-0x02 map via {Encoder} (not +factory.dump+) so
|
|
130
140
|
# the embedded payload flows through the same boundary as a top-level
|
|
131
141
|
# encode — nested kobako values (Handle, nested Fault) reach the
|
|
132
|
-
# registered ext-type packers via the cached singleton.
|
|
142
|
+
# registered ext-type packers via the cached singleton. A +details+
|
|
143
|
+
# chain nested past {MAX_EXT_DEPTH} has no wire representation and
|
|
144
|
+
# surfaces as +UnsupportedType+.
|
|
133
145
|
def pack_fault(fault)
|
|
134
|
-
|
|
146
|
+
within_ext_frame(UnsupportedType) do
|
|
147
|
+
Encoder.encode("type" => fault.type, "message" => fault.message, "details" => fault.details)
|
|
148
|
+
end
|
|
135
149
|
end
|
|
136
150
|
|
|
137
151
|
# Peel the embedded msgpack map and hand it to +Kobako::Fault.new+
|
|
@@ -139,19 +153,33 @@ module Kobako
|
|
|
139
153
|
# +ArgumentError+ invariants surface as +InvalidType+ through the
|
|
140
154
|
# decoder boundary. Inner decode goes through {Decoder} (not
|
|
141
155
|
# +factory.load+) so the embedded +str+ payloads flow through the
|
|
142
|
-
# same UTF-8 validation as a top-level decode.
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
# singleton instance feeds +Decoder.decode+, which re-enters this
|
|
146
|
-
# method when a nested ext 0x02 appears inside +details+. The recursion
|
|
147
|
-
# is bounded by msgpack nesting depth — identical to nested Array /
|
|
148
|
-
# Hash payloads — so no extra guard is needed. Do not switch back to
|
|
149
|
-
# +factory.load+ to "simplify": that path bypasses UTF-8 validation.
|
|
156
|
+
# same UTF-8 validation as a top-level decode. A nested ext 0x02 in
|
|
157
|
+
# +details+ re-enters this method, so {#within_ext_frame} bounds the
|
|
158
|
+
# chain depth to keep it from exhausting the native stack.
|
|
150
159
|
def unpack_fault(payload)
|
|
151
|
-
|
|
152
|
-
|
|
160
|
+
within_ext_frame(InvalidType) do
|
|
161
|
+
Decoder.decode(payload) do |map|
|
|
162
|
+
raise InvalidType, "Fault payload must be a map" unless map.is_a?(Hash)
|
|
163
|
+
|
|
164
|
+
Kobako::Fault.new(type: map["type"], message: map["message"], details: map["details"])
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
153
168
|
|
|
154
|
-
|
|
169
|
+
# Track ext-envelope re-entry depth and refuse a chain past
|
|
170
|
+
# {MAX_EXT_DEPTH}, raising +over_limit+ so the failure lands in the
|
|
171
|
+
# caller's existing wire-error class. The counter is thread-scoped and
|
|
172
|
+
# balanced by the +ensure+, so a raise mid-chain still unwinds it to
|
|
173
|
+
# its entry value.
|
|
174
|
+
def within_ext_frame(over_limit)
|
|
175
|
+
depth = (Thread.current[EXT_DEPTH_KEY] || 0) + 1
|
|
176
|
+
raise over_limit, "ext envelope nesting exceeds #{MAX_EXT_DEPTH} levels" if depth > MAX_EXT_DEPTH
|
|
177
|
+
|
|
178
|
+
Thread.current[EXT_DEPTH_KEY] = depth
|
|
179
|
+
begin
|
|
180
|
+
yield
|
|
181
|
+
ensure
|
|
182
|
+
Thread.current[EXT_DEPTH_KEY] = depth - 1
|
|
155
183
|
end
|
|
156
184
|
end
|
|
157
185
|
end
|
|
@@ -97,6 +97,10 @@ module Kobako
|
|
|
97
97
|
case value
|
|
98
98
|
when ::Array then value.map { |element| HandleWalk.deep_restore(element, handler) }
|
|
99
99
|
when ::Hash
|
|
100
|
+
# Rebuilt with each key restored: two distinct Handle keys that
|
|
101
|
+
# resolve to equal host objects collapse to the later pair, as in
|
|
102
|
+
# any Ruby Hash. The guest authored this payload, so that collapse
|
|
103
|
+
# is its own concern, not a fidelity guarantee the host owes it.
|
|
100
104
|
value.to_h { |key, val| [HandleWalk.deep_restore(key, handler), HandleWalk.deep_restore(val, handler)] }
|
|
101
105
|
when Kobako::Handle then handler.fetch(value.id)
|
|
102
106
|
else value
|
data/lib/kobako/errors.rb
CHANGED
|
@@ -35,7 +35,7 @@ module Kobako
|
|
|
35
35
|
#
|
|
36
36
|
# * {ModuleNotBuiltError} < {SetupError} — Guest Binary artifact absent
|
|
37
37
|
# at +wasm_path+.
|
|
38
|
-
# * {
|
|
38
|
+
# * {HandleExhaustedError} < {SandboxError} — Handle id cap hit.
|
|
39
39
|
|
|
40
40
|
# Base for all kobako-raised errors so callers that want to ignore the
|
|
41
41
|
# taxonomy can rescue a single class.
|
|
@@ -89,10 +89,13 @@ module Kobako
|
|
|
89
89
|
# +ModuleNotBuiltError+ first.
|
|
90
90
|
class ModuleNotBuiltError < SetupError; end
|
|
91
91
|
|
|
92
|
-
#
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
|
|
92
|
+
# The structured attribution the two invocation-failure classes carry
|
|
93
|
+
# from a decoded guest exception — its +origin+, original +klass+,
|
|
94
|
+
# +backtrace_lines+, and +details+ — so a Host App can inspect a failure
|
|
95
|
+
# beyond its message. Mixed into both rather than promoted to a shared
|
|
96
|
+
# superclass because +SandboxError+ and +ServiceError+ sit in distinct
|
|
97
|
+
# branches of the invocation-outcome taxonomy under +Kobako::Error+.
|
|
98
|
+
module StructuredError
|
|
96
99
|
attr_reader :origin, :klass, :backtrace_lines, :details
|
|
97
100
|
|
|
98
101
|
def initialize(message, origin: nil, klass: nil, backtrace_lines: nil, details: nil)
|
|
@@ -104,26 +107,25 @@ module Kobako
|
|
|
104
107
|
end
|
|
105
108
|
end
|
|
106
109
|
|
|
110
|
+
# Sandbox / wire layer. Raised when the guest ran to completion but
|
|
111
|
+
# execution failed due to a mruby script error, a protocol fault, or a
|
|
112
|
+
# host-side wire decode failure on an otherwise valid outcome tag.
|
|
113
|
+
class SandboxError < Error
|
|
114
|
+
include StructuredError
|
|
115
|
+
end
|
|
116
|
+
|
|
107
117
|
# Service layer. Raised when a Service capability call inside a mruby
|
|
108
118
|
# script reported an application-level failure that the script did not
|
|
109
119
|
# rescue.
|
|
110
120
|
class ServiceError < Error
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
def initialize(message, origin: nil, klass: nil, backtrace_lines: nil, details: nil)
|
|
114
|
-
super(message)
|
|
115
|
-
@origin = origin
|
|
116
|
-
@klass = klass
|
|
117
|
-
@backtrace_lines = backtrace_lines
|
|
118
|
-
@details = details
|
|
119
|
-
end
|
|
121
|
+
include StructuredError
|
|
120
122
|
end
|
|
121
123
|
|
|
122
|
-
#
|
|
124
|
+
# HandleExhaustedError is the canonical SandboxError subclass for the
|
|
123
125
|
# id-cap-hit path. Raised when the per-invocation Handle ID counter in
|
|
124
126
|
# Catalog::Handles reaches +0x7fff_ffff+ (2³¹ − 1) and further
|
|
125
127
|
# allocation would exceed the cap.
|
|
126
|
-
class
|
|
128
|
+
class HandleExhaustedError < SandboxError; end
|
|
127
129
|
|
|
128
130
|
# BytecodeError is the SandboxError subclass raised when a
|
|
129
131
|
# `#preload(binary:)` snippet fails structural validation during the
|
data/lib/kobako/sandbox.rb
CHANGED
|
@@ -89,7 +89,9 @@ module Kobako
|
|
|
89
89
|
# normalisation. The constructed +SandboxOptions+ is exposed as
|
|
90
90
|
# +#options+ and the four caps remain readable directly on Sandbox via
|
|
91
91
|
# +Forwardable+ delegation.
|
|
92
|
-
def initialize(wasm_path: nil,
|
|
92
|
+
def initialize(wasm_path: nil,
|
|
93
|
+
stdout_limit: SandboxOptions::DEFAULT_OUTPUT_LIMIT,
|
|
94
|
+
stderr_limit: SandboxOptions::DEFAULT_OUTPUT_LIMIT,
|
|
93
95
|
timeout: SandboxOptions::DEFAULT_TIMEOUT_SECONDS,
|
|
94
96
|
memory_limit: SandboxOptions::DEFAULT_MEMORY_LIMIT)
|
|
95
97
|
@wasm_path = wasm_path || Kobako::Runtime.default_path
|
|
@@ -207,17 +209,17 @@ module Kobako
|
|
|
207
209
|
|
|
208
210
|
private
|
|
209
211
|
|
|
210
|
-
# Configure the +Runtime+'s host↔guest dispatch wiring.
|
|
211
|
-
#
|
|
212
|
-
# +
|
|
213
|
-
#
|
|
214
|
-
#
|
|
215
|
-
#
|
|
216
|
-
#
|
|
212
|
+
# Configure the +Runtime+'s host↔guest dispatch wiring. Registers a
|
|
213
|
+
# dispatch +Proc+ that routes guest→host calls through the stateless
|
|
214
|
+
# +Transport::Dispatcher+, capturing +@services+ / +@handler+ in the
|
|
215
|
+
# closure. The ext hands the +Proc+ a per-dispatch +guest_yielder+ — a
|
|
216
|
+
# +String → String+ callable that re-enters the in-flight guest to run a
|
|
217
|
+
# yielded block — which the +Dispatcher+ forwards to the +Transport::Yielder+
|
|
218
|
+
# it builds for the call. Registered once at construction time so the
|
|
219
|
+
# wasm ext callback can fire without further setup.
|
|
217
220
|
def install_dispatch_proc!
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
Transport::Dispatcher.dispatch(request_bytes, @services, @handler, yield_to_guest)
|
|
221
|
+
@runtime.on_dispatch = lambda do |request_bytes, guest_yielder|
|
|
222
|
+
Transport::Dispatcher.dispatch(request_bytes, @services, @handler, guest_yielder)
|
|
221
223
|
end
|
|
222
224
|
end
|
|
223
225
|
|
|
@@ -226,8 +228,7 @@ module Kobako
|
|
|
226
228
|
# state — capture buffers, truncation predicates, and the
|
|
227
229
|
# +Catalog::Handles+ counter — before the guest runs. The
|
|
228
230
|
# +Catalog::Handles+ itself is held as +@handler+ and never exposed
|
|
229
|
-
# beyond this class
|
|
230
|
-
# Host App".
|
|
231
|
+
# beyond this class — it is not part of the Host App's surface.
|
|
231
232
|
def begin_invocation!
|
|
232
233
|
@services.seal!
|
|
233
234
|
@handler.reset!
|
|
@@ -239,9 +240,10 @@ module Kobako
|
|
|
239
240
|
# the +invoke!+ +ensure+ block so the usage record is populated on
|
|
240
241
|
# every outcome — value return, +Kobako::TrapError+ (including
|
|
241
242
|
# +TimeoutError+ / +MemoryLimitError+), +Kobako::SandboxError+,
|
|
242
|
-
# and +Kobako::ServiceError+.
|
|
243
|
-
#
|
|
244
|
-
#
|
|
243
|
+
# and +Kobako::ServiceError+. +Runtime#usage+ is the single source for
|
|
244
|
+
# both paths: the figures are stashed in the ext on every outcome, so
|
|
245
|
+
# unlike the +Snapshot+ (built only on success) the readout here also
|
|
246
|
+
# covers the trap path.
|
|
245
247
|
#
|
|
246
248
|
# The ext returns a positional 2-tuple +[wall_time, memory_peak]+
|
|
247
249
|
# whose order matches the +Kobako::Usage+ field order; the
|
|
@@ -272,8 +274,8 @@ module Kobako
|
|
|
272
274
|
# TrapError message so the failing export is identifiable.
|
|
273
275
|
#
|
|
274
276
|
# The yielded block must return a +Kobako::Snapshot+ — i.e. the
|
|
275
|
-
# value of +Runtime#eval+ / +#run
|
|
276
|
-
#
|
|
277
|
+
# value of +Runtime#eval+ / +#run+. The success path unpacks
|
|
278
|
+
# +#stdout+ / +#stderr+ into
|
|
277
279
|
# +Capture+ and feeds +#return_bytes+ to +Outcome.decode+; usage is
|
|
278
280
|
# populated by the +ensure+ readout ({#read_usage!}) on every outcome.
|
|
279
281
|
# The rescue chain is the single trap-translation boundary —
|
|
@@ -6,11 +6,13 @@ module Kobako
|
|
|
6
6
|
# Data.define(...)+ subclass form (the Steep-friendly shape — see
|
|
7
7
|
# +lib/kobako/outcome/panic.rb+).
|
|
8
8
|
#
|
|
9
|
-
# The +initialize+
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
9
|
+
# The +initialize+ normalises every cap before delegating to Data's
|
|
10
|
+
# +super+: +timeout+ to Float seconds, +memory_limit+ / +stdout_limit+ /
|
|
11
|
+
# +stderr_limit+ to positive Integer bytes. Each cap is +nil+-disablable
|
|
12
|
+
# (an absent argument takes its DEFAULT; an explicit +nil+ leaves the
|
|
13
|
+
# bound off), so all four behave uniformly. Anything that survives
|
|
14
|
+
# +SandboxOptions.new+ is a wire-ready cap bundle the +Kobako::Runtime+
|
|
15
|
+
# constructor consumes as-is.
|
|
14
16
|
class SandboxOptions < Data.define(:timeout, :memory_limit, :stdout_limit, :stderr_limit)
|
|
15
17
|
# Default wall-clock timeout for a single invocation: 60 seconds.
|
|
16
18
|
DEFAULT_TIMEOUT_SECONDS = 60.0
|
|
@@ -25,12 +27,12 @@ module Kobako
|
|
|
25
27
|
|
|
26
28
|
def initialize(timeout: DEFAULT_TIMEOUT_SECONDS,
|
|
27
29
|
memory_limit: DEFAULT_MEMORY_LIMIT,
|
|
28
|
-
stdout_limit:
|
|
29
|
-
stderr_limit:
|
|
30
|
+
stdout_limit: DEFAULT_OUTPUT_LIMIT,
|
|
31
|
+
stderr_limit: DEFAULT_OUTPUT_LIMIT)
|
|
30
32
|
timeout = normalize_timeout(timeout)
|
|
31
33
|
memory_limit = normalize_memory_limit(memory_limit)
|
|
32
|
-
stdout_limit
|
|
33
|
-
stderr_limit
|
|
34
|
+
stdout_limit = normalize_output_limit(stdout_limit, "stdout_limit")
|
|
35
|
+
stderr_limit = normalize_output_limit(stderr_limit, "stderr_limit")
|
|
34
36
|
super
|
|
35
37
|
end
|
|
36
38
|
|
|
@@ -62,5 +64,19 @@ module Kobako
|
|
|
62
64
|
|
|
63
65
|
memory_limit
|
|
64
66
|
end
|
|
67
|
+
|
|
68
|
+
# Coerce a per-channel output cap (+stdout_limit+ / +stderr_limit+)
|
|
69
|
+
# into the byte cap the ext expects, or +nil+ to leave the channel
|
|
70
|
+
# uncapped. Same shape as +normalize_memory_limit+: a positive Integer
|
|
71
|
+
# when set, Float / zero / negative rejected. +name+ tags the
|
|
72
|
+
# +ArgumentError+ with the offending keyword.
|
|
73
|
+
def normalize_output_limit(limit, name)
|
|
74
|
+
return nil if limit.nil?
|
|
75
|
+
unless limit.is_a?(Integer) && limit.positive?
|
|
76
|
+
raise ArgumentError, "#{name} must be a positive Integer or nil, got #{limit.inspect}"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
limit
|
|
80
|
+
end
|
|
65
81
|
end
|
|
66
82
|
end
|
data/lib/kobako/snapshot.rb
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "capture"
|
|
4
|
-
require_relative "usage"
|
|
5
4
|
|
|
6
5
|
module Kobako
|
|
7
6
|
# Kobako::Snapshot — per-invocation observable bundle returned from
|
|
8
7
|
# +Kobako::Runtime#eval+ and +#run+.
|
|
9
8
|
#
|
|
10
|
-
# The magnus class (see ext/kobako/src/snapshot.rs) carries
|
|
9
|
+
# The magnus class (see ext/kobako/src/snapshot.rs) carries five raw
|
|
11
10
|
# readers: +return_bytes+, +stdout_bytes+, +stdout_truncated+,
|
|
12
|
-
# +stderr_bytes+, +stderr_truncated
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
11
|
+
# +stderr_bytes+, +stderr_truncated+. This file reopens the class to add
|
|
12
|
+
# the Ruby-side helpers that pack those raw fields into the user-facing
|
|
13
|
+
# value object +Kobako::Capture+ — the same shape +Kobako::Sandbox+
|
|
14
|
+
# exposes to the Host App. Usage is not on the Snapshot; +Sandbox#usage+
|
|
15
|
+
# reads it from +Kobako::Runtime#usage+, which also covers the trap path
|
|
16
|
+
# where no Snapshot is produced.
|
|
17
17
|
class Snapshot
|
|
18
18
|
# Wrap the stdout capture pair (+stdout_bytes+, +stdout_truncated+)
|
|
19
19
|
# as a +Kobako::Capture+ value object. The byte content never carries
|
|
@@ -28,11 +28,5 @@ module Kobako
|
|
|
28
28
|
def stderr
|
|
29
29
|
Capture.new(bytes: stderr_bytes, truncated: stderr_truncated)
|
|
30
30
|
end
|
|
31
|
-
|
|
32
|
-
# Wrap the per-last-invocation usage pair (+wall_time+,
|
|
33
|
-
# +memory_peak+) as a +Kobako::Usage+ value object.
|
|
34
|
-
def usage
|
|
35
|
-
Usage.new(wall_time: wall_time, memory_peak: memory_peak)
|
|
36
|
-
end
|
|
37
31
|
end
|
|
38
32
|
end
|
|
@@ -72,8 +72,8 @@ module Kobako
|
|
|
72
72
|
# closure so the Dispatcher stays stateless and the registry doesn't
|
|
73
73
|
# need to publish accessors for the Sandbox-owned +Catalog::Handles+
|
|
74
74
|
# or +Runtime+. +yield_to_guest+ is a +String → String+ callable
|
|
75
|
-
# (
|
|
76
|
-
#
|
|
75
|
+
# (the ext's per-dispatch +Kobako::Runtime::GuestYielder+) used only
|
|
76
|
+
# when the Request carries +block_given: true+. Always
|
|
77
77
|
# returns a binary String — every failure path is reified as a
|
|
78
78
|
# Response.error envelope so the guest sees a transport error rather
|
|
79
79
|
# than a wasm trap.
|
|
@@ -38,20 +38,6 @@ module Kobako
|
|
|
38
38
|
new(status: STATUS_ERROR, payload: fault)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
# Decode +bytes+ into a {Response}. Raises +Codec::InvalidType+ when the
|
|
42
|
-
# envelope is not the expected 2-element msgpack array, or when the
|
|
43
|
-
# Value Object's construction invariants reject the decoded fields.
|
|
44
|
-
def self.decode(bytes)
|
|
45
|
-
Codec::Decoder.decode(bytes) do |arr|
|
|
46
|
-
unless arr.is_a?(Array) && arr.length == 2
|
|
47
|
-
raise Codec::InvalidType, "Response envelope is malformed (expected a 2-element array)"
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
status, payload = arr
|
|
51
|
-
new(status: status, payload: payload)
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
41
|
def initialize(status:, payload:)
|
|
56
42
|
unless [STATUS_OK, STATUS_ERROR].include?(status)
|
|
57
43
|
raise ArgumentError, "Response status must be 0 (ok) or 1 (error), got #{status.inspect}"
|
|
@@ -71,6 +57,20 @@ module Kobako
|
|
|
71
57
|
def encode
|
|
72
58
|
Codec::Encoder.encode([status, payload])
|
|
73
59
|
end
|
|
60
|
+
|
|
61
|
+
# Decode +bytes+ into a {Response}. Raises +Codec::InvalidType+ when the
|
|
62
|
+
# envelope is not the expected 2-element msgpack array, or when the
|
|
63
|
+
# Value Object's construction invariants reject the decoded fields.
|
|
64
|
+
def self.decode(bytes)
|
|
65
|
+
Codec::Decoder.decode(bytes) do |arr|
|
|
66
|
+
unless arr.is_a?(Array) && arr.length == 2
|
|
67
|
+
raise Codec::InvalidType, "Response envelope is malformed (expected a 2-element array)"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
status, payload = arr
|
|
71
|
+
new(status: status, payload: payload)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
74
|
end
|
|
75
75
|
end
|
|
76
76
|
end
|
data/lib/kobako/transport/run.rb
CHANGED
|
@@ -43,8 +43,8 @@ module Kobako
|
|
|
43
43
|
|
|
44
44
|
def initialize(entrypoint:, args: [], kwargs: {})
|
|
45
45
|
entrypoint = normalize_entrypoint(entrypoint)
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
validate_args!(args)
|
|
47
|
+
validate_kwargs!(kwargs)
|
|
48
48
|
super
|
|
49
49
|
end
|
|
50
50
|
|
|
@@ -100,8 +100,6 @@ module Kobako
|
|
|
100
100
|
def validate_args!(args)
|
|
101
101
|
raise ArgumentError, "arguments must be an Array" unless args.is_a?(Array)
|
|
102
102
|
raise ArgumentError, forged_handle_message("arguments") if args.any?(Kobako::Handle)
|
|
103
|
-
|
|
104
|
-
args
|
|
105
103
|
end
|
|
106
104
|
|
|
107
105
|
# Reject a non-Symbol kwargs key, and a +Kobako::Handle+ arriving
|
|
@@ -117,8 +115,6 @@ module Kobako
|
|
|
117
115
|
"keyword argument keys must be Symbols (got #{bad_keys.inspect})"
|
|
118
116
|
end
|
|
119
117
|
raise ArgumentError, forged_handle_message("keyword argument values") if kwargs.each_value.any?(Kobako::Handle)
|
|
120
|
-
|
|
121
|
-
kwargs
|
|
122
118
|
end
|
|
123
119
|
|
|
124
120
|
# Single source of truth for the forged-Handle reject message so the
|
|
@@ -67,7 +67,7 @@ module Kobako
|
|
|
67
67
|
raise Codec::InvalidType, "YieldResponse must carry at least one byte" if bytes.empty?
|
|
68
68
|
|
|
69
69
|
tag = bytes.getbyte(0) # : Integer
|
|
70
|
-
body = bytes.byteslice(1, bytes.bytesize - 1)
|
|
70
|
+
body = bytes.byteslice(1, bytes.bytesize - 1) # : String
|
|
71
71
|
|
|
72
72
|
reject_dead_tag!(tag)
|
|
73
73
|
new(tag: tag, value: Codec::Decoder.decode(body))
|
|
@@ -28,8 +28,8 @@ module Kobako
|
|
|
28
28
|
# dispatch completes; any later call to a stashed Yielder then raises
|
|
29
29
|
# +LocalJumpError+ — the observable shape of an escaped Yielder.
|
|
30
30
|
class Yielder
|
|
31
|
-
# +yield_to_guest+ is a +String → String+ callable (
|
|
32
|
-
# +Runtime
|
|
31
|
+
# +yield_to_guest+ is a +String → String+ callable (the ext's
|
|
32
|
+
# per-dispatch +Kobako::Runtime::GuestYielder+) that
|
|
33
33
|
# {#yield} invokes to re-enter the guest; +break_tag+ is the +catch+
|
|
34
34
|
# throw tag the Dispatcher matches against to unwind the Service on
|
|
35
35
|
# +tag 0x02+. +handler+ is the Sandbox's +Kobako::Catalog::Handles+,
|
data/lib/kobako/version.rb
CHANGED
data/release-please-config.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
|
|
3
3
|
"release-type": "ruby",
|
|
4
|
-
"last-release-sha": "
|
|
4
|
+
"last-release-sha": "98509af508988f708bf0d7a76a718bb0428a177e",
|
|
5
5
|
"packages": {
|
|
6
6
|
".": {
|
|
7
7
|
"component": "kobako",
|
|
@@ -103,13 +103,58 @@
|
|
|
103
103
|
"path": "/wasm/kobako-baker/README.md"
|
|
104
104
|
}
|
|
105
105
|
]
|
|
106
|
+
},
|
|
107
|
+
"crates/kobako-runtime": {
|
|
108
|
+
"component": "kobako-runtime",
|
|
109
|
+
"release-type": "rust",
|
|
110
|
+
"extra-files": [
|
|
111
|
+
{
|
|
112
|
+
"type": "toml",
|
|
113
|
+
"path": "/crates/Cargo.lock",
|
|
114
|
+
"jsonpath": "$.package[?(@.name=='kobako-runtime')].version"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"type": "toml",
|
|
118
|
+
"path": "/Cargo.lock",
|
|
119
|
+
"jsonpath": "$.package[?(@.name=='kobako-runtime')].version"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"type": "generic",
|
|
123
|
+
"path": "/crates/kobako-runtime/README.md"
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
"crates/kobako-wasmtime": {
|
|
128
|
+
"component": "kobako-wasmtime",
|
|
129
|
+
"release-type": "rust",
|
|
130
|
+
"extra-files": [
|
|
131
|
+
{
|
|
132
|
+
"type": "toml",
|
|
133
|
+
"path": "/crates/Cargo.lock",
|
|
134
|
+
"jsonpath": "$.package[?(@.name=='kobako-wasmtime')].version"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"type": "toml",
|
|
138
|
+
"path": "/Cargo.lock",
|
|
139
|
+
"jsonpath": "$.package[?(@.name=='kobako-wasmtime')].version"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"type": "toml",
|
|
143
|
+
"path": "/crates/kobako-wasmtime/Cargo.toml",
|
|
144
|
+
"jsonpath": "$.dependencies['kobako-runtime'].version"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"type": "generic",
|
|
148
|
+
"path": "/crates/kobako-wasmtime/README.md"
|
|
149
|
+
}
|
|
150
|
+
]
|
|
106
151
|
}
|
|
107
152
|
},
|
|
108
153
|
"plugins": [
|
|
109
154
|
{
|
|
110
155
|
"type": "linked-versions",
|
|
111
|
-
"groupName": "kobako
|
|
112
|
-
"components": ["kobako-core", "kobako-rs", "kobako-io", "kobako-json", "kobako-regexp", "kobako-baker"]
|
|
156
|
+
"groupName": "kobako crates",
|
|
157
|
+
"components": ["kobako-core", "kobako-rs", "kobako-io", "kobako-json", "kobako-regexp", "kobako-baker", "kobako-runtime", "kobako-wasmtime"]
|
|
113
158
|
}
|
|
114
159
|
],
|
|
115
160
|
"extra-files": [
|
|
@@ -8,6 +8,8 @@ module Kobako
|
|
|
8
8
|
EXT_SYMBOL: Integer
|
|
9
9
|
EXT_HANDLE: Integer
|
|
10
10
|
EXT_ERRENV: Integer
|
|
11
|
+
MAX_EXT_DEPTH: Integer
|
|
12
|
+
EXT_DEPTH_KEY: Symbol
|
|
11
13
|
|
|
12
14
|
def dump: (untyped value) -> String
|
|
13
15
|
def load: (String bytes) -> untyped
|
|
@@ -26,6 +28,7 @@ module Kobako
|
|
|
26
28
|
def unpack_handle: (String payload) -> Kobako::Handle
|
|
27
29
|
def pack_fault: (Kobako::Fault fault) -> String
|
|
28
30
|
def unpack_fault: (String payload) -> Kobako::Fault
|
|
31
|
+
def within_ext_frame: [T] (singleton(Kobako::Codec::Error) over_limit) { () -> T } -> T
|
|
29
32
|
end
|
|
30
33
|
end
|
|
31
34
|
end
|
data/sig/kobako/errors.rbs
CHANGED
|
@@ -17,7 +17,7 @@ module Kobako
|
|
|
17
17
|
class ModuleNotBuiltError < SetupError
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
module StructuredError : Error
|
|
21
21
|
attr_reader origin: String?
|
|
22
22
|
attr_reader klass: String?
|
|
23
23
|
attr_reader backtrace_lines: Array[String]?
|
|
@@ -32,22 +32,15 @@ module Kobako
|
|
|
32
32
|
) -> void
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
class
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
attr_reader backtrace_lines: Array[String]?
|
|
39
|
-
attr_reader details: untyped
|
|
35
|
+
class SandboxError < Error
|
|
36
|
+
include StructuredError
|
|
37
|
+
end
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
?origin: String?,
|
|
44
|
-
?klass: String?,
|
|
45
|
-
?backtrace_lines: Array[String]?,
|
|
46
|
-
?details: untyped
|
|
47
|
-
) -> void
|
|
39
|
+
class ServiceError < Error
|
|
40
|
+
include StructuredError
|
|
48
41
|
end
|
|
49
42
|
|
|
50
|
-
class
|
|
43
|
+
class HandleExhaustedError < SandboxError
|
|
51
44
|
end
|
|
52
45
|
|
|
53
46
|
class BytecodeError < SandboxError
|
data/sig/kobako/runtime.rbs
CHANGED
|
@@ -10,14 +10,19 @@ module Kobako
|
|
|
10
10
|
Integer? stderr_limit_bytes
|
|
11
11
|
) -> Runtime
|
|
12
12
|
|
|
13
|
-
def on_dispatch=: (^(String) -> String dispatch_proc) -> void
|
|
14
|
-
|
|
15
|
-
def yield_to_active_invocation: (String args_bytes) -> String
|
|
13
|
+
def on_dispatch=: (^(String, Kobako::Transport::_GuestYielder) -> String dispatch_proc) -> void
|
|
16
14
|
|
|
17
15
|
def eval: (String preamble, String source, String snippets) -> Kobako::Snapshot
|
|
18
16
|
|
|
19
17
|
def run: (String preamble, String snippets, String envelope) -> Kobako::Snapshot
|
|
20
18
|
|
|
21
19
|
def usage: () -> [Float, Integer]
|
|
20
|
+
|
|
21
|
+
# Frame-scoped guest re-entry handle the ext hands the dispatch Proc as
|
|
22
|
+
# its second argument; stands in as the +String -> String+ callable the
|
|
23
|
+
# host +Transport::Yielder+ invokes for a block yield.
|
|
24
|
+
class GuestYielder
|
|
25
|
+
def call: (String args_bytes) -> String
|
|
26
|
+
end
|
|
22
27
|
end
|
|
23
28
|
end
|
data/sig/kobako/sandbox.rbs
CHANGED
|
@@ -8,8 +8,8 @@ module Kobako
|
|
|
8
8
|
# Forwarded to @options via Forwardable#def_delegators.
|
|
9
9
|
def timeout: () -> Float?
|
|
10
10
|
def memory_limit: () -> Integer?
|
|
11
|
-
def stdout_limit: () -> Integer
|
|
12
|
-
def stderr_limit: () -> Integer
|
|
11
|
+
def stdout_limit: () -> Integer?
|
|
12
|
+
def stderr_limit: () -> Integer?
|
|
13
13
|
|
|
14
14
|
def initialize: (
|
|
15
15
|
?wasm_path: String?,
|
|
@@ -6,8 +6,8 @@ module Kobako
|
|
|
6
6
|
|
|
7
7
|
attr_reader timeout: Float?
|
|
8
8
|
attr_reader memory_limit: Integer?
|
|
9
|
-
attr_reader stdout_limit: Integer
|
|
10
|
-
attr_reader stderr_limit: Integer
|
|
9
|
+
attr_reader stdout_limit: Integer?
|
|
10
|
+
attr_reader stderr_limit: Integer?
|
|
11
11
|
|
|
12
12
|
def self.new: (
|
|
13
13
|
?timeout: (Float | Integer)?,
|
|
@@ -28,5 +28,7 @@ module Kobako
|
|
|
28
28
|
def normalize_timeout: ((Float | Integer)? timeout) -> Float?
|
|
29
29
|
|
|
30
30
|
def normalize_memory_limit: (Integer? memory_limit) -> Integer?
|
|
31
|
+
|
|
32
|
+
def normalize_output_limit: (Integer? limit, String name) -> Integer?
|
|
31
33
|
end
|
|
32
34
|
end
|
data/sig/kobako/snapshot.rbs
CHANGED
|
@@ -5,11 +5,8 @@ module Kobako
|
|
|
5
5
|
def stdout_truncated: () -> bool
|
|
6
6
|
def stderr_bytes: () -> String
|
|
7
7
|
def stderr_truncated: () -> bool
|
|
8
|
-
def wall_time: () -> Float
|
|
9
|
-
def memory_peak: () -> Integer
|
|
10
8
|
|
|
11
9
|
def stdout: () -> Kobako::Capture
|
|
12
10
|
def stderr: () -> Kobako::Capture
|
|
13
|
-
def usage: () -> Kobako::Usage
|
|
14
11
|
end
|
|
15
12
|
end
|
|
@@ -12,7 +12,7 @@ module Kobako
|
|
|
12
12
|
|
|
13
13
|
CALLABLE_ALLOW: Array[Symbol]
|
|
14
14
|
|
|
15
|
-
def self?.dispatch: (String request_bytes, Kobako::Catalog::Namespaces namespaces, Kobako::Catalog::Handles handler,
|
|
15
|
+
def self?.dispatch: (String request_bytes, Kobako::Catalog::Namespaces namespaces, Kobako::Catalog::Handles handler, Kobako::Transport::_GuestYielder yield_to_guest) -> String
|
|
16
16
|
|
|
17
17
|
def self?.resolve_call_args: (Kobako::Transport::Request request, Kobako::Catalog::Handles handler) -> [Array[untyped], Hash[Symbol, untyped]]
|
|
18
18
|
|
|
@@ -17,9 +17,9 @@ module Kobako
|
|
|
17
17
|
|
|
18
18
|
def normalize_entrypoint: (Symbol | String target) -> Symbol
|
|
19
19
|
|
|
20
|
-
def validate_args!: (Array[untyped] args) ->
|
|
20
|
+
def validate_args!: (Array[untyped] args) -> void
|
|
21
21
|
|
|
22
|
-
def validate_kwargs!: (Hash[untyped, untyped] kwargs) ->
|
|
22
|
+
def validate_kwargs!: (Hash[untyped, untyped] kwargs) -> void
|
|
23
23
|
|
|
24
24
|
def forged_handle_message: (String slot) -> String
|
|
25
25
|
end
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
module Kobako
|
|
2
2
|
module Transport
|
|
3
3
|
class Yielder
|
|
4
|
-
@yield_to_guest:
|
|
4
|
+
@yield_to_guest: Kobako::Transport::_GuestYielder
|
|
5
5
|
@break_tag: Symbol
|
|
6
6
|
@handler: Kobako::Catalog::Handles
|
|
7
7
|
@active: bool
|
|
8
8
|
|
|
9
|
-
def initialize: (
|
|
9
|
+
def initialize: (Kobako::Transport::_GuestYielder yield_to_guest, Symbol break_tag, Kobako::Catalog::Handles handler) -> void
|
|
10
10
|
|
|
11
11
|
def yield: (*untyped args) -> untyped
|
|
12
12
|
|
data/sig/kobako/transport.rbs
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
module Kobako
|
|
2
2
|
module Transport
|
|
3
|
+
# The guest re-entry callable a dispatch hands to a Yielder: invoked
|
|
4
|
+
# with the encoded yield args, it returns the encoded YieldResponse.
|
|
5
|
+
# The ext's Kobako::Runtime::GuestYielder is the production conformer;
|
|
6
|
+
# modelled structurally so the Transport layer needs no upward
|
|
7
|
+
# dependency on Runtime.
|
|
8
|
+
interface _GuestYielder
|
|
9
|
+
def call: (String) -> String
|
|
10
|
+
end
|
|
3
11
|
end
|
|
4
12
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kobako
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.12.
|
|
4
|
+
version: 0.12.2
|
|
5
5
|
platform: x64-mingw-ucrt
|
|
6
6
|
authors:
|
|
7
7
|
- Aotokitsuruya
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-07-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: msgpack
|
|
@@ -38,6 +38,10 @@ files:
|
|
|
38
38
|
- LICENSE
|
|
39
39
|
- README.md
|
|
40
40
|
- SECURITY.md
|
|
41
|
+
- crates/kobako-runtime/CHANGELOG.md
|
|
42
|
+
- crates/kobako-runtime/README.md
|
|
43
|
+
- crates/kobako-wasmtime/CHANGELOG.md
|
|
44
|
+
- crates/kobako-wasmtime/README.md
|
|
41
45
|
- data/kobako.wasm
|
|
42
46
|
- lib/kobako.rb
|
|
43
47
|
- lib/kobako/3.3/kobako.so
|