kobako 0.26.0-aarch64-linux → 0.27.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 +32 -0
- data/README.md +80 -17
- data/crates/kobako-runtime/CHANGELOG.md +7 -0
- data/crates/kobako-runtime/README.md +9 -12
- data/crates/kobako-transport/CHANGELOG.md +7 -0
- data/crates/kobako-transport/README.md +29 -22
- data/crates/kobako-wasmtime/CHANGELOG.md +7 -0
- data/crates/kobako-wasmtime/README.md +8 -10
- 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/version.rb +1 -1
- data/rust-toolchain.toml +4 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 60336f7cdf1fe0abadc8ade4e40a549de94ecc3233c01b4b5f3f9dc584cd0f45
|
|
4
|
+
data.tar.gz: 7e9a80c3838fdc079548e2dfb448eebca2e7497c7195cc80dc36f5315592e9e0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3a94964cb83b51c3e528d4aab9555710032405e700ad8ffcceb3f9f629d79527bb4ad456d5e2ef84e4c5b7140d7841e8406e7d861086bbe1cbbffb1b4f027c32
|
|
7
|
+
data.tar.gz: 8c0b5786a0ebc742f7667afe7ed109e837d8260a02316bc36389bf54124321e7441ef2d020e1b0c63668c34a49a480cb95d3a68197a4da4da6eeeca92f8cc519
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{".":"0.
|
|
1
|
+
{".":"0.27.0","wasm/kobako-core":"0.17.0","wasm/kobako-mruby":"0.17.0","wasm/kobako-io":"0.17.0","wasm/kobako-json":"0.17.0","wasm/kobako-regexp":"0.17.0","wasm/kobako-baker":"0.17.0","crates/kobako-transport":"0.17.0","crates/kobako-codec":"0.17.0","crates/kobako-runtime":"0.17.0","crates/kobako-wasmtime":"0.17.0","crates/kobako":"0.17.0"}
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.27.0](https://github.com/elct9620/kobako/compare/v0.26.0...v0.27.0) (2026-09-20)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### ⚠ BREAKING CHANGES
|
|
7
|
+
|
|
8
|
+
* **guest:** a pattern's allocator is undefined from the moment the capability installs rather than from its first wrap, so allocating one is refused for the missing allocator throughout an invocation, where before the first statement could still reach an uninitialized carrier.
|
|
9
|
+
* **mruby:** `kobako_mruby::dispatch` takes `Option<Proc>` where it took a `Value` that could be nil. A gem passes the block its method read off its own frame; `None` says there is none.
|
|
10
|
+
* **json:** a JSON failure whose error class the guest replaced reaches the Host App as a guest exception rather than as a trap.
|
|
11
|
+
* **json:** JSON.parse refuses a second positional argument. Options passed as a positional Hash, the shape MRI also refuses, must be written as keywords.
|
|
12
|
+
* **mruby:** an object bearing a capability reference's class name without being one is refused as a value the wire cannot carry, where it previously crossed as a reference to whatever identifier it held.
|
|
13
|
+
* **mruby:** an object whose class carries a list's or a map's name without being one is refused rather than read as that container, both as the invocation's own answer and as a dispatch argument.
|
|
14
|
+
* **guest:** `Kobako::raise_transport_error`, `raise_service_error` and `reraise` are gone. A flow of its own builds `Kobako::transport_error` or `service_error` and hands the result back as `Err`, which beni raises at the guest call site.
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* **gate:** hold a crate README's install snippet to its manifest ([31f6926](https://github.com/elct9620/kobako/commit/31f692602de6e1a2d9e5f84872164e83c4008e50))
|
|
19
|
+
* **guest:** rebuild the guest crates on beni 0.17 ([b397701](https://github.com/elct9620/kobako/commit/b397701231c7d8718503d24f73b175676d0d1be3))
|
|
20
|
+
* **guest:** rebuild the guest crates on beni 0.18 ([ae232eb](https://github.com/elct9620/kobako/commit/ae232ebbf708419ff0672172fbf8627363fb02da))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
* **json:** read a parse's options from the keywords it declares ([6f0c83c](https://github.com/elct9620/kobako/commit/6f0c83cc0b6ae0fe0f327ad0b514d46a6f3432c0))
|
|
26
|
+
* **json:** report a replaced error class instead of ending the invocation ([5a75e42](https://github.com/elct9620/kobako/commit/5a75e42ba7990eb31d8487dd3979cca3c4a3d29b))
|
|
27
|
+
* **mruby:** prove a container's layout by its tag, not its class name ([5ee8c59](https://github.com/elct9620/kobako/commit/5ee8c59db90cee27f356028ff466860afe89e06e))
|
|
28
|
+
* **mruby:** read a reference's identity from the class the bridge registered ([0f24102](https://github.com/elct9620/kobako/commit/0f24102b75f771548cbc39256690e59d6df1f9e4))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### Code Refactoring
|
|
32
|
+
|
|
33
|
+
* **mruby:** carry a dispatch's block as the block it is ([01d8831](https://github.com/elct9620/kobako/commit/01d8831dff173e80c10d965af8615acb4de2498b))
|
|
34
|
+
|
|
3
35
|
## [0.26.0](https://github.com/elct9620/kobako/compare/v0.25.0...v0.26.0) (2026-09-15)
|
|
4
36
|
|
|
5
37
|
|
data/README.md
CHANGED
|
@@ -24,11 +24,14 @@ The host (`wasmtime`) runs a precompiled `kobako.wasm` guest containing mruby an
|
|
|
24
24
|
|
|
25
25
|
## Requirements
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
| What | Which versions | When you need it |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| Ruby | ≥ 3.3.0 | always |
|
|
30
|
+
| Platform | Linux or macOS | always — Windows is not supported |
|
|
31
|
+
| Rust / Cargo | current stable | only where no prebuilt gem matches your platform; otherwise the native extension installs ready-built |
|
|
32
|
+
| WASI toolchain | vendored by the build | only when building the gem from a source checkout — see [Development](#development) |
|
|
30
33
|
|
|
31
|
-
The precompiled `kobako.wasm` Guest Binary ships inside the gem, so end users do **not** need a WASI toolchain.
|
|
34
|
+
The precompiled `kobako.wasm` Guest Binary ships inside the gem, so end users do **not** need a WASI toolchain.
|
|
32
35
|
|
|
33
36
|
## Installation
|
|
34
37
|
|
|
@@ -63,9 +66,16 @@ The gem bundles its Guest Binary; a Rust host loads one explicitly — see [Fron
|
|
|
63
66
|
|
|
64
67
|
## Frontends & Guest Binaries
|
|
65
68
|
|
|
66
|
-
Embedding kobako is two independent choices: the **host frontend** you build against, and the **Guest Binary** it runs.
|
|
69
|
+
Embedding kobako is two independent choices: the **host frontend** you build against, and the **Guest Binary** it runs.
|
|
67
70
|
|
|
68
|
-
|
|
71
|
+
```text
|
|
72
|
+
host frontend Guest Binary
|
|
73
|
+
Ruby gem ──┐ ┌── kobako.wasm (pure)
|
|
74
|
+
Rust SDK ──┼──┼── kobako+regexp.wasm
|
|
75
|
+
your own ──┘ └── kobako+json.wasm · your own
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
They compose freely — any frontend loads any Guest Binary, so a Ruby host can run a JSON-enabled guest and a Rust host can run the pure default. How far down those choices go — and which ones a given starting point quietly makes for you — is laid out in [`docs/architecture.md`](docs/architecture.md).
|
|
69
79
|
|
|
70
80
|
### Host frontends
|
|
71
81
|
|
|
@@ -149,6 +159,16 @@ Build the crate as a `cdylib` for `wasm32-wasip1`, then bake the canonical boot
|
|
|
149
159
|
|
|
150
160
|
## Usage
|
|
151
161
|
|
|
162
|
+
Each section below stands on its own; this is the order they build in.
|
|
163
|
+
|
|
164
|
+
| If you want to | Read |
|
|
165
|
+
|---|---|
|
|
166
|
+
| let guest code call into your host | [Services](#services), [Per-Invocation Bindings](#per-invocation-bindings), [Service Blocks](#service-blocks) |
|
|
167
|
+
| see what a run produced or why it failed | [Output Capture](#output-capture), [Error Handling](#error-handling), [Invocation Lifecycle](#invocation-lifecycle) |
|
|
168
|
+
| bound what a run may consume | [Resource Limits](#resource-limits), [Concurrency](#concurrency), [Pooling](#pooling) |
|
|
169
|
+
| hand host objects across the boundary | [Handle Management](#handle-management) |
|
|
170
|
+
| ship guest code with the Sandbox | [Snippets & Entrypoints](#snippets--entrypoints), [Extensions](#extensions) |
|
|
171
|
+
|
|
152
172
|
### Services
|
|
153
173
|
|
|
154
174
|
`bind` any Ruby object as a Service at a constant-path name; the guest reaches it as a `MyService::KV` (or top-level `File`) proxy and invokes the public methods its own class defines through the Transport wire. See [`SV-006`](docs/spec/behavior/services.md) and [`SV-007`](docs/spec/behavior/services.md).
|
|
@@ -256,7 +276,14 @@ Beyond the four caps, `profile:` requests the Sandbox's isolation posture on the
|
|
|
256
276
|
|
|
257
277
|
### Concurrency
|
|
258
278
|
|
|
259
|
-
A Sandbox keeps no state from any run, so concurrent Threads may invoke distinct Sandboxes or share a single one; each invocation owns its Handles, captures, and usage either way ([`RT-001`](docs/spec/behavior/runtime.md), [`RT-002`](docs/spec/behavior/runtime.md)). One Thread still runs one invocation at a time. Sharing a Sandbox adds a single obligation
|
|
279
|
+
A Sandbox keeps no state from any run, so concurrent Threads may invoke distinct Sandboxes or share a single one; each invocation owns its Handles, captures, and usage either way ([`RT-001`](docs/spec/behavior/runtime.md), [`RT-002`](docs/spec/behavior/runtime.md)). One Thread still runs one invocation at a time. Sharing a Sandbox adds a single obligation.
|
|
280
|
+
|
|
281
|
+
| What you bind | Who reaches it | What it owes |
|
|
282
|
+
|---|---|---|
|
|
283
|
+
| Bound once at setup | every Thread sharing the Sandbox | it must itself be thread-safe |
|
|
284
|
+
| Supplied per invocation — `ctx.bind`, or an Extension `provider:` | that invocation alone | nothing |
|
|
285
|
+
|
|
286
|
+
#### Choosing a GVL mode
|
|
260
287
|
|
|
261
288
|
By default an invocation holds Ruby's GVL for its whole span, so guest execution across Threads serializes. `gvl: :release` drops the GVL for the guest span and re-acquires it for each guest→host dispatch, running guest code in parallel across Threads ([`RT-024`](docs/spec/behavior/runtime.md), [`RT-026`](docs/spec/behavior/runtime.md)).
|
|
262
289
|
|
|
@@ -321,8 +348,6 @@ For workloads that must be isolated from each other (one Sandbox per tenant, per
|
|
|
321
348
|
|
|
322
349
|
For hosts that serve many short invocations, `Kobako::Pool` keeps a bounded set of warm, identically set-up Sandboxes and hands each one to a single exclusive holder at a time ([`PL-003`](docs/spec/behavior/pool.md), [`PL-011`](docs/spec/behavior/pool.md)). Construction forwards every `Sandbox.new` keyword verbatim; the optional block is the per-Sandbox setup window and runs exactly once per constructed Sandbox.
|
|
323
350
|
|
|
324
|
-
`Kobako::Pool` is experimental today and is best treated as a convenience for warm, pre-configured reuse rather than a throughput optimisation. The build bakes the shared boot state into the artifact ([`mruby.md`](docs/spec/behavior/mruby.md)) and every dynamic script still compiles and runs per invocation, so all a pool actually saves is the host-side `Sandbox.new` — now under 3 µs, an order of magnitude below the invocation that follows it. For the workload kobako is built for — many small, short-lived Sandboxes running dynamic scripts — that is not a gain worth the coupling. What a Pool buys is warm setup and exclusive checkout, not isolation: a Sandbox holds no state from any run, so Threads sharing one are equally safe (see [Concurrency](#concurrency)).
|
|
325
|
-
|
|
326
351
|
```ruby
|
|
327
352
|
pool = Kobako::Pool.new(slots: 4) do |sandbox|
|
|
328
353
|
sandbox.bind("KV::Lookup", ->(key) { redis.get(key) })
|
|
@@ -331,6 +356,8 @@ end
|
|
|
331
356
|
pool.with { |sandbox| sandbox.eval(%(KV::Lookup.call("user_42"))).value }
|
|
332
357
|
```
|
|
333
358
|
|
|
359
|
+
#### Options and lifetime
|
|
360
|
+
|
|
334
361
|
| Option | Meaning | Default |
|
|
335
362
|
|--------|---------|---------|
|
|
336
363
|
| `slots:` | Upper bound on constructed Sandboxes | required |
|
|
@@ -338,6 +365,14 @@ pool.with { |sandbox| sandbox.eval(%(KV::Lookup.call("user_42"))).value }
|
|
|
338
365
|
|
|
339
366
|
Sandboxes construct lazily on first demand. `#with` yields a Sandbox and returns the block's value; at block exit the Sandbox returns to the pool, except a block that raises `Kobako::TrapError` discards its Sandbox and the slot refills by a fresh construction on next demand. A checkout that waits past `checkout_timeout` raises `Kobako::PoolTimeoutError`. There is no teardown verb — a Pool releases everything with its own reachability.
|
|
340
367
|
|
|
368
|
+
#### What a Pool buys
|
|
369
|
+
|
|
370
|
+
| It gives you | It does not give you |
|
|
371
|
+
|---|---|
|
|
372
|
+
| warm, pre-configured Sandboxes and exclusive checkout | isolation — a Sandbox holds no state from any run, so Threads sharing one are equally safe (see [Concurrency](#concurrency)) |
|
|
373
|
+
|
|
374
|
+
`Kobako::Pool` is experimental today and is best treated as a convenience for warm, pre-configured reuse rather than a throughput optimisation. The build bakes the shared boot state into the artifact ([`mruby.md`](docs/spec/behavior/mruby.md)) and every dynamic script still compiles and runs per invocation, so all a pool actually saves is the host-side `Sandbox.new` — now about 3 µs, an order of magnitude below the invocation that follows it. For the workload kobako is built for — many small, short-lived Sandboxes running dynamic scripts — that is not a gain worth the coupling.
|
|
375
|
+
|
|
341
376
|
### Service Blocks
|
|
342
377
|
|
|
343
378
|
A Service method can accept a guest-supplied block via `&blk` and `yield` into it. The block body runs inside the Wasm guest; `break` / `next` / exceptions follow normal Ruby semantics, scoped to the single dispatch. See [`T-085`](docs/spec/behavior/transport-yield.md) and [`T-089`](docs/spec/behavior/transport-yield.md).
|
|
@@ -367,6 +402,8 @@ sandbox.eval('Factory::Make.call("Bob")').value # => #<Greeter @name="Bob
|
|
|
367
402
|
|
|
368
403
|
A `break` value from a guest block is the one exception: it unwinds back to the guest Service call rather than to host code, so a Handle in it stays a Handle — restoring would just re-wrap the same object into a new id on the return trip.
|
|
369
404
|
|
|
405
|
+
#### One Handle per dispatch
|
|
406
|
+
|
|
370
407
|
Each dispatch that hands back a non-wire-representable object allocates a *new* Handle — kobako never deduplicates by object identity ([`T-007`](docs/spec/behavior/transport-dispatch.md), [`T-009`](docs/spec/behavior/transport-dispatch.md)). This is most visible with fluent / builder APIs. An `ActiveRecord::Relation` chain `spawn`s a fresh relation at each step, so every hop is an independent dispatch that binds its own Handle:
|
|
371
408
|
|
|
372
409
|
```
|
|
@@ -417,6 +454,8 @@ A target no snippet defined raises `Kobako::UndefinedEntrypointError`, whose `#a
|
|
|
417
454
|
return the Execution, then discard the instance
|
|
418
455
|
```
|
|
419
456
|
|
|
457
|
+
#### Choosing a payload form
|
|
458
|
+
|
|
420
459
|
`#preload` accepts two payload forms:
|
|
421
460
|
|
|
422
461
|
| Form | Signature | Snippet name source | Validation timing |
|
|
@@ -481,11 +520,22 @@ sandbox.bind("Cfg::Settings", ThemeReader.new) # not: bind("Cfg::Settings", App
|
|
|
481
520
|
sandbox.eval('Cfg::Settings.color').value # => "#3366ff" — every other method raises NoMethodError
|
|
482
521
|
```
|
|
483
522
|
|
|
523
|
+
#### Gating an object's own surface
|
|
524
|
+
|
|
484
525
|
When a purpose-built wrapper is more than you need, an object can gate its own surface in
|
|
485
526
|
place: a private `respond_to_guest?(name)` answers, per method, whether the guest may call
|
|
486
527
|
it. Returning `false` for every name makes the object opaque — a credential the guest
|
|
487
528
|
forwards to another Service but never reads — while permitting a named subset exposes exactly those.
|
|
488
529
|
|
|
530
|
+
```ruby
|
|
531
|
+
class Credential
|
|
532
|
+
def initialize(token) = @token = token
|
|
533
|
+
def to_s = @token
|
|
534
|
+
|
|
535
|
+
private def respond_to_guest?(_name) = false # forwardable, never readable
|
|
536
|
+
end
|
|
537
|
+
```
|
|
538
|
+
|
|
489
539
|
Guest code can name any `MyService::KV` path, but a forged name only resolves to
|
|
490
540
|
something you bound — the real authorization gate is this host-side allowlist. Give each
|
|
491
541
|
trust context its own Sandbox, and see [`docs/security-model.md`](docs/security-model.md) for the rest
|
|
@@ -499,17 +549,25 @@ Order-of-magnitude figures on macOS arm64, Ruby 3.4.7, YJIT off. Absolute values
|
|
|
499
549
|
| Phase | Cost |
|
|
500
550
|
|--------------------------------------------------------------|-----------------------|
|
|
501
551
|
| First `Sandbox.new` ever for a Guest Binary (Module JIT, then disk-cached) | ~500 ms once per machine |
|
|
502
|
-
| First `Sandbox.new` in a fresh process (`.cwasm` cache warm) | ~
|
|
552
|
+
| First `Sandbox.new` in a fresh process (`.cwasm` cache warm) | ~3 ms one-time |
|
|
503
553
|
| Subsequent `Sandbox.new` (caches warm) | ~3 µs |
|
|
504
|
-
| Warm `#eval` with one Service call on a reused Sandbox | ~
|
|
505
|
-
| Warm `#run(:Entrypoint, ...)` dispatch | ~
|
|
506
|
-
| Service call amortized inside one invocation | ~5.
|
|
507
|
-
| Snippet replay per invocation | ~7.
|
|
554
|
+
| Warm `#eval` with one Service call on a reused Sandbox | ~70 µs |
|
|
555
|
+
| Warm `#run(:Entrypoint, ...)` dispatch | ~79 µs |
|
|
556
|
+
| Service call amortized inside one invocation | ~5.8 µs |
|
|
557
|
+
| Snippet replay per invocation | ~7.0 µs each |
|
|
508
558
|
| Per additional idle Sandbox (RSS) | ~1 KB |
|
|
509
559
|
|
|
510
|
-
The Cranelift JIT runs once per machine and gem version — the compiled artifact persists in a `.cwasm` disk cache, so later processes deserialize in milliseconds. An idle Sandbox holds no wasm instance (the canonical boot state is baked into the artifact and instantiated per invocation), which is why a thousand idle tenants cost ~
|
|
560
|
+
The Cranelift JIT runs once per machine and gem version — the compiled artifact persists in a `.cwasm` disk cache, so later processes deserialize in milliseconds. An idle Sandbox holds no wasm instance (the canonical boot state is baked into the artifact and instantiated per invocation), which is why a thousand idle tenants cost ~34 MB total. A +10% regression on any SPEC-mandated benchmark blocks release.
|
|
561
|
+
|
|
562
|
+
#### What moves the ceiling
|
|
511
563
|
|
|
512
|
-
|
|
564
|
+
| Choice | What it changes |
|
|
565
|
+
|---|---|
|
|
566
|
+
| `gvl: :hold` (default) | wasm work is GVL-serialized: aggregate throughput stays around 16k `#eval`/s regardless of Thread count, though Ruby-side `#eval` setup still overlaps |
|
|
567
|
+
| `gvl: :release` | lifts that ceiling for compute-bound scripts (see [Concurrency](#concurrency)) |
|
|
568
|
+
| `match?` over `=~` | `=~` (~5 µs/match) costs about 5× `match?` (~1.0 µs), because it eagerly builds the `MatchData` and match globals — prefer `match?` for boolean tests |
|
|
569
|
+
|
|
570
|
+
Regexp is an opt-in capability gem, excluded from the default binary and the gated set; its throughput is tracked in a separate non-gated characterization (`#11` in [`benchmark/README.md`](benchmark/README.md)).
|
|
513
571
|
|
|
514
572
|
```bash
|
|
515
573
|
bundle exec rake bench # every gated regression benchmark (~5-8 min)
|
|
@@ -530,7 +588,12 @@ Building from source requires a WASI-capable Rust toolchain in addition to the s
|
|
|
530
588
|
|
|
531
589
|
Bug reports and pull requests are welcome at <https://github.com/elct9620/kobako>. Please open an issue before starting on non-trivial changes so we can align on scope.
|
|
532
590
|
|
|
533
|
-
Releases are automated with release-please across two tracks
|
|
591
|
+
Releases are automated with release-please across two tracks; the version rules, commit conventions, and how to cut each release live in [`docs/releasing.md`](docs/releasing.md).
|
|
592
|
+
|
|
593
|
+
| Track | What it ships | Tag |
|
|
594
|
+
|---|---|---|
|
|
595
|
+
| Gem | the Ruby gem, with the bundled `kobako.wasm` | `v*` |
|
|
596
|
+
| Crates | the linked guest-crate group | `<component>-v*` |
|
|
534
597
|
|
|
535
598
|
## License
|
|
536
599
|
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.17.0](https://github.com/elct9620/kobako/compare/kobako-runtime-v0.16.0...kobako-runtime-v0.17.0) (2026-09-20)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Miscellaneous Chores
|
|
7
|
+
|
|
8
|
+
* **kobako-runtime:** Synchronize kobako crates versions
|
|
9
|
+
|
|
3
10
|
## [0.16.0](https://github.com/elct9620/kobako/compare/kobako-runtime-v0.15.0...kobako-runtime-v0.16.0) (2026-09-15)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -6,17 +6,14 @@ sandbox for running untrusted mruby scripts.
|
|
|
6
6
|
|
|
7
7
|
A kobako host drives a Guest Binary through a wasm engine; this crate
|
|
8
8
|
is the surface where the two meet, free of any engine or frontend
|
|
9
|
-
type, so the engine stays swappable
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
|
9
|
+
type, so the engine stays swappable.
|
|
10
|
+
|
|
11
|
+
| Module | What it declares |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `runtime` | the `Runtime` trait: one guest invocation on a fresh instance in, its observable `Snapshot` out |
|
|
14
|
+
| `snapshot` | the per-invocation observables — `Completion` (outcome or trap), the two output `Capture`s, and resource `Usage`, uniform across success and trap |
|
|
15
|
+
| `error` | the neutral failure channels: `Trap` (engine fault) and `SetupError` (the invocation never started) |
|
|
16
|
+
| `dispatch` / `yielder` | the `DispatchHandler` and `Yielder` traits a frontend supplies for guest→host dispatch and block-yield re-entry |
|
|
20
17
|
|
|
21
18
|
Engine implementations (such as `kobako-wasmtime`) implement
|
|
22
19
|
`Runtime`; host frontends (such as the kobako Ruby gem's native ext)
|
|
@@ -26,7 +23,7 @@ map the neutral types onto their own language surface.
|
|
|
26
23
|
|
|
27
24
|
```toml
|
|
28
25
|
[dependencies]
|
|
29
|
-
kobako-runtime = "0.
|
|
26
|
+
kobako-runtime = "0.17.0" # x-release-please-version
|
|
30
27
|
```
|
|
31
28
|
|
|
32
29
|
## License
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.17.0](https://github.com/elct9620/kobako/compare/kobako-transport-v0.16.0...kobako-transport-v0.17.0) (2026-09-20)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Miscellaneous Chores
|
|
7
|
+
|
|
8
|
+
* **kobako-transport:** Synchronize kobako crates versions
|
|
9
|
+
|
|
3
10
|
## [0.16.0](https://github.com/elct9620/kobako/compare/kobako-transport-v0.15.0...kobako-transport-v0.16.0) (2026-09-15)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -5,27 +5,34 @@ an in-process Wasm sandbox for running untrusted mruby scripts.
|
|
|
5
5
|
|
|
6
6
|
kobako is assembled from three parts chosen independently: a host, a
|
|
7
7
|
payload codec, and a guest. That works only because two things are the
|
|
8
|
-
same in every assembly. This crate is both of them, and nothing else
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
8
|
+
same in every assembly. This crate is both of them, and nothing else.
|
|
9
|
+
|
|
10
|
+
| Module | What it fixes |
|
|
11
|
+
|---|---|
|
|
12
|
+
| `envelope` | the **core envelope**, the outer frame each message rides in: `Call` / `Reply` / `YieldReply` for a dispatch round-trip, `Outcome` / `Panic` for how an invocation ended, `Run` / `Preamble` / `Snippets` for what an invocation is handed, and the `ErrorRecord` a guest failure carries |
|
|
13
|
+
| `abi` | the values a host and a guest must already agree on to exchange a byte: the version, the packed `(ptr, len)` return layout, the invocation-channel frame prefix, and the message size cap |
|
|
14
|
+
|
|
15
|
+
## What the envelope does not read
|
|
16
|
+
|
|
17
|
+
The envelope reads a message's routing fields and its ok-versus-fault tag
|
|
18
|
+
without decoding a payload byte. Everything the resolved method consumes
|
|
19
|
+
rides through opaque, and a decoded envelope borrows the buffer it came
|
|
20
|
+
from, so that payload reaches its reader as a view rather than a copy.
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
Call { method, payload }
|
|
24
|
+
└── opaque here; read by whoever owns the schema
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Where it sits
|
|
28
|
+
|
|
29
|
+
This crate depends on no other, and every kobako tier depends on it —
|
|
30
|
+
including any third-party engine, codec, or guest composing against them.
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
host kobako-runtime · kobako-wasmtime ──┐
|
|
34
|
+
guest kobako-core · kobako-mruby ────────┴──> kobako-transport
|
|
35
|
+
```
|
|
29
36
|
|
|
30
37
|
The byte layout is specified in
|
|
31
38
|
[`docs/wire/envelope.md`](https://github.com/elct9620/kobako/blob/main/docs/wire/envelope.md);
|
|
@@ -35,7 +42,7 @@ the golden vectors in this crate are derived from that document.
|
|
|
35
42
|
|
|
36
43
|
```toml
|
|
37
44
|
[dependencies]
|
|
38
|
-
kobako-transport = "0.
|
|
45
|
+
kobako-transport = "0.17.0" # x-release-please-version
|
|
39
46
|
```
|
|
40
47
|
|
|
41
48
|
## License
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.17.0](https://github.com/elct9620/kobako/compare/kobako-wasmtime-v0.16.0...kobako-wasmtime-v0.17.0) (2026-09-20)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Miscellaneous Chores
|
|
7
|
+
|
|
8
|
+
* **kobako-wasmtime:** Synchronize kobako crates versions
|
|
9
|
+
|
|
3
10
|
## [0.16.0](https://github.com/elct9620/kobako/compare/kobako-wasmtime-v0.15.0...kobako-wasmtime-v0.16.0) (2026-09-15)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -6,16 +6,14 @@ The [wasmtime](https://wasmtime.dev) implementation of the
|
|
|
6
6
|
|
|
7
7
|
`Driver` implements the contract's `Runtime` trait over wasmtime and
|
|
8
8
|
owns every engine-bound mechanic, so frontends see only the neutral
|
|
9
|
-
contract surface
|
|
9
|
+
contract surface.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- ambient denial: frozen WASI clocks and a constant RNG, so a guest
|
|
18
|
-
observes no real time and no real entropy
|
|
11
|
+
| Mechanic | What the driver holds |
|
|
12
|
+
|---|---|
|
|
13
|
+
| Compilation | process-wide Engine and compiled-Module caches, with an on-disk AOT (`.cwasm`) artifact cache keyed by Guest Binary content |
|
|
14
|
+
| Instantiation | a pre-linked `InstancePre` per guest path; every invocation runs on a fresh instance and discards its Store afterwards |
|
|
15
|
+
| Bounds | the epoch-based wall-clock timeout and the per-invocation linear-memory cap |
|
|
16
|
+
| Ambient denial | frozen WASI clocks and a constant RNG, so a guest observes no real time and no real entropy |
|
|
19
17
|
|
|
20
18
|
The kobako Ruby gem's native ext is the first frontend; a Rust host
|
|
21
19
|
SDK consumes the same surface.
|
|
@@ -24,7 +22,7 @@ SDK consumes the same surface.
|
|
|
24
22
|
|
|
25
23
|
```toml
|
|
26
24
|
[dependencies]
|
|
27
|
-
kobako-wasmtime = "0.
|
|
25
|
+
kobako-wasmtime = "0.17.0" # x-release-please-version
|
|
28
26
|
```
|
|
29
27
|
|
|
30
28
|
## License
|
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/version.rb
CHANGED
data/rust-toolchain.toml
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
# vendored wasi-sdk 33's libc.a supplies that symbol, so the two move together.
|
|
4
4
|
# Bump this in lockstep with the wasi-sdk toolchain beni vendors
|
|
5
5
|
# (`rake beni:build`, wired in the Rakefile's Beni::Tasks block).
|
|
6
|
+
# The floor is 1.98: rustc strips an Apple binary with its own Mach-O writer,
|
|
7
|
+
# and only from that release does the stripped string pool keep the alignment
|
|
8
|
+
# dyld requires from macOS 26 onward — below it, `strip = true` in the release
|
|
9
|
+
# profile yields an ext no dlopen accepts.
|
|
6
10
|
# This file is the single source of the channel; the CI workflows read it.
|
|
7
11
|
[toolchain]
|
|
8
12
|
channel = "stable"
|
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.27.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-09-
|
|
11
|
+
date: 2026-09-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: msgpack
|