kobako 0.12.2-aarch64-linux → 0.13.0-aarch64-linux
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 +2 -0
- data/crates/kobako-runtime/CHANGELOG.md +8 -0
- data/crates/kobako-runtime/README.md +1 -1
- data/crates/kobako-wasmtime/CHANGELOG.md +8 -0
- data/crates/kobako-wasmtime/README.md +1 -1
- 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/codec.rb +1 -1
- data/lib/kobako/sandbox.rb +58 -28
- data/lib/kobako/sandbox_options.rb +51 -9
- data/lib/kobako/version.rb +1 -1
- data/lib/kobako.rb +0 -1
- data/release-please-config.json +31 -1
- data/sig/kobako/runtime.rbs +8 -3
- data/sig/kobako/sandbox.rbs +9 -5
- data/sig/kobako/sandbox_options.rbs +11 -2
- metadata +2 -4
- data/lib/kobako/snapshot.rb +0 -32
- data/sig/kobako/snapshot.rbs +0 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c0a1b4ccd9f4e1debe32912b925847390d00fbf09e798b41eb54ac0756ef4ab3
|
|
4
|
+
data.tar.gz: 4819002a95e4407ebacb91d1ae77cd8a7c52d80a1eb0511dcc01ac405d6b7459
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 902954ca6a47611ab670ea52dbe5edc2268428128ffaac0dd9d55e309af6d5b4a70fc47d07eed4f31261bdcdc7158cbdd91fbfad32d56098c8a2c84077db2855
|
|
7
|
+
data.tar.gz: 53174e7d4e921b558bca17b3683c0865954ff73219a0c07d86d11e18e6e812506aece5d5dc0626ce021fe9342a63d8d3b5ab612f513d7349e939e0e6e08ed063
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{".":"0.
|
|
1
|
+
{".":"0.13.0","wasm/kobako-core":"0.7.0","wasm/kobako":"0.7.0","wasm/kobako-io":"0.7.0","wasm/kobako-json":"0.7.0","wasm/kobako-regexp":"0.7.0","wasm/kobako-baker":"0.7.0","crates/kobako-codec":"0.7.0","crates/kobako-runtime":"0.7.0","crates/kobako-wasmtime":"0.7.0"}
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.13.0](https://github.com/elct9620/kobako/compare/v0.12.2...v0.13.0) (2026-07-03)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **crates:** build the requested isolation profile into the WASI context ([63c25d8](https://github.com/elct9620/kobako/commit/63c25d835d4d03010c1658217cee412318e6b5d8))
|
|
9
|
+
* enforce the isolation-profile floor at Sandbox construction ([73f0dfe](https://github.com/elct9620/kobako/commit/73f0dfe34a144045a559a28caec31468351de64a))
|
|
10
|
+
* forward the Sandbox profile request through the ext to the driver ([f47f906](https://github.com/elct9620/kobako/commit/f47f9063aa56462be023f5c76cbc73db6e4315ad))
|
|
11
|
+
* keep guest output readable after a trap ([464454c](https://github.com/elct9620/kobako/commit/464454cd774db96ad72b3787007f2ce015673587))
|
|
12
|
+
* **runtime:** runtimes declare their isolation profile ([f89717a](https://github.com/elct9620/kobako/commit/f89717a6bc9809f0de0df78f97da33a49a1474ac))
|
|
13
|
+
|
|
3
14
|
## [0.12.2](https://github.com/elct9620/kobako/compare/v0.12.1...v0.12.2) (2026-07-02)
|
|
4
15
|
|
|
5
16
|
|
data/README.md
CHANGED
|
@@ -154,6 +154,8 @@ sandbox = Kobako::Sandbox.new(
|
|
|
154
154
|
|
|
155
155
|
`memory_limit` covers the per-invocation `memory.grow` delta from the entry baseline, so a Sandbox reused across invocations does not silently accumulate against a global budget.
|
|
156
156
|
|
|
157
|
+
A fifth option, `profile:`, requests the Sandbox's isolation posture on the `:permissive` < `:hermetic` ladder (default `:hermetic`). `:hermetic` denies the guest ambient time and entropy; `:permissive` lets the guest's `wasi:clocks` / `wasi:random` read live host sources — an explicit trade of reproducibility, with filesystem, environment, and network still unreachable. The request is also a floor: construction fails with `Kobako::SetupError` on a runtime that declares a weaker posture than requested. See [`docs/security-model.md`](docs/security-model.md) § Isolation profiles.
|
|
158
|
+
|
|
157
159
|
### Invocation Lifecycle
|
|
158
160
|
|
|
159
161
|
One Sandbox serves many invocations. Service bindings and preloaded snippets persist across calls; capability state (Handles, stdout, stderr, memory delta) resets between them.
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.0](https://github.com/elct9620/kobako/compare/kobako-runtime-v0.6.1...kobako-runtime-v0.7.0) (2026-07-03)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **crates:** build the requested isolation profile into the WASI context ([63c25d8](https://github.com/elct9620/kobako/commit/63c25d835d4d03010c1658217cee412318e6b5d8))
|
|
9
|
+
* **runtime:** runtimes declare their isolation profile ([f89717a](https://github.com/elct9620/kobako/commit/f89717a6bc9809f0de0df78f97da33a49a1474ac))
|
|
10
|
+
|
|
3
11
|
## [0.6.1](https://github.com/elct9620/kobako/compare/kobako-runtime-v0.6.0...kobako-runtime-v0.6.1) (2026-07-02)
|
|
4
12
|
|
|
5
13
|
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.0](https://github.com/elct9620/kobako/compare/kobako-wasmtime-v0.6.1...kobako-wasmtime-v0.7.0) (2026-07-03)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **crates:** build the requested isolation profile into the WASI context ([63c25d8](https://github.com/elct9620/kobako/commit/63c25d835d4d03010c1658217cee412318e6b5d8))
|
|
9
|
+
* **runtime:** runtimes declare their isolation profile ([f89717a](https://github.com/elct9620/kobako/commit/f89717a6bc9809f0de0df78f97da33a49a1474ac))
|
|
10
|
+
|
|
3
11
|
## [0.6.1](https://github.com/elct9620/kobako/compare/kobako-wasmtime-v0.6.0...kobako-wasmtime-v0.6.1) (2026-07-02)
|
|
4
12
|
|
|
5
13
|
|
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
|
data/lib/kobako/codec.rb
CHANGED
|
@@ -22,7 +22,7 @@ module Kobako
|
|
|
22
22
|
# {Decoder} are thin wrappers that register the three kobako-specific
|
|
23
23
|
# ext types (0x00 Symbol, 0x01 Capability Handle, 0x02 Exception
|
|
24
24
|
# envelope) on a single +MessagePack::Factory+ instance. The Rust side
|
|
25
|
-
# mirrors this layer as the +codec+ module in the +kobako-
|
|
25
|
+
# mirrors this layer as the +codec+ module in the +kobako-codec+ crate;
|
|
26
26
|
# the ext-code constants live as module-private values on {Factory}
|
|
27
27
|
# alongside +codec::EXT_SYMBOL+ / +codec::EXT_HANDLE+ /
|
|
28
28
|
# +codec::EXT_ERRENV+ on that side.
|
data/lib/kobako/sandbox.rb
CHANGED
|
@@ -38,14 +38,16 @@ module Kobako
|
|
|
38
38
|
|
|
39
39
|
attr_reader :wasm_path, :options
|
|
40
40
|
|
|
41
|
-
# Per-
|
|
41
|
+
# Per-option accessors forward to the immutable +SandboxOptions+ Value
|
|
42
42
|
# Object so the Host App still reads them off Sandbox directly.
|
|
43
|
-
def_delegators :@options, :timeout, :memory_limit, :stdout_limit, :stderr_limit
|
|
43
|
+
def_delegators :@options, :timeout, :memory_limit, :stdout_limit, :stderr_limit, :profile
|
|
44
44
|
|
|
45
45
|
# Returns the bytes the guest wrote to stdout during the most recent
|
|
46
46
|
# invocation as a UTF-8 String, clipped at +stdout_limit+. Empty before
|
|
47
47
|
# any invocation; the byte content never contains a truncation sentinel,
|
|
48
|
-
# so use +#stdout_truncated?+ to observe overflow.
|
|
48
|
+
# so use +#stdout_truncated?+ to observe overflow. Populated on every
|
|
49
|
+
# outcome — including a rescued +TrapError+, after which it holds the
|
|
50
|
+
# bytes written before the trap fired — mirroring +#usage+.
|
|
49
51
|
def stdout
|
|
50
52
|
@stdout_capture.bytes
|
|
51
53
|
end
|
|
@@ -83,25 +85,24 @@ module Kobako
|
|
|
83
85
|
# Build a fresh Sandbox.
|
|
84
86
|
#
|
|
85
87
|
# +wasm_path+ is the absolute path to the Guest Binary; defaults to the
|
|
86
|
-
# gem-bundled +data/kobako.wasm+.
|
|
87
|
-
# +stderr_limit+, +timeout+, +memory_limit+)
|
|
88
|
-
# +
|
|
88
|
+
# gem-bundled +data/kobako.wasm+. Every other keyword — the four caps
|
|
89
|
+
# (+stdout_limit+, +stderr_limit+, +timeout+, +memory_limit+) and the
|
|
90
|
+
# requested isolation profile (+profile+) — is forwarded verbatim to
|
|
91
|
+
# +Kobako::SandboxOptions+, which owns the DEFAULT fallbacks and
|
|
89
92
|
# normalisation. The constructed +SandboxOptions+ is exposed as
|
|
90
|
-
# +#options+ and
|
|
91
|
-
# +Forwardable+ delegation.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
# +#options+ and every option remains readable directly on Sandbox via
|
|
94
|
+
# +Forwardable+ delegation. The runtime builds the requested profile —
|
|
95
|
+
# +:hermetic+ (the default) denies the guest ambient time and entropy,
|
|
96
|
+
# +:permissive+ leaves them live — and construction refuses a runtime
|
|
97
|
+
# whose declared profile falls below the request, raising
|
|
98
|
+
# +Kobako::SetupError+ before any invocation entry point runs.
|
|
99
|
+
def initialize(wasm_path: nil, **)
|
|
97
100
|
@wasm_path = wasm_path || Kobako::Runtime.default_path
|
|
98
|
-
@options = SandboxOptions.new(
|
|
99
|
-
stderr_limit: stderr_limit)
|
|
101
|
+
@options = SandboxOptions.new(**)
|
|
100
102
|
@handler = Catalog::Handles.new
|
|
101
103
|
@services = Kobako::Catalog::Namespaces.new(handler: @handler)
|
|
102
104
|
@snippets = Catalog::Snippets.new
|
|
103
|
-
@runtime =
|
|
104
|
-
@options.stdout_limit, @options.stderr_limit)
|
|
105
|
+
@runtime = build_runtime!
|
|
105
106
|
install_dispatch_proc!
|
|
106
107
|
reset_invocation_state!
|
|
107
108
|
end
|
|
@@ -209,6 +210,17 @@ module Kobako
|
|
|
209
210
|
|
|
210
211
|
private
|
|
211
212
|
|
|
213
|
+
# Construct the +Runtime+ with the requested isolation profile and
|
|
214
|
+
# refuse one whose declared posture falls below the request —
|
|
215
|
+
# +SandboxOptions#enforce_floor!+ owns the ladder comparison, so a
|
|
216
|
+
# runtime that cannot honor the request never runs guest code.
|
|
217
|
+
def build_runtime!
|
|
218
|
+
runtime = Kobako::Runtime.from_path(@wasm_path, @options.timeout, @options.memory_limit,
|
|
219
|
+
@options.stdout_limit, @options.stderr_limit, profile)
|
|
220
|
+
@options.enforce_floor!(runtime.profile)
|
|
221
|
+
runtime
|
|
222
|
+
end
|
|
223
|
+
|
|
212
224
|
# Configure the +Runtime+'s host↔guest dispatch wiring. Registers a
|
|
213
225
|
# dispatch +Proc+ that routes guest→host calls through the stateless
|
|
214
226
|
# +Transport::Dispatcher+, capturing +@services+ / +@handler+ in the
|
|
@@ -242,8 +254,8 @@ module Kobako
|
|
|
242
254
|
# +TimeoutError+ / +MemoryLimitError+), +Kobako::SandboxError+,
|
|
243
255
|
# and +Kobako::ServiceError+. +Runtime#usage+ is the single source for
|
|
244
256
|
# both paths: the figures are stashed in the ext on every outcome, so
|
|
245
|
-
#
|
|
246
|
-
#
|
|
257
|
+
# the readout here also covers the trap path, where +Runtime#eval+ /
|
|
258
|
+
# +#run+ raise instead of returning outcome bytes.
|
|
247
259
|
#
|
|
248
260
|
# The ext returns a positional 2-tuple +[wall_time, memory_peak]+
|
|
249
261
|
# whose order matches the +Kobako::Usage+ field order; the
|
|
@@ -269,33 +281,51 @@ module Kobako
|
|
|
269
281
|
end
|
|
270
282
|
end
|
|
271
283
|
|
|
284
|
+
# Read the per-last-invocation output captures from the ext and wrap
|
|
285
|
+
# them as +Kobako::Capture+ value objects. Runs in the +invoke!+
|
|
286
|
+
# +ensure+ block next to {#read_usage!} for the same reason: the ext
|
|
287
|
+
# stashes the captures on every outcome, so the readout also covers
|
|
288
|
+
# the trap path, where +Runtime#eval+ / +#run+ raise instead of
|
|
289
|
+
# returning outcome bytes — +#stdout+ / +#stderr+ keep the guest's
|
|
290
|
+
# partial output readable after a rescue.
|
|
291
|
+
#
|
|
292
|
+
# The ext returns a positional 4-tuple
|
|
293
|
+
# +[stdout_bytes, stdout_truncated, stderr_bytes, stderr_truncated]+;
|
|
294
|
+
# the destructure-then-kwargs handoff below is the explicit
|
|
295
|
+
# positional→keyword conversion point.
|
|
296
|
+
def read_captures!
|
|
297
|
+
stdout_bytes, stdout_truncated, stderr_bytes, stderr_truncated = @runtime.captures
|
|
298
|
+
@stdout_capture = Capture.new(bytes: stdout_bytes, truncated: stdout_truncated)
|
|
299
|
+
@stderr_capture = Capture.new(bytes: stderr_bytes, truncated: stderr_truncated)
|
|
300
|
+
end
|
|
301
|
+
|
|
272
302
|
# Shared prologue / epilogue + trap-class translator for both
|
|
273
303
|
# invocation verbs. +verb+ is +:eval+ or +:run+; it tags the
|
|
274
304
|
# TrapError message so the failing export is identifiable.
|
|
275
305
|
#
|
|
276
|
-
# The yielded block must return
|
|
277
|
-
# value of +Runtime#eval+ / +#run
|
|
278
|
-
#
|
|
279
|
-
# +
|
|
280
|
-
#
|
|
306
|
+
# The yielded block must return the invocation's raw outcome bytes —
|
|
307
|
+
# i.e. the value of +Runtime#eval+ / +#run+ — which the success path
|
|
308
|
+
# feeds to +Outcome.decode+. Captures and usage are populated by the
|
|
309
|
+
# +ensure+ readouts ({#read_usage!} / {#read_captures!}) on every
|
|
310
|
+
# outcome, so +#stdout+ / +#stderr+ / +#usage+ stay readable after a
|
|
311
|
+
# rescued trap.
|
|
281
312
|
# The rescue chain is the single trap-translation boundary —
|
|
282
313
|
# configured-cap paths surface as named TrapError subclasses
|
|
283
314
|
# (+TimeoutError+ / +MemoryLimitError+); everything else surfaces as
|
|
284
315
|
# the base +TrapError+.
|
|
285
316
|
def invoke!(verb)
|
|
286
317
|
begin_invocation!
|
|
287
|
-
|
|
288
|
-
@stdout_capture = snapshot.stdout
|
|
289
|
-
@stderr_capture = snapshot.stderr
|
|
318
|
+
return_bytes = yield
|
|
290
319
|
# A Capability Handle in the result is decoded as a Kobako::Handle
|
|
291
320
|
# token; restore it to the host object the guest referenced before
|
|
292
321
|
# handing the value to the Host App. @handler still holds this
|
|
293
322
|
# invocation's table — reset only happens at the next #begin_invocation!.
|
|
294
|
-
Codec::HandleWalk.deep_restore(Outcome.decode(
|
|
323
|
+
Codec::HandleWalk.deep_restore(Outcome.decode(return_bytes), @handler)
|
|
295
324
|
rescue Kobako::TrapError => e
|
|
296
325
|
raise trap_class_for(e), "Sandbox##{verb} failed: #{e.message}"
|
|
297
326
|
ensure
|
|
298
327
|
read_usage!
|
|
328
|
+
read_captures!
|
|
299
329
|
end
|
|
300
330
|
end
|
|
301
331
|
end
|
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "errors"
|
|
4
|
+
|
|
3
5
|
module Kobako
|
|
4
6
|
# Kobako::SandboxOptions — immutable Value Object holding the four
|
|
5
|
-
# per-Sandbox configuration caps
|
|
6
|
-
# Data.define(...)+ subclass form (the
|
|
7
|
-
# +lib/kobako/outcome/panic.rb+).
|
|
7
|
+
# per-Sandbox configuration caps and the requested isolation profile.
|
|
8
|
+
# Built on the +class X < Data.define(...)+ subclass form (the
|
|
9
|
+
# Steep-friendly shape — see +lib/kobako/outcome/panic.rb+).
|
|
8
10
|
#
|
|
9
|
-
# The +initialize+ normalises every
|
|
11
|
+
# The +initialize+ normalises every option before delegating to Data's
|
|
10
12
|
# +super+: +timeout+ to Float seconds, +memory_limit+ / +stdout_limit+ /
|
|
11
13
|
# +stderr_limit+ to positive Integer bytes. Each cap is +nil+-disablable
|
|
12
14
|
# (an absent argument takes its DEFAULT; an explicit +nil+ leaves the
|
|
13
|
-
# bound off), so all four behave uniformly.
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
|
|
15
|
+
# bound off), so all four behave uniformly. +profile+ is the one
|
|
16
|
+
# non-cap: a Symbol on the PROFILES ladder naming the posture the
|
|
17
|
+
# runtime builds, which is also the weakest the Host App accepts —
|
|
18
|
+
# +nil+ is rejected because the weakest posture is requested as an
|
|
19
|
+
# explicit +:permissive+. Anything that survives +SandboxOptions.new+
|
|
20
|
+
# is a wire-ready bundle the +Kobako::Runtime+ constructor consumes
|
|
21
|
+
# as-is. The options also own the ladder comparison
|
|
22
|
+
# (+#enforce_floor!+) that +Kobako::Sandbox+ delegates its
|
|
23
|
+
# construction floor check to.
|
|
24
|
+
class SandboxOptions < Data.define(:timeout, :memory_limit, :stdout_limit, :stderr_limit, :profile)
|
|
17
25
|
# Default wall-clock timeout for a single invocation: 60 seconds.
|
|
18
26
|
DEFAULT_TIMEOUT_SECONDS = 60.0
|
|
19
27
|
|
|
@@ -25,17 +33,41 @@ module Kobako
|
|
|
25
33
|
# Default per-channel capture ceiling: 1 MiB.
|
|
26
34
|
DEFAULT_OUTPUT_LIMIT = 1 << 20
|
|
27
35
|
|
|
36
|
+
# The isolation ladder, weakest first — index order is rank order,
|
|
37
|
+
# so a floor check is an index comparison.
|
|
38
|
+
PROFILES = %i[permissive hermetic].freeze
|
|
39
|
+
|
|
40
|
+
# Default isolation profile: the strictest rung — opting down to
|
|
41
|
+
# +:permissive+ is the Host App's explicit trade.
|
|
42
|
+
DEFAULT_PROFILE = :hermetic
|
|
43
|
+
|
|
28
44
|
def initialize(timeout: DEFAULT_TIMEOUT_SECONDS,
|
|
29
45
|
memory_limit: DEFAULT_MEMORY_LIMIT,
|
|
30
46
|
stdout_limit: DEFAULT_OUTPUT_LIMIT,
|
|
31
|
-
stderr_limit: DEFAULT_OUTPUT_LIMIT
|
|
47
|
+
stderr_limit: DEFAULT_OUTPUT_LIMIT,
|
|
48
|
+
profile: DEFAULT_PROFILE)
|
|
32
49
|
timeout = normalize_timeout(timeout)
|
|
33
50
|
memory_limit = normalize_memory_limit(memory_limit)
|
|
34
51
|
stdout_limit = normalize_output_limit(stdout_limit, "stdout_limit")
|
|
35
52
|
stderr_limit = normalize_output_limit(stderr_limit, "stderr_limit")
|
|
53
|
+
profile = normalize_profile(profile)
|
|
36
54
|
super
|
|
37
55
|
end
|
|
38
56
|
|
|
57
|
+
# Enforce the requested +profile+ as the floor against +declared+ —
|
|
58
|
+
# the posture a runtime reports having built — so a runtime that
|
|
59
|
+
# cannot honor the request fails construction with
|
|
60
|
+
# +Kobako::SetupError+ instead of weakening the posture silently.
|
|
61
|
+
# Both fallbacks fail closed: a declaration off the PROFILES ladder
|
|
62
|
+
# ranks below every request, and a request off the ladder
|
|
63
|
+
# (unreachable past +initialize+) refuses every declaration.
|
|
64
|
+
def enforce_floor!(declared)
|
|
65
|
+
return if (PROFILES.index(declared) || -1) >= (PROFILES.index(profile) || PROFILES.size)
|
|
66
|
+
|
|
67
|
+
raise Kobako::SetupError, "runtime declares isolation profile #{declared.inspect}, " \
|
|
68
|
+
"below the requested floor #{profile.inspect}"
|
|
69
|
+
end
|
|
70
|
+
|
|
39
71
|
private
|
|
40
72
|
|
|
41
73
|
# Coerce +timeout+ into the Float seconds the ext expects, or +nil+
|
|
@@ -78,5 +110,15 @@ module Kobako
|
|
|
78
110
|
|
|
79
111
|
limit
|
|
80
112
|
end
|
|
113
|
+
|
|
114
|
+
# Validate +profile+ against the PROFILES ladder. Unlike the caps
|
|
115
|
+
# there is no +nil+ form: the weakest posture is requested as an
|
|
116
|
+
# explicit +:permissive+, so anything off the ladder — +nil+
|
|
117
|
+
# included — is rejected.
|
|
118
|
+
def normalize_profile(profile)
|
|
119
|
+
return profile if PROFILES.include?(profile)
|
|
120
|
+
|
|
121
|
+
raise ArgumentError, "profile must be one of #{PROFILES.map(&:inspect).join(", ")}, got #{profile.inspect}"
|
|
122
|
+
end
|
|
81
123
|
end
|
|
82
124
|
end
|
data/lib/kobako/version.rb
CHANGED
data/lib/kobako.rb
CHANGED
data/release-please-config.json
CHANGED
|
@@ -18,6 +18,11 @@
|
|
|
18
18
|
"path": "/wasm/Cargo.lock",
|
|
19
19
|
"jsonpath": "$.package[?(@.name=='kobako-core')].version"
|
|
20
20
|
},
|
|
21
|
+
{
|
|
22
|
+
"type": "toml",
|
|
23
|
+
"path": "/wasm/kobako-core/Cargo.toml",
|
|
24
|
+
"jsonpath": "$.dependencies['kobako-codec'].version"
|
|
25
|
+
},
|
|
21
26
|
{
|
|
22
27
|
"type": "generic",
|
|
23
28
|
"path": "/wasm/kobako-core/README.md"
|
|
@@ -38,6 +43,11 @@
|
|
|
38
43
|
"path": "/wasm/kobako/Cargo.toml",
|
|
39
44
|
"jsonpath": "$.dependencies['kobako-core'].version"
|
|
40
45
|
},
|
|
46
|
+
{
|
|
47
|
+
"type": "toml",
|
|
48
|
+
"path": "/wasm/kobako/Cargo.toml",
|
|
49
|
+
"jsonpath": "$.dependencies['kobako-codec'].version"
|
|
50
|
+
},
|
|
41
51
|
{
|
|
42
52
|
"type": "generic",
|
|
43
53
|
"path": "/wasm/kobako/README.md"
|
|
@@ -104,6 +114,26 @@
|
|
|
104
114
|
}
|
|
105
115
|
]
|
|
106
116
|
},
|
|
117
|
+
"crates/kobako-codec": {
|
|
118
|
+
"component": "kobako-codec",
|
|
119
|
+
"release-type": "rust",
|
|
120
|
+
"extra-files": [
|
|
121
|
+
{
|
|
122
|
+
"type": "toml",
|
|
123
|
+
"path": "/crates/Cargo.lock",
|
|
124
|
+
"jsonpath": "$.package[?(@.name=='kobako-codec')].version"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"type": "toml",
|
|
128
|
+
"path": "/wasm/Cargo.lock",
|
|
129
|
+
"jsonpath": "$.package[?(@.name=='kobako-codec')].version"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"type": "generic",
|
|
133
|
+
"path": "/crates/kobako-codec/README.md"
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
},
|
|
107
137
|
"crates/kobako-runtime": {
|
|
108
138
|
"component": "kobako-runtime",
|
|
109
139
|
"release-type": "rust",
|
|
@@ -154,7 +184,7 @@
|
|
|
154
184
|
{
|
|
155
185
|
"type": "linked-versions",
|
|
156
186
|
"groupName": "kobako crates",
|
|
157
|
-
"components": ["kobako-core", "kobako-rs", "kobako-io", "kobako-json", "kobako-regexp", "kobako-baker", "kobako-runtime", "kobako-wasmtime"]
|
|
187
|
+
"components": ["kobako-codec", "kobako-core", "kobako-rs", "kobako-io", "kobako-json", "kobako-regexp", "kobako-baker", "kobako-runtime", "kobako-wasmtime"]
|
|
158
188
|
}
|
|
159
189
|
],
|
|
160
190
|
"extra-files": [
|
data/sig/kobako/runtime.rbs
CHANGED
|
@@ -7,17 +7,22 @@ module Kobako
|
|
|
7
7
|
(Float | Integer)? timeout_seconds,
|
|
8
8
|
Integer? memory_limit,
|
|
9
9
|
Integer? stdout_limit_bytes,
|
|
10
|
-
Integer? stderr_limit_bytes
|
|
10
|
+
Integer? stderr_limit_bytes,
|
|
11
|
+
Symbol profile
|
|
11
12
|
) -> Runtime
|
|
12
13
|
|
|
13
14
|
def on_dispatch=: (^(String, Kobako::Transport::_GuestYielder) -> String dispatch_proc) -> void
|
|
14
15
|
|
|
15
|
-
def eval: (String preamble, String source, String snippets) ->
|
|
16
|
+
def eval: (String preamble, String source, String snippets) -> String
|
|
16
17
|
|
|
17
|
-
def run: (String preamble, String snippets, String envelope) ->
|
|
18
|
+
def run: (String preamble, String snippets, String envelope) -> String
|
|
18
19
|
|
|
19
20
|
def usage: () -> [Float, Integer]
|
|
20
21
|
|
|
22
|
+
def captures: () -> [String, bool, String, bool]
|
|
23
|
+
|
|
24
|
+
def profile: () -> Symbol
|
|
25
|
+
|
|
21
26
|
# Frame-scoped guest re-entry handle the ext hands the dispatch Proc as
|
|
22
27
|
# its second argument; stands in as the +String -> String+ callable the
|
|
23
28
|
# host +Transport::Yielder+ invokes for a block yield.
|
data/sig/kobako/sandbox.rbs
CHANGED
|
@@ -10,13 +10,13 @@ module Kobako
|
|
|
10
10
|
def memory_limit: () -> Integer?
|
|
11
11
|
def stdout_limit: () -> Integer?
|
|
12
12
|
def stderr_limit: () -> Integer?
|
|
13
|
+
def profile: () -> Symbol
|
|
13
14
|
|
|
15
|
+
# Every keyword beyond wasm_path forwards verbatim to
|
|
16
|
+
# SandboxOptions.new (the four caps + the profile floor).
|
|
14
17
|
def initialize: (
|
|
15
18
|
?wasm_path: String?,
|
|
16
|
-
|
|
17
|
-
?stderr_limit: Integer?,
|
|
18
|
-
?timeout: (Float | Integer)?,
|
|
19
|
-
?memory_limit: Integer?
|
|
19
|
+
**untyped options
|
|
20
20
|
) -> void
|
|
21
21
|
|
|
22
22
|
def stdout: () -> String
|
|
@@ -42,14 +42,18 @@ module Kobako
|
|
|
42
42
|
|
|
43
43
|
private
|
|
44
44
|
|
|
45
|
+
def build_runtime!: () -> Kobako::Runtime
|
|
46
|
+
|
|
45
47
|
def install_dispatch_proc!: () -> void
|
|
46
48
|
|
|
47
49
|
def begin_invocation!: () -> void
|
|
48
50
|
|
|
49
51
|
def read_usage!: () -> void
|
|
50
52
|
|
|
53
|
+
def read_captures!: () -> void
|
|
54
|
+
|
|
51
55
|
def trap_class_for: (Kobako::TrapError err) -> singleton(Kobako::TrapError)
|
|
52
56
|
|
|
53
|
-
def invoke!: (Symbol verb) { () ->
|
|
57
|
+
def invoke!: (Symbol verb) { () -> String } -> untyped
|
|
54
58
|
end
|
|
55
59
|
end
|
|
@@ -3,26 +3,33 @@ module Kobako
|
|
|
3
3
|
DEFAULT_TIMEOUT_SECONDS: Float
|
|
4
4
|
DEFAULT_MEMORY_LIMIT: Integer
|
|
5
5
|
DEFAULT_OUTPUT_LIMIT: Integer
|
|
6
|
+
DEFAULT_PROFILE: Symbol
|
|
7
|
+
PROFILES: Array[Symbol]
|
|
6
8
|
|
|
7
9
|
attr_reader timeout: Float?
|
|
8
10
|
attr_reader memory_limit: Integer?
|
|
9
11
|
attr_reader stdout_limit: Integer?
|
|
10
12
|
attr_reader stderr_limit: Integer?
|
|
13
|
+
attr_reader profile: Symbol
|
|
11
14
|
|
|
12
15
|
def self.new: (
|
|
13
16
|
?timeout: (Float | Integer)?,
|
|
14
17
|
?memory_limit: Integer?,
|
|
15
18
|
?stdout_limit: Integer?,
|
|
16
|
-
?stderr_limit: Integer
|
|
19
|
+
?stderr_limit: Integer?,
|
|
20
|
+
?profile: Symbol
|
|
17
21
|
) -> SandboxOptions
|
|
18
22
|
|
|
19
23
|
def initialize: (
|
|
20
24
|
?timeout: (Float | Integer)?,
|
|
21
25
|
?memory_limit: Integer?,
|
|
22
26
|
?stdout_limit: Integer?,
|
|
23
|
-
?stderr_limit: Integer
|
|
27
|
+
?stderr_limit: Integer?,
|
|
28
|
+
?profile: Symbol
|
|
24
29
|
) -> void
|
|
25
30
|
|
|
31
|
+
def enforce_floor!: (Symbol declared) -> void
|
|
32
|
+
|
|
26
33
|
private
|
|
27
34
|
|
|
28
35
|
def normalize_timeout: ((Float | Integer)? timeout) -> Float?
|
|
@@ -30,5 +37,7 @@ module Kobako
|
|
|
30
37
|
def normalize_memory_limit: (Integer? memory_limit) -> Integer?
|
|
31
38
|
|
|
32
39
|
def normalize_output_limit: (Integer? limit, String name) -> Integer?
|
|
40
|
+
|
|
41
|
+
def normalize_profile: (untyped profile) -> Symbol
|
|
33
42
|
end
|
|
34
43
|
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.
|
|
4
|
+
version: 0.13.0
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Aotokitsuruya
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: msgpack
|
|
@@ -69,7 +69,6 @@ files:
|
|
|
69
69
|
- lib/kobako/runtime.rb
|
|
70
70
|
- lib/kobako/sandbox.rb
|
|
71
71
|
- lib/kobako/sandbox_options.rb
|
|
72
|
-
- lib/kobako/snapshot.rb
|
|
73
72
|
- lib/kobako/snippet.rb
|
|
74
73
|
- lib/kobako/snippet/binary.rb
|
|
75
74
|
- lib/kobako/snippet/source.rb
|
|
@@ -108,7 +107,6 @@ files:
|
|
|
108
107
|
- sig/kobako/runtime.rbs
|
|
109
108
|
- sig/kobako/sandbox.rbs
|
|
110
109
|
- sig/kobako/sandbox_options.rbs
|
|
111
|
-
- sig/kobako/snapshot.rbs
|
|
112
110
|
- sig/kobako/snippet.rbs
|
|
113
111
|
- sig/kobako/snippet/binary.rbs
|
|
114
112
|
- sig/kobako/snippet/source.rbs
|
data/lib/kobako/snapshot.rb
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "capture"
|
|
4
|
-
|
|
5
|
-
module Kobako
|
|
6
|
-
# Kobako::Snapshot — per-invocation observable bundle returned from
|
|
7
|
-
# +Kobako::Runtime#eval+ and +#run+.
|
|
8
|
-
#
|
|
9
|
-
# The magnus class (see ext/kobako/src/snapshot.rs) carries five raw
|
|
10
|
-
# readers: +return_bytes+, +stdout_bytes+, +stdout_truncated+,
|
|
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
|
-
class Snapshot
|
|
18
|
-
# Wrap the stdout capture pair (+stdout_bytes+, +stdout_truncated+)
|
|
19
|
-
# as a +Kobako::Capture+ value object. The byte content never carries
|
|
20
|
-
# a truncation sentinel; +#truncated?+ is the only way to observe
|
|
21
|
-
# that the cap was hit.
|
|
22
|
-
def stdout
|
|
23
|
-
Capture.new(bytes: stdout_bytes, truncated: stdout_truncated)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Wrap the stderr capture pair as a +Kobako::Capture+ value object.
|
|
27
|
-
# Mirror of +#stdout+.
|
|
28
|
-
def stderr
|
|
29
|
-
Capture.new(bytes: stderr_bytes, truncated: stderr_truncated)
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
data/sig/kobako/snapshot.rbs
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
module Kobako
|
|
2
|
-
class Snapshot
|
|
3
|
-
def return_bytes: () -> String
|
|
4
|
-
def stdout_bytes: () -> String
|
|
5
|
-
def stdout_truncated: () -> bool
|
|
6
|
-
def stderr_bytes: () -> String
|
|
7
|
-
def stderr_truncated: () -> bool
|
|
8
|
-
|
|
9
|
-
def stdout: () -> Kobako::Capture
|
|
10
|
-
def stderr: () -> Kobako::Capture
|
|
11
|
-
end
|
|
12
|
-
end
|