kobako 0.9.1 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +11 -0
- data/Cargo.lock +1 -1
- data/Cargo.toml +6 -0
- data/data/kobako.wasm +0 -0
- data/ext/kobako/Cargo.toml +1 -1
- data/ext/kobako/src/runtime/ambient.rs +78 -0
- data/ext/kobako/src/runtime/invocation.rs +1 -1
- data/ext/kobako/src/runtime.rs +21 -4
- data/lib/kobako/catalog/handles.rb +30 -7
- data/lib/kobako/catalog/namespaces.rb +0 -1
- data/lib/kobako/codec.rb +5 -6
- data/lib/kobako/transport/dispatcher.rb +29 -10
- data/lib/kobako/transport/request.rb +1 -9
- data/lib/kobako/transport/response.rb +9 -2
- data/lib/kobako/version.rb +1 -1
- data/release-please-config.json +1 -2
- data/sig/kobako/catalog/handles.rbs +6 -0
- data/sig/kobako/transport/dispatcher.rbs +4 -0
- data/sig/kobako/transport/request.rbs +0 -3
- data/sig/kobako/transport/response.rbs +3 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3177d01c5cb742a539ac9713226c17c159299911344b1590a680aacd99aa70fd
|
|
4
|
+
data.tar.gz: 6f9a4503a56855076b1f5d83725775669ae4c34283b24bcb8467485509e26c03
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b8f0f15f5c76c54b785e109ca6f7c10a37ebc7394d49f05637b18ace67a1326f941aa0a03ee99b985d8b09b70c39ba42c8318f9dd4fe885dba530472e5b24c81
|
|
7
|
+
data.tar.gz: 794e0c2f476fceaee007fbeb1c8082accd8d1de2de682aa333606bc0ab6593ed281abda277222ca51d58a88f2663d37220e8068891396565221ecc694bdc2b68
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{".":"0.9.
|
|
1
|
+
{".":"0.9.2","wasm/kobako-core":"0.4.1","wasm/kobako":"0.4.1","wasm/kobako-io":"0.4.1","wasm/kobako-regexp":"0.4.1"}
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.9.2](https://github.com/elct9620/kobako/compare/v0.9.1...v0.9.2) (2026-06-11)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **catalog:** never mint a Capability Handle for a reflective gadget ([6c2d29d](https://github.com/elct9620/kobako/commit/6c2d29d0fbcced5187df5538c2c6c437705fd6d8))
|
|
9
|
+
* **ext:** cap stdin frames at 16 MiB like the run envelope ([a94099a](https://github.com/elct9620/kobako/commit/a94099a03830929c55fcb266e227073db9c5a624))
|
|
10
|
+
* **ext:** deny guest ambient clock and entropy at the WASI layer ([1275b35](https://github.com/elct9620/kobako/commit/1275b35264813628a2aeb396a3546faf1f6d9d0c))
|
|
11
|
+
* **transport:** reject reflective gadget methods in guest dispatch ([948fb9e](https://github.com/elct9620/kobako/commit/948fb9ea7d6c0d6bd91f6e261d3263743974388b))
|
|
12
|
+
* **wasm:** mirror the reflection rejection in the guest proxy ([f6ead3b](https://github.com/elct9620/kobako/commit/f6ead3b91f1ac92c3c075397d177edb4b82cd15d))
|
|
13
|
+
|
|
3
14
|
## [0.9.1](https://github.com/elct9620/kobako/compare/v0.9.0...v0.9.1) (2026-06-11)
|
|
4
15
|
|
|
5
16
|
|
data/Cargo.lock
CHANGED
data/Cargo.toml
CHANGED
|
@@ -9,3 +9,9 @@ members = ["./ext/kobako"]
|
|
|
9
9
|
# dependency graphs separate.
|
|
10
10
|
exclude = ["wasm", "vendor"]
|
|
11
11
|
resolver = "2"
|
|
12
|
+
|
|
13
|
+
# Strip the local-symbol table from the shipped ext (~22% of the binary).
|
|
14
|
+
# Guest wasm backtraces and Rust panic locations don't depend on it; for
|
|
15
|
+
# native-crash debugging rebuild with `RB_SYS_CARGO_PROFILE=dev`.
|
|
16
|
+
[profile.release]
|
|
17
|
+
strip = true
|
data/data/kobako.wasm
CHANGED
|
Binary file
|
data/ext/kobako/Cargo.toml
CHANGED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
//! Defense-in-depth denial of guest ambient authority at the WASI layer.
|
|
2
|
+
//!
|
|
3
|
+
//! `wasmtime-wasi`'s `WasiCtxBuilder` defaults the guest's `wasi:clocks` to
|
|
4
|
+
//! the host wall / monotonic clock and `wasi:random` to a fresh per-context
|
|
5
|
+
//! seed. No allowlisted mrbgem reaches these preview1 imports today
|
|
6
|
+
//! (`build_config/wasi.rb`), but a future libc-backed gem would silently
|
|
7
|
+
//! obtain real time and host entropy — a covert timing channel and a
|
|
8
|
+
//! nondeterminism source the sandbox deliberately excludes (docs/security.md).
|
|
9
|
+
//! Pinning the clocks to the Unix epoch and the RNG to a constant stream
|
|
10
|
+
//! makes that denial a property of the host, not merely of the gem allowlist.
|
|
11
|
+
//!
|
|
12
|
+
//! The host wall-clock cap is unaffected: the per-invocation timeout runs on
|
|
13
|
+
//! wasmtime epoch interruption against a host `Instant`, never the guest's
|
|
14
|
+
//! frozen `wasi:clocks/monotonic-clock` (docs/behavior.md B-01).
|
|
15
|
+
|
|
16
|
+
use std::time::Duration;
|
|
17
|
+
|
|
18
|
+
use wasmtime_wasi::random::Deterministic;
|
|
19
|
+
use wasmtime_wasi::{HostMonotonicClock, HostWallClock};
|
|
20
|
+
|
|
21
|
+
/// Wall clock frozen at the Unix epoch — the guest observes no real time.
|
|
22
|
+
pub(super) struct FrozenWallClock;
|
|
23
|
+
|
|
24
|
+
impl HostWallClock for FrozenWallClock {
|
|
25
|
+
fn resolution(&self) -> Duration {
|
|
26
|
+
Duration::from_secs(1)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
fn now(&self) -> Duration {
|
|
30
|
+
Duration::ZERO
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/// Monotonic clock frozen at zero — the guest observes no elapsed time.
|
|
35
|
+
pub(super) struct FrozenMonotonicClock;
|
|
36
|
+
|
|
37
|
+
impl HostMonotonicClock for FrozenMonotonicClock {
|
|
38
|
+
fn resolution(&self) -> u64 {
|
|
39
|
+
1
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
fn now(&self) -> u64 {
|
|
43
|
+
0
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/// Constant-stream RNG handed to the guest's `wasi:random`, so a guest that
|
|
48
|
+
/// reaches `random_get` receives no host entropy.
|
|
49
|
+
pub(super) fn deterministic_rng() -> Deterministic {
|
|
50
|
+
Deterministic::new(vec![0])
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
#[cfg(test)]
|
|
54
|
+
mod tests {
|
|
55
|
+
//! Pin the frozen-clock contract: the guest must observe no real wall
|
|
56
|
+
//! or monotonic time through `wasi:clocks`, regardless of the host's
|
|
57
|
+
//! actual clock. A regression that reverts either clock to the WASI
|
|
58
|
+
//! default would re-expose ambient time to a future libc-backed gem.
|
|
59
|
+
use super::*;
|
|
60
|
+
|
|
61
|
+
#[test]
|
|
62
|
+
fn the_guest_wall_clock_reads_the_unix_epoch() {
|
|
63
|
+
assert_eq!(
|
|
64
|
+
FrozenWallClock.now(),
|
|
65
|
+
Duration::ZERO,
|
|
66
|
+
"guest wasi:clocks/wall-clock must read the Unix epoch, not host time"
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#[test]
|
|
71
|
+
fn the_guest_monotonic_clock_never_advances() {
|
|
72
|
+
assert_eq!(
|
|
73
|
+
FrozenMonotonicClock.now(),
|
|
74
|
+
0,
|
|
75
|
+
"guest wasi:clocks/monotonic-clock must stay frozen at zero"
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
//! initial allocation and prior invocations' watermark are outside the
|
|
19
19
|
//! budget.
|
|
20
20
|
//!
|
|
21
|
-
//! [SPEC.md Single-Invocation Slot]:
|
|
21
|
+
//! [SPEC.md Single-Invocation Slot]: ../../../../SPEC.md
|
|
22
22
|
|
|
23
23
|
use std::cell::{Ref, RefCell, RefMut};
|
|
24
24
|
use std::time::{Duration, Instant};
|
data/ext/kobako/src/runtime.rs
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
// `timeout_err` / `memory_limit_err` / `setup_err` constructors shared by
|
|
32
32
|
// every submodule, and the Ruby init() that registers the class.
|
|
33
33
|
|
|
34
|
+
mod ambient;
|
|
34
35
|
mod cache;
|
|
35
36
|
mod capture;
|
|
36
37
|
mod config;
|
|
@@ -506,7 +507,7 @@ impl Runtime {
|
|
|
506
507
|
rstring_to_vec(preamble),
|
|
507
508
|
rstring_to_vec(source),
|
|
508
509
|
rstring_to_vec(snippets),
|
|
509
|
-
])
|
|
510
|
+
])?;
|
|
510
511
|
self.call_with_caps(eval, ())
|
|
511
512
|
.map_err(|e| trap::call_err(&ruby, e))?;
|
|
512
513
|
self.build_snapshot(&ruby)
|
|
@@ -530,7 +531,7 @@ impl Runtime {
|
|
|
530
531
|
) -> Result<Snapshot, MagnusError> {
|
|
531
532
|
let ruby = Ruby::get().expect("Ruby thread");
|
|
532
533
|
let run = require_export(&ruby, self.exports.run.as_ref())?;
|
|
533
|
-
self.refresh_wasi(&[rstring_to_vec(preamble), rstring_to_vec(snippets)])
|
|
534
|
+
self.refresh_wasi(&[rstring_to_vec(preamble), rstring_to_vec(snippets)])?;
|
|
534
535
|
let (env_ptr, env_len) = self.write_envelope(&ruby, envelope)?;
|
|
535
536
|
self.call_with_caps(run, (env_ptr, env_len))
|
|
536
537
|
.map_err(|e| trap::call_err(&ruby, e))?;
|
|
@@ -735,8 +736,18 @@ impl Runtime {
|
|
|
735
736
|
/// `capture::clip_capture` can distinguish "wrote exactly cap
|
|
736
737
|
/// bytes" from "exceeded cap"; uncapped channels fall back
|
|
737
738
|
/// to `usize::MAX` and rely on `memory_limit` (docs/behavior.md E-20)
|
|
738
|
-
/// for the real ceiling.
|
|
739
|
-
|
|
739
|
+
/// for the real ceiling. Raises `Kobako::TrapError` when any frame
|
|
740
|
+
/// exceeds the 16 MiB cap that keeps its `u32` length prefix from
|
|
741
|
+
/// wrapping.
|
|
742
|
+
fn refresh_wasi(&self, frames: &[Vec<u8>]) -> Result<(), MagnusError> {
|
|
743
|
+
let ruby = Ruby::get().expect("Ruby thread");
|
|
744
|
+
// Every frame carries the same 16 MiB cap as the `#run` envelope
|
|
745
|
+
// (`write_envelope`): the length prefix is a `u32`, so a frame past
|
|
746
|
+
// the cap would silently wrap and corrupt the stdin frame stream.
|
|
747
|
+
for frame in frames {
|
|
748
|
+
guest_mem::checked_payload_len(frame.len()).map_err(|msg| trap_err(&ruby, msg))?;
|
|
749
|
+
}
|
|
750
|
+
|
|
740
751
|
let total: usize = frames.iter().map(|f| 4 + f.len()).sum();
|
|
741
752
|
let mut stdin_content: Vec<u8> = Vec::with_capacity(total);
|
|
742
753
|
for frame in frames {
|
|
@@ -754,12 +765,18 @@ impl Runtime {
|
|
|
754
765
|
builder.stdin(stdin_pipe);
|
|
755
766
|
builder.stdout(stdout_pipe.clone());
|
|
756
767
|
builder.stderr(stderr_pipe.clone());
|
|
768
|
+
// Deny the preview1 ambient-authority imports the guest never legitimately
|
|
769
|
+
// reaches but the WASI layer would otherwise grant (see `ambient`).
|
|
770
|
+
builder.wall_clock(ambient::FrozenWallClock);
|
|
771
|
+
builder.monotonic_clock(ambient::FrozenMonotonicClock);
|
|
772
|
+
builder.secure_random(ambient::deterministic_rng());
|
|
757
773
|
let wasi = builder.build_p1();
|
|
758
774
|
|
|
759
775
|
self.store
|
|
760
776
|
.borrow_mut()
|
|
761
777
|
.data_mut()
|
|
762
778
|
.install_wasi(wasi, stdout_pipe, stderr_pipe);
|
|
779
|
+
Ok(())
|
|
763
780
|
}
|
|
764
781
|
|
|
765
782
|
/// Invoke `__kobako_take_outcome`, decode the packed `(ptr<<32)|len`
|
|
@@ -30,6 +30,13 @@ module Kobako
|
|
|
30
30
|
# +0x7fff_ffff+ (2³¹ − 1). Allocation beyond the cap raises
|
|
31
31
|
# immediately — no silent truncation, no wrap, no ID reuse.
|
|
32
32
|
class Handles
|
|
33
|
+
# Reflective gadget types that are never minted as a Capability Handle
|
|
34
|
+
# ({docs/behavior.md B-43}[link:../../../docs/behavior.md]): wrapping a
|
|
35
|
+
# +Binding+ / +Method+ / +UnboundMethod+ would hand the guest a callable
|
|
36
|
+
# proxy onto host reflection (a returned +Binding+ reaches +Binding#eval+).
|
|
37
|
+
UNWRAPPABLE_TYPES = [Binding, Method, UnboundMethod].freeze
|
|
38
|
+
private_constant :UNWRAPPABLE_TYPES
|
|
39
|
+
|
|
33
40
|
# Build a fresh, empty table. +next_id+ is an internal seam that
|
|
34
41
|
# sets the starting value of the monotonic counter (defaults to 1 per
|
|
35
42
|
# B-15); tests pass a value near +Kobako::Handle::MAX_ID+ to exercise
|
|
@@ -53,14 +60,9 @@ module Kobako
|
|
|
53
60
|
# is reserved for the codec's wire-decode path, where the id is
|
|
54
61
|
# the only thing the bytes carry.
|
|
55
62
|
def alloc(object)
|
|
63
|
+
reject_unwrappable!(object)
|
|
64
|
+
ensure_capacity!
|
|
56
65
|
id = @next_id
|
|
57
|
-
cap = Kobako::Handle::MAX_ID
|
|
58
|
-
if id > cap
|
|
59
|
-
raise HandlerExhaustedError,
|
|
60
|
-
"Out of handle allocations: too many host objects were referenced " \
|
|
61
|
-
"in a single invocation (limit #{cap})"
|
|
62
|
-
end
|
|
63
|
-
|
|
64
66
|
@entries[id] = object
|
|
65
67
|
@next_id = id + 1
|
|
66
68
|
Kobako::Handle.restore(id)
|
|
@@ -94,6 +96,27 @@ module Kobako
|
|
|
94
96
|
|
|
95
97
|
private
|
|
96
98
|
|
|
99
|
+
# Refuse to mint a Capability Handle for a reflective gadget
|
|
100
|
+
# ({UNWRAPPABLE_TYPES}, B-43). Raising here keeps the rule at the single
|
|
101
|
+
# mint point, so it holds on both the Service-return (B-14) and the
|
|
102
|
+
# +#run+ host→guest auto-wrap (B-34) paths.
|
|
103
|
+
def reject_unwrappable!(object)
|
|
104
|
+
return unless UNWRAPPABLE_TYPES.any? { |type| object.is_a?(type) }
|
|
105
|
+
|
|
106
|
+
raise SandboxError, "a #{object.class} cannot cross as a Capability Handle"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Guard {#alloc} against issuing an ID past the B-21 cap. Returns +nil+
|
|
110
|
+
# on success; raises +Kobako::HandlerExhaustedError+ at exhaustion.
|
|
111
|
+
def ensure_capacity!
|
|
112
|
+
cap = Kobako::Handle::MAX_ID
|
|
113
|
+
return unless @next_id > cap
|
|
114
|
+
|
|
115
|
+
raise HandlerExhaustedError,
|
|
116
|
+
"Out of handle allocations: too many host objects were referenced " \
|
|
117
|
+
"in a single invocation (limit #{cap})"
|
|
118
|
+
end
|
|
119
|
+
|
|
97
120
|
# Single source of truth for the "unknown Handle id" raise used by
|
|
98
121
|
# {#fetch}. Returns +nil+ on success; raises +Kobako::SandboxError+
|
|
99
122
|
# when +id+ is not currently bound.
|
data/lib/kobako/codec.rb
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "codec/error"
|
|
4
|
+
require_relative "codec/utils"
|
|
5
|
+
require_relative "codec/factory"
|
|
6
|
+
require_relative "codec/encoder"
|
|
7
|
+
require_relative "codec/decoder"
|
|
4
8
|
|
|
5
9
|
module Kobako
|
|
6
10
|
# Host-side MessagePack codec for the kobako wire contract — the
|
|
@@ -17,15 +21,10 @@ module Kobako
|
|
|
17
21
|
# {Decoder} are thin wrappers that register the three kobako-specific
|
|
18
22
|
# ext types (0x00 Symbol, 0x01 Capability Handle, 0x02 Exception
|
|
19
23
|
# envelope) on a single +MessagePack::Factory+ instance. The Rust side
|
|
20
|
-
# mirrors this layer as the +codec+ module in the +kobako-
|
|
24
|
+
# mirrors this layer as the +codec+ module in the +kobako-core+ crate;
|
|
21
25
|
# the ext-code constants live as module-private values on {Factory}
|
|
22
26
|
# alongside +codec::EXT_SYMBOL+ / +codec::EXT_HANDLE+ /
|
|
23
27
|
# +codec::EXT_ERRENV+ on that side.
|
|
24
28
|
module Codec
|
|
25
29
|
end
|
|
26
30
|
end
|
|
27
|
-
|
|
28
|
-
require_relative "codec/utils"
|
|
29
|
-
require_relative "codec/factory"
|
|
30
|
-
require_relative "codec/encoder"
|
|
31
|
-
require_relative "codec/decoder"
|
|
@@ -46,13 +46,28 @@ module Kobako
|
|
|
46
46
|
# metaprogramming surface (+send+, +public_send+, +instance_eval+,
|
|
47
47
|
# +method+, +tap+, +instance_variable_get+, ...) rather than Service
|
|
48
48
|
# behaviour. A guest-supplied method name resolving to one of these is
|
|
49
|
-
# rejected
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
# +Kernel#eval+ / +#system+
|
|
49
|
+
# rejected ({docs/behavior.md B-42}[link:../../../docs/behavior.md]):
|
|
50
|
+
# only methods the bound object itself exposes as Service behaviour are
|
|
51
|
+
# reachable, and +public_send(:send, ...)+ would otherwise let a guest
|
|
52
|
+
# pivot through +send+ into the private +Kernel#eval+ / +#system+
|
|
53
|
+
# surface (host RCE).
|
|
53
54
|
META_OWNERS = [BasicObject, Kernel, Object, Module, Class].freeze
|
|
54
55
|
private_constant :META_OWNERS
|
|
55
56
|
|
|
57
|
+
# Callable gadget types whose own public methods are reflection surface
|
|
58
|
+
# (+Proc#binding+ reaches +Binding#eval+, +Method#receiver+ / +#unbind+
|
|
59
|
+
# hand back the underlying object) rather than Service behaviour. Only
|
|
60
|
+
# {CALLABLE_ALLOW} is reachable on a target of these types; a bound
|
|
61
|
+
# lambda stays invocable, its reflective surface does not (B-42).
|
|
62
|
+
GADGET_OWNERS = [Proc, Method, UnboundMethod, Binding].freeze
|
|
63
|
+
private_constant :GADGET_OWNERS
|
|
64
|
+
|
|
65
|
+
# The sole methods reachable on a {GADGET_OWNERS} target: invoking it
|
|
66
|
+
# (+call+ / +[]+ / +yield+) and the harmless +arity+ / +lambda?+
|
|
67
|
+
# describers that aid guest-side debugging.
|
|
68
|
+
CALLABLE_ALLOW = %i[call [] yield arity lambda?].freeze
|
|
69
|
+
private_constant :CALLABLE_ALLOW
|
|
70
|
+
|
|
56
71
|
# Dispatch a single transport request and return the encoded
|
|
57
72
|
# Response bytes ({docs/behavior.md B-12}[link:../../../docs/behavior.md]).
|
|
58
73
|
# Invoked from the +Runtime#on_dispatch+ Proc that
|
|
@@ -131,14 +146,18 @@ module Kobako
|
|
|
131
146
|
end
|
|
132
147
|
|
|
133
148
|
# Guard the +public_send+ below against ambient reflection methods
|
|
134
|
-
# (
|
|
135
|
-
#
|
|
136
|
-
#
|
|
137
|
-
#
|
|
138
|
-
#
|
|
149
|
+
# ({docs/behavior.md B-42}[link:../../../docs/behavior.md]). A public
|
|
150
|
+
# method whose owner is a {META_OWNERS} or {GADGET_OWNERS} module is
|
|
151
|
+
# rejected, except {CALLABLE_ALLOW} on a gadget target (a bound lambda
|
|
152
|
+
# stays invocable). A name with no concrete public method is allowed
|
|
153
|
+
# only when the target opts into it via +respond_to?+ (dynamic
|
|
154
|
+
# +method_missing+ Services), since the dangerous methods are all
|
|
155
|
+
# concretely defined and therefore never reach that branch.
|
|
139
156
|
def reject_meta_method!(target, name)
|
|
140
157
|
owner = target.public_method(name).owner
|
|
141
|
-
|
|
158
|
+
gadget = GADGET_OWNERS.include?(owner)
|
|
159
|
+
return unless META_OWNERS.include?(owner) || gadget
|
|
160
|
+
return if gadget && CALLABLE_ALLOW.include?(name)
|
|
142
161
|
|
|
143
162
|
raise UndefinedTargetError, "method #{name.inspect} is not a Service method"
|
|
144
163
|
rescue NameError
|
|
@@ -5,16 +5,8 @@ require_relative "../codec"
|
|
|
5
5
|
|
|
6
6
|
module Kobako
|
|
7
7
|
# See lib/kobako/transport.rb for the umbrella module doc; this file
|
|
8
|
-
# owns the Request value object and its +#encode+ / +.decode+ codec
|
|
9
|
-
# plus the +STATUS_OK+ / +STATUS_ERROR+ constants shared with Response.
|
|
8
|
+
# owns the Request value object and its +#encode+ / +.decode+ codec.
|
|
10
9
|
module Transport
|
|
11
|
-
# ---------------- Response status bytes (docs/wire-contract.md § Response Shape) ---
|
|
12
|
-
|
|
13
|
-
# Response variant marker for the success branch.
|
|
14
|
-
STATUS_OK = 0
|
|
15
|
-
# Response variant marker for the fault branch.
|
|
16
|
-
STATUS_ERROR = 1
|
|
17
|
-
|
|
18
10
|
# Value object for a single guest-initiated Transport Request
|
|
19
11
|
# ({docs/wire-codec.md Envelope Encoding → Request}[link:../../../docs/wire-codec.md]).
|
|
20
12
|
#
|
|
@@ -2,12 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "../codec"
|
|
4
4
|
require_relative "../fault"
|
|
5
|
-
require_relative "request"
|
|
6
5
|
|
|
7
6
|
module Kobako
|
|
8
7
|
# See lib/kobako/transport.rb for the umbrella module doc; this file
|
|
9
|
-
# owns the Response value object and its +#encode+ / +.decode+ codec
|
|
8
|
+
# owns the Response value object and its +#encode+ / +.decode+ codec,
|
|
9
|
+
# plus the +STATUS_OK+ / +STATUS_ERROR+ status bytes.
|
|
10
10
|
module Transport
|
|
11
|
+
# ---------------- Response status bytes (docs/wire-contract.md § Response Shape) ---
|
|
12
|
+
|
|
13
|
+
# Response variant marker for the success branch.
|
|
14
|
+
STATUS_OK = 0
|
|
15
|
+
# Response variant marker for the fault branch.
|
|
16
|
+
STATUS_ERROR = 1
|
|
17
|
+
|
|
11
18
|
# Value object for a single host-side Transport Response
|
|
12
19
|
# ({docs/wire-codec.md Envelope Encoding → Response}[link:../../../docs/wire-codec.md]).
|
|
13
20
|
#
|
data/lib/kobako/version.rb
CHANGED
data/release-please-config.json
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
module Kobako
|
|
2
2
|
module Catalog
|
|
3
3
|
class Handles
|
|
4
|
+
UNWRAPPABLE_TYPES: Array[Module]
|
|
5
|
+
|
|
4
6
|
def initialize: (?next_id: Integer) -> void
|
|
5
7
|
|
|
6
8
|
def alloc: (untyped object) -> Kobako::Handle
|
|
@@ -13,6 +15,10 @@ module Kobako
|
|
|
13
15
|
|
|
14
16
|
private
|
|
15
17
|
|
|
18
|
+
def reject_unwrappable!: (untyped object) -> void
|
|
19
|
+
|
|
20
|
+
def ensure_capacity!: () -> void
|
|
21
|
+
|
|
16
22
|
def require_bound!: (Integer id) -> void
|
|
17
23
|
end
|
|
18
24
|
end
|
|
@@ -8,6 +8,10 @@ module Kobako
|
|
|
8
8
|
|
|
9
9
|
META_OWNERS: Array[Module]
|
|
10
10
|
|
|
11
|
+
GADGET_OWNERS: Array[Module]
|
|
12
|
+
|
|
13
|
+
CALLABLE_ALLOW: Array[Symbol]
|
|
14
|
+
|
|
11
15
|
def self?.dispatch: (String request_bytes, Kobako::Catalog::Namespaces namespaces, Kobako::Catalog::Handles handler, ^(String) -> String yield_to_guest) -> String
|
|
12
16
|
|
|
13
17
|
def self?.resolve_call_args: (Kobako::Transport::Request request, Kobako::Catalog::Handles handler) -> [Array[untyped], Hash[Symbol, untyped]]
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kobako
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.9.
|
|
4
|
+
version: 0.9.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Aotokitsuruya
|
|
@@ -58,6 +58,7 @@ files:
|
|
|
58
58
|
- ext/kobako/extconf.rb
|
|
59
59
|
- ext/kobako/src/lib.rs
|
|
60
60
|
- ext/kobako/src/runtime.rs
|
|
61
|
+
- ext/kobako/src/runtime/ambient.rs
|
|
61
62
|
- ext/kobako/src/runtime/cache.rs
|
|
62
63
|
- ext/kobako/src/runtime/capture.rs
|
|
63
64
|
- ext/kobako/src/runtime/config.rs
|