kobako 0.11.0-x86_64-linux → 0.11.2-x86_64-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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 88cfe63025113640b86313e0db4764e075df080db27c2d46a41f3437a9665748
4
- data.tar.gz: 2fea087aa65fbf8a56ab9ac6d4cb040c02c920095e2e024894419f9094df3a62
3
+ metadata.gz: 1cbf315e79e4ac7f8de90374553441ad92e118cf4bd6f8488274b5034586265d
4
+ data.tar.gz: 5a6812ef28f479cdbdd6a075bc644252a598f5897edd4344bf90629ada4fca12
5
5
  SHA512:
6
- metadata.gz: eba4996867c874cfbbe5170420637f9fb8743cd68e7a5e0fc5bc63af5afbb9b8303cb3388f4808c1d6c699357a2f411e55040ef1ab23b4878c4fac3e18403063
7
- data.tar.gz: e4ab4f98eff567fb86415365099d6d11e7857be4146c5fa6ac3260ca8fca1c1c9de9e1b0cfde77a3aa2a1781409ccf76d0df3116505e22f81ecc75a2069dcb9a
6
+ metadata.gz: 7a9f4396ffa3c4a19e31add9bc6d188b058df8a5f1701070d59a903d0db1cfe57dbf6b19a0e49366f88961182b7830a5f85a7dd14c1bed24890c46dcb22dfa16
7
+ data.tar.gz: c660365459baf0609e08e21505919af61cb1044df86cc1f73dd12c5cef16a03c5c23b5dfceee46889e18f4a8b61d23109a675b9f8fc7a2fe72031e363e7214c9
@@ -1 +1 @@
1
- {".":"0.11.0","wasm/kobako-core":"0.5.0","wasm/kobako":"0.5.0","wasm/kobako-io":"0.5.0","wasm/kobako-regexp":"0.5.0","wasm/kobako-baker":"0.5.0"}
1
+ {".":"0.11.2","wasm/kobako-core":"0.5.2","wasm/kobako":"0.5.2","wasm/kobako-io":"0.5.2","wasm/kobako-regexp":"0.5.2","wasm/kobako-baker":"0.5.2"}
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.11.2](https://github.com/elct9620/kobako/compare/v0.11.1...v0.11.2) (2026-06-24)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **codec:** encode guest Handle args/kwargs as ext 0x01 ([bd58538](https://github.com/elct9620/kobako/commit/bd58538f4dbbf91a0927d15fd37f47abc761f8a6))
9
+ * **codec:** refuse out-of-range inbound integers instead of saturating ([f9e9184](https://github.com/elct9620/kobako/commit/f9e91845e0f28fecbb0867d8b70c871cd1feafea))
10
+ * **dispatch:** keep short method names intact across kwarg unpacking ([c6e4a6f](https://github.com/elct9620/kobako/commit/c6e4a6f268970c0c2d2851d3a23e3bec153dc56d))
11
+ * **release:** drop the group PR title pattern that breaks tagging ([d797350](https://github.com/elct9620/kobako/commit/d797350953c2de82df592d3c88e44155d3f076dc))
12
+ * **release:** scope publish triggers to each release's owning tag ([58508a1](https://github.com/elct9620/kobako/commit/58508a1e967799522b2674a989233d8619cabbc9))
13
+
14
+ ## [0.11.1](https://github.com/elct9620/kobako/compare/v0.11.0...v0.11.1) (2026-06-14)
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * **guest:** adopt beni 0.7.0 protected dispatch (B-51) ([c61655b](https://github.com/elct9620/kobako/commit/c61655bcead336d32a4b6ff7ff1b34c21cdfccd9))
20
+
3
21
  ## [0.11.0](https://github.com/elct9620/kobako/compare/v0.10.0...v0.11.0) (2026-06-13)
4
22
 
5
23
 
data/README.md CHANGED
@@ -329,7 +329,7 @@ forwards to another Service but never reads — while a named subset becomes an
329
329
 
330
330
  Guest code can name any `<Namespace>::<Member>` path, but a forged name only resolves to
331
331
  something you bound — the real authorization gate is this host-side allowlist. Give each
332
- trust context its own Sandbox, and see [`docs/security.md`](docs/security.md) for the rest
332
+ trust context its own Sandbox, and see [`docs/security-model.md`](docs/security-model.md) for the rest
333
333
  as security-design concerns: validating untrusted input, default-deny external effects,
334
334
  and controlling the return surface.
335
335
 
data/SECURITY.md ADDED
@@ -0,0 +1,35 @@
1
+ # Security Policy
2
+
3
+ kobako runs untrusted guest code inside an in-process Wasm sandbox, so a break in
4
+ its isolation boundary is treated as a security issue. This file is about **reporting
5
+ such an issue**; for how the boundary is meant to work and where your
6
+ responsibilities as a host begin, see [`docs/security-model.md`](docs/security-model.md).
7
+
8
+ ## Supported versions
9
+
10
+ kobako is pre-1.0. Security fixes land on the latest released `0.x` version only;
11
+ upgrade to it before reporting.
12
+
13
+ ## Reporting a vulnerability
14
+
15
+ Report privately through GitHub's **[Report a vulnerability](https://github.com/elct9620/kobako/security/advisories/new)**
16
+ flow — please do not open a public issue or pull request for a suspected vulnerability.
17
+
18
+ Include the affected version, a minimal guest script or host setup that reproduces the
19
+ issue, and what boundary you expected to hold. You can expect an initial acknowledgement
20
+ within a few days; once a fix or mitigation is agreed, disclosure is coordinated through
21
+ a GitHub Security Advisory. Reporters are credited in the published advisory unless you
22
+ ask to stay anonymous.
23
+
24
+ ## Scope
25
+
26
+ In scope is anything that lets guest code cross the isolation boundary it should not:
27
+ reaching host memory, the filesystem, the network, or `ENV`; obtaining ambient time or
28
+ entropy the host froze; reaching a `Namespace::Member` you never bound; or a
29
+ memory-safety fault in the host codec or wasmtime driver.
30
+
31
+ Out of scope is what a bound Service is *designed* to expose: if guest code reaches a
32
+ method because you bound an object carrying it, that is a host-side authorization
33
+ choice, not a sandbox escape — narrow the bound surface as described in the security
34
+ model. Resource exhaustion that stays within the limits you configured is likewise
35
+ expected behaviour, not a vulnerability.
data/data/kobako.wasm CHANGED
Binary file
Binary file
Binary file
Binary file
@@ -43,9 +43,9 @@ module Kobako
43
43
  # and the allocator share the same invariant.
44
44
  #
45
45
  # Returning a Handle (rather than a bare Integer id) keeps the
46
- # allocator's output a domain entity; +Kobako::Handle.restore+
47
- # is reserved for the codec's wire-decode path, where the id is
48
- # the only thing the bytes carry.
46
+ # allocator's output a domain entity. An id is the Handle's only
47
+ # content, so the same internal +Kobako::Handle.restore+ constructor
48
+ # serves both this allocator and the codec's wire-decode path.
49
49
  def alloc(object)
50
50
  reject_unwrappable!(object)
51
51
  ensure_capacity!
@@ -72,7 +72,7 @@ module Kobako
72
72
  end
73
73
 
74
74
  # Number of currently-bound entries. Used by tests of the Dispatcher
75
- # and Codec::Utils#deep_wrap to observe whether each path allocates
75
+ # and Codec::HandleWalk#deep_wrap to observe whether each path allocates
76
76
  # exactly the Handle entries it should — the +Handles+ table itself never
77
77
  # consults its own size, but the surrounding code's allocation
78
78
  # contract is part of the observable boundary.
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../handle"
4
+
5
+ module Kobako
6
+ module Codec
7
+ # Substitutes Capability Handles into and out of a Ruby value tree at
8
+ # the host↔guest boundary. {deep_wrap} allocates a +Kobako::Handle+ for
9
+ # each non-wire-representable leaf on the host→guest +#run+ argument
10
+ # path; {deep_restore} resolves each wire-decoded Handle back to its
11
+ # host object on every guest→host value path — the +#eval+ / +#run+
12
+ # result and the yield-block result alike. {representable?} is the
13
+ # by-value codec-type predicate that decides which leaves {deep_wrap}
14
+ # must wrap: the closed 12-entry wire type set
15
+ # ({docs/wire-codec.md}[link:../../../docs/wire-codec.md] § Type
16
+ # Mapping).
17
+ #
18
+ # All helpers are pure except {deep_wrap}, whose only side effect is
19
+ # allocating new Handle ids into the supplied table.
20
+ module HandleWalk
21
+ module_function
22
+
23
+ # Inclusive Integer range the msgpack gem encodes without raising
24
+ # +RangeError+ at encode time — signed +int 64+ minimum through
25
+ # unsigned +uint 64+ maximum
26
+ # ({docs/wire-codec.md}[link:../../../docs/wire-codec.md] § Type
27
+ # Mapping #3, the +fixint+ / +int 8..64+ / +uint 8..64+ union).
28
+ # Anchored as a +Range+ so {primitive_type?} stays a single
29
+ # dispatch line. This is the codec's encode domain — not to
30
+ # be confused with the Handle id range, which lives on
31
+ # +Kobako::Handle+ as +MIN_ID+ / +MAX_ID+ (1..2^31 − 1) and
32
+ # represents a different concept entirely.
33
+ MSGPACK_INT_RANGE = (-(2**63)..((2**64) - 1))
34
+
35
+ # Codec-type predicate
36
+ # ({docs/wire-codec.md}[link:../../../docs/wire-codec.md] § Type
37
+ # Mapping). Returns +true+ when +value+ belongs to the closed
38
+ # 12-entry codec type set — +nil+, +TrueClass+, +FalseClass+,
39
+ # +Integer+ (in the +i64..u64+ value domain), +Float+, +String+,
40
+ # +Symbol+, +Kobako::Handle+, +Array+ whose every element is itself
41
+ # representable, or +Hash+ whose every key and value are
42
+ # representable. Integers outside the codec's signed-64 /
43
+ # unsigned-64 union are rejected so the predicate agrees with the
44
+ # msgpack gem's encode-time +RangeError+ behaviour the codec
45
+ # already surfaces as {UnsupportedType}.
46
+ def representable?(value)
47
+ primitive_type?(value) || container_representable?(value)
48
+ end
49
+
50
+ # Deep-walk Array / Hash containers in +value+ and replace every
51
+ # leaf that fails {representable?} with a +Kobako::Handle+
52
+ # allocated from +handler+. The
53
+ # walk only descends through representable container shapes
54
+ # (Array, Hash) one structural level at a time; a non-representable
55
+ # leaf is wrapped as-is without inspecting its internal structure.
56
+ # An existing +Kobako::Handle+ is representable and passes through
57
+ # unchanged — auto-wrap never re-wraps a Handle.
58
+ #
59
+ # +value+ may be any Ruby value; +handler+ must respond to
60
+ # +#alloc(object) -> Kobako::Handle+ (a host-side
61
+ # +Kobako::Catalog::Handles+). Returns a structurally equivalent value
62
+ # whose leaves are either representable or +Kobako::Handle+
63
+ # tokens.
64
+ #
65
+ # The block bodies spell +HandleWalk.deep_wrap+ explicitly rather
66
+ # than the unqualified +deep_wrap+ because +module_function+ makes
67
+ # the instance copy of these helpers private; an implicit receiver
68
+ # inside a block would resolve against the enclosing +self+
69
+ # (still +HandleWalk+ at definition time, but the qualified form
70
+ # keeps the dispatch readable when the recursive call sits inside a
71
+ # Proc captured from elsewhere).
72
+ def deep_wrap(value, handler)
73
+ case value
74
+ when ::Array then value.map { |element| HandleWalk.deep_wrap(element, handler) }
75
+ when ::Hash then value.transform_values { |val| HandleWalk.deep_wrap(val, handler) }
76
+ else
77
+ representable?(value) ? value : handler.alloc(value)
78
+ end
79
+ end
80
+
81
+ # Deep-walk Array / Hash containers in +value+ and replace every
82
+ # +Kobako::Handle+ leaf with the host-side object +handler+ resolves
83
+ # it to. The symmetric inverse of {deep_wrap}: that walk allocates objects
84
+ # into Handles on the host→guest argument path; this walk resolves
85
+ # Handles back to their objects on every guest→host value path — the
86
+ # +#eval+ / +#run+ result and the yield-block result alike. The walk
87
+ # descends through Array elements and Hash keys and values one
88
+ # structural level at a time; any non-Handle leaf passes through
89
+ # unchanged.
90
+ #
91
+ # +value+ is a decoded Ruby value (a Handle here is a wire-decoded
92
+ # +Kobako::Handle+, never a guest-forged one); +handler+ must
93
+ # respond to +#fetch(id) -> object+ (a host-side
94
+ # +Kobako::Catalog::Handles+). +handler.fetch+ raises
95
+ # +Kobako::SandboxError+ for an id with no live binding, the
96
+ # corrupted-runtime fallback.
97
+ def deep_restore(value, handler)
98
+ case value
99
+ when ::Array then value.map { |element| HandleWalk.deep_restore(element, handler) }
100
+ when ::Hash
101
+ value.to_h { |key, val| [HandleWalk.deep_restore(key, handler), HandleWalk.deep_restore(val, handler)] }
102
+ when Kobako::Handle then handler.fetch(value.id)
103
+ else value
104
+ end
105
+ end
106
+
107
+ # The non-container branch of {representable?}: returns +true+ for
108
+ # the scalar leaves and an existing Handle. Not part of the
109
+ # public surface; reach for {representable?} instead.
110
+ def primitive_type?(value)
111
+ case value
112
+ when ::NilClass, ::TrueClass, ::FalseClass, ::Float, ::String, ::Symbol, Kobako::Handle then true
113
+ when ::Integer then MSGPACK_INT_RANGE.cover?(value)
114
+ else false
115
+ end
116
+ end
117
+
118
+ # The container branch of {representable?}: recurses into Array
119
+ # elements and Hash key+value pairs through the public
120
+ # {representable?}. Not part of the public surface; reach for
121
+ # {representable?} instead.
122
+ def container_representable?(value)
123
+ case value
124
+ when ::Array then value.all? { |element| HandleWalk.representable?(element) }
125
+ when ::Hash then value.all? { |key, val| HandleWalk.representable?(key) && HandleWalk.representable?(val) }
126
+ else false
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -1,12 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "error"
4
- require_relative "../handle"
5
4
 
6
5
  module Kobako
7
6
  module Codec
8
- # Codec helpers shared by the host-side encoders and decoders.
9
- # Three concerns live here today:
7
+ # Byte-boundary helpers shared by the host-side encoder and decoder.
8
+ # Two concerns live here:
10
9
  #
11
10
  # - UTF-8 assertion at the codec boundary
12
11
  # ({docs/wire-codec.md}[link:../../../docs/wire-codec.md]
@@ -16,14 +15,9 @@ module Kobako
16
15
  # - +ArgumentError+ translation at the codec boundary
17
16
  # ({with_boundary}) so the public taxonomy stays
18
17
  # {Kobako::Codec::Error}.
19
- # - Representability predicate ({representable?}) and the symmetric
20
- # host→guest +#run+ argument walk ({deep_wrap}) used by
21
- # +Kobako::Transport::Run#encode+ to route non-representable leaves
22
- # through the Sandbox's +Kobako::Catalog::Handles+.
23
18
  #
24
- # All helpers are pure — they only inspect inputs, never mutate
25
- # them except {deep_wrap}, whose only side effect is allocating
26
- # new Handle ids into the supplied table.
19
+ # Both helpers are pure — they only inspect inputs, never mutate them.
20
+ # The host↔guest Handle substitution walk lives in {HandleWalk}.
27
21
  module Utils
28
22
  module_function
29
23
 
@@ -53,113 +47,6 @@ module Kobako
53
47
  rescue ::ArgumentError => e
54
48
  raise InvalidType, e.message
55
49
  end
56
-
57
- # Inclusive Integer range the msgpack gem encodes without raising
58
- # +RangeError+ at encode time — signed +int 64+ minimum through
59
- # unsigned +uint 64+ maximum
60
- # ({docs/wire-codec.md}[link:../../../docs/wire-codec.md] § Type
61
- # Mapping #3, the +fixint+ / +int 8..64+ / +uint 8..64+ union).
62
- # Anchored as a +Range+ so {primitive_type?} stays a single
63
- # dispatch line. This is the codec's encode domain — not to
64
- # be confused with the Handle id range, which lives on
65
- # +Kobako::Handle+ as +MIN_ID+ / +MAX_ID+ (1..2^31 − 1) and
66
- # represents a different concept entirely.
67
- MSGPACK_INT_RANGE = (-(2**63)..((2**64) - 1))
68
-
69
- # Codec-type predicate
70
- # ({docs/wire-codec.md}[link:../../../docs/wire-codec.md] § Type
71
- # Mapping). Returns +true+ when +value+ belongs to the closed
72
- # 12-entry codec type set — +nil+, +TrueClass+, +FalseClass+,
73
- # +Integer+ (in the +i64..u64+ value domain), +Float+, +String+,
74
- # +Symbol+, +Kobako::Handle+, +Array+ whose every element is itself
75
- # representable, or +Hash+ whose every key and value are
76
- # representable. Integers outside the codec's signed-64 /
77
- # unsigned-64 union are rejected so the predicate agrees with the
78
- # msgpack gem's encode-time +RangeError+ behaviour the codec
79
- # already surfaces as {UnsupportedType}.
80
- def representable?(value)
81
- primitive_type?(value) || container_representable?(value)
82
- end
83
-
84
- # Deep-walk Array / Hash containers in +value+ and replace every
85
- # leaf that fails {representable?} with a +Kobako::Handle+
86
- # allocated from +handler+. The
87
- # walk only descends through representable container shapes
88
- # (Array, Hash) one structural level at a time; a non-representable
89
- # leaf is wrapped as-is without inspecting its internal structure.
90
- # An existing +Kobako::Handle+ is representable and passes through
91
- # unchanged — auto-wrap never re-wraps a Handle.
92
- #
93
- # +value+ may be any Ruby value; +handler+ must respond to
94
- # +#alloc(object) -> Kobako::Handle+ (a host-side
95
- # +Kobako::Catalog::Handles+). Returns a structurally equivalent value
96
- # whose leaves are either representable or +Kobako::Handle+
97
- # tokens.
98
- #
99
- # The block bodies spell +Utils.deep_wrap+ explicitly rather than
100
- # the unqualified +deep_wrap+ because +module_function+ makes the
101
- # instance copy of these helpers private; an implicit receiver
102
- # inside a block would resolve against the enclosing +self+
103
- # (still +Utils+ at definition time, but the qualified form keeps
104
- # the dispatch readable when the recursive call sits inside a
105
- # Proc captured from elsewhere).
106
- def deep_wrap(value, handler)
107
- case value
108
- when ::Array then value.map { |element| Utils.deep_wrap(element, handler) }
109
- when ::Hash then value.transform_values { |val| Utils.deep_wrap(val, handler) }
110
- else
111
- representable?(value) ? value : handler.alloc(value)
112
- end
113
- end
114
-
115
- # Deep-walk Array / Hash containers in +value+ and replace every
116
- # +Kobako::Handle+ leaf with the host-side object +handler+ resolves
117
- # it to. The symmetric inverse of {deep_wrap}: that walk allocates objects
118
- # into Handles on the host→guest argument path; this walk resolves
119
- # Handles back to their objects on every guest→host value path — the
120
- # +#eval+ / +#run+ result and the yield-block result alike. The walk
121
- # descends through Array elements and Hash keys and values one
122
- # structural level at a time; any non-Handle leaf passes through
123
- # unchanged.
124
- #
125
- # +value+ is a decoded Ruby value (a Handle here is a wire-decoded
126
- # +Kobako::Handle+, never a guest-forged one); +handler+ must
127
- # respond to +#fetch(id) -> object+ (a host-side
128
- # +Kobako::Catalog::Handles+). +handler.fetch+ raises
129
- # +Kobako::SandboxError+ for an id with no live binding, the
130
- # corrupted-runtime fallback.
131
- def deep_restore(value, handler)
132
- case value
133
- when ::Array then value.map { |element| Utils.deep_restore(element, handler) }
134
- when ::Hash
135
- value.to_h { |key, val| [Utils.deep_restore(key, handler), Utils.deep_restore(val, handler)] }
136
- when Kobako::Handle then handler.fetch(value.id)
137
- else value
138
- end
139
- end
140
-
141
- # The non-container branch of {representable?}: returns +true+ for
142
- # the scalar leaves and an existing Handle. Not part of the
143
- # public surface; reach for {representable?} instead.
144
- def primitive_type?(value)
145
- case value
146
- when ::NilClass, ::TrueClass, ::FalseClass, ::Float, ::String, ::Symbol, Kobako::Handle then true
147
- when ::Integer then MSGPACK_INT_RANGE.cover?(value)
148
- else false
149
- end
150
- end
151
-
152
- # The container branch of {representable?}: recurses into Array
153
- # elements and Hash key+value pairs through the public
154
- # {representable?}. Not part of the public surface; reach for
155
- # {representable?} instead.
156
- def container_representable?(value)
157
- case value
158
- when ::Array then value.all? { |element| Utils.representable?(element) }
159
- when ::Hash then value.all? { |key, val| Utils.representable?(key) && Utils.representable?(val) }
160
- else false
161
- end
162
- end
163
50
  end
164
51
  end
165
52
  end
data/lib/kobako/codec.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "codec/error"
4
4
  require_relative "codec/utils"
5
+ require_relative "codec/handle_walk"
5
6
  require_relative "codec/factory"
6
7
  require_relative "codec/encoder"
7
8
  require_relative "codec/decoder"
data/lib/kobako/handle.rb CHANGED
@@ -17,7 +17,7 @@ module Kobako
17
17
  # fields on raised error objects. The Host Gem itself constructs
18
18
  # Handles through {.restore}, which exists at exactly two call
19
19
  # sites: +Kobako::Codec::Factory#unpack_handle+ (wire decode) and
20
- # +Kobako::Codec::Utils.deep_wrap+ / +Kobako::Transport::Dispatcher#wrap_as_handle+
20
+ # +Kobako::Codec::HandleWalk.deep_wrap+ / +Kobako::Transport::Dispatcher#wrap_as_handle+
21
21
  # (allocator paths). Both live inside +lib/kobako/+ and are not part
22
22
  # of any public surface.
23
23
  #
@@ -14,13 +14,6 @@ module Kobako
14
14
  # +Kobako::Outcome::Panic+. The byte-level msgpack codec at
15
15
  # +Kobako::Codec+ is invoked for the body itself; otherwise
16
16
  # nothing in +Transport+ participates.
17
- #
18
- # * tag 0x01, decode OK → return decoded value
19
- # * tag 0x01, decode fails → SandboxError
20
- # * tag 0x02, origin="service" → ServiceError
21
- # * tag 0x02, origin="sandbox"/missing → SandboxError
22
- # * tag 0x02, decode fails → SandboxError
23
- # * unknown tag → TrapError
24
17
  module Outcome
25
18
  # First byte of the OUTCOME_BUFFER for the success branch — body is
26
19
  # the bare msgpack encoding of the returned value
@@ -47,9 +40,8 @@ module Kobako
47
40
  # TrapError for unknown or absent tag
48
41
  # ({docs/wire-codec.md ABI Signatures}[link:../../docs/wire-codec.md]:
49
42
  # zero-length output and unrecognised first byte both walk the trap
50
- # path). The user-facing message stays in caller vocabulary — the
51
- # raw tag byte (or absence) belongs in +details+ for operators, not
52
- # in the message a caller sees.
43
+ # path). The absent-vs-present distinction selects the message;
44
+ # the raw byte is not actionable to a caller and is not surfaced.
53
45
  def build_trap_error(tag)
54
46
  if tag.nil?
55
47
  TrapError.new("Sandbox exited without producing a result")
@@ -289,7 +289,7 @@ module Kobako
289
289
  # token; restore it to the host object the guest referenced before
290
290
  # handing the value to the Host App. @handler still holds this
291
291
  # invocation's table — reset only happens at the next #begin_invocation!.
292
- Codec::Utils.deep_restore(Outcome.decode(snapshot.return_bytes), @handler)
292
+ Codec::HandleWalk.deep_restore(Outcome.decode(snapshot.return_bytes), @handler)
293
293
  rescue Kobako::TrapError => e
294
294
  raise trap_class_for(e), "Sandbox##{verb} failed: #{e.message}"
295
295
  ensure
@@ -100,13 +100,9 @@ module Kobako
100
100
  end
101
101
 
102
102
  # Map an error caught at the dispatch boundary to a +Response.error+
103
- # envelope. +error+ is the +StandardError+ caught by {#dispatch}'s
104
- # rescue. Returns a msgpack-encoded Response envelope (binary). Four
105
- # error buckets:
106
- # +Kobako::Codec::Error+ → type="runtime" (malformed request);
107
- # +UndefinedTargetError+ → type="undefined"; +ArgumentError+ →
108
- # type="argument" (arity mismatch); everything else →
109
- # type="runtime".
103
+ # envelope (binary msgpack). +error+ is the +StandardError+ caught by
104
+ # {#dispatch}'s rescue; the +type+ field tells the guest which kind
105
+ # of failure it was so it can raise the matching proxy-side error.
110
106
  def encode_caught_error(error)
111
107
  case error
112
108
  when Kobako::Codec::Error then encode_error("runtime",
@@ -51,8 +51,8 @@ module Kobako
51
51
  # Encode this Run to the msgpack bytes the guest's +__kobako_run+
52
52
  # entry point consumes as its command-buffer payload
53
53
  # ({docs/wire-codec.md Invocation channels}[link:../../../docs/wire-codec.md]).
54
- # Walks +args+ / +kwargs+ through {Codec::Utils.deep_wrap} so any
55
- # non-wire-representable leaf is allocated into +handler+ and
54
+ # Walks +args+ / +kwargs+ through {Codec::HandleWalk.deep_wrap} so
55
+ # any non-wire-representable leaf is allocated into +handler+ and
56
56
  # replaced with a +Kobako::Handle+; the
57
57
  # +handler+ argument is the Sandbox's table, sharing the same
58
58
  # allocator the guest→host return path uses.
@@ -64,8 +64,8 @@ module Kobako
64
64
  def encode(handler)
65
65
  Codec::Encoder.encode(
66
66
  "entrypoint" => entrypoint,
67
- "args" => Codec::Utils.deep_wrap(args, handler),
68
- "kwargs" => Codec::Utils.deep_wrap(kwargs, handler)
67
+ "args" => Codec::HandleWalk.deep_wrap(args, handler),
68
+ "kwargs" => Codec::HandleWalk.deep_wrap(kwargs, handler)
69
69
  )
70
70
  end
71
71
 
@@ -82,7 +82,7 @@ module Kobako
82
82
  # Array / Hash one level at a time; a plain value passes through
83
83
  # unchanged.
84
84
  def restore(value)
85
- Kobako::Codec::Utils.deep_restore(value, @handler)
85
+ Kobako::Codec::HandleWalk.deep_restore(value, @handler)
86
86
  end
87
87
 
88
88
  # Reify a +YieldResponse+ tag 0x04 payload into a +RuntimeError+ the
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kobako
4
- VERSION = "0.11.0"
4
+ VERSION = "0.11.2"
5
5
  end
@@ -0,0 +1,17 @@
1
+ module Kobako
2
+ module Codec
3
+ module HandleWalk
4
+ MSGPACK_INT_RANGE: Range[Integer]
5
+
6
+ def self?.representable?: (untyped value) -> bool
7
+
8
+ def self?.deep_wrap: (untyped value, Kobako::Catalog::Handles handler) -> untyped
9
+
10
+ def self?.deep_restore: (untyped value, Kobako::Catalog::Handles handler) -> untyped
11
+
12
+ def self?.primitive_type?: (untyped value) -> bool
13
+
14
+ def self?.container_representable?: (untyped value) -> bool
15
+ end
16
+ end
17
+ end
@@ -1,21 +1,9 @@
1
1
  module Kobako
2
2
  module Codec
3
3
  module Utils
4
- MSGPACK_INT_RANGE: Range[Integer]
5
-
6
4
  def self?.assert_utf8!: (String string, String label) -> void
7
5
 
8
6
  def self?.with_boundary: [T] () { () -> T } -> T
9
-
10
- def self?.representable?: (untyped value) -> bool
11
-
12
- def self?.deep_wrap: (untyped value, Kobako::Catalog::Handles handler) -> untyped
13
-
14
- def self?.deep_restore: (untyped value, Kobako::Catalog::Handles handler) -> untyped
15
-
16
- def self?.primitive_type?: (untyped value) -> bool
17
-
18
- def self?.container_representable?: (untyped value) -> bool
19
7
  end
20
8
  end
21
9
  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.11.0
4
+ version: 0.11.2
5
5
  platform: x86_64-linux
6
6
  authors:
7
7
  - Aotokitsuruya
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-06-13 00:00:00.000000000 Z
11
+ date: 2026-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -37,6 +37,7 @@ files:
37
37
  - CHANGELOG.md
38
38
  - LICENSE
39
39
  - README.md
40
+ - SECURITY.md
40
41
  - data/kobako.wasm
41
42
  - lib/kobako.rb
42
43
  - lib/kobako/3.3/kobako.so
@@ -52,6 +53,7 @@ files:
52
53
  - lib/kobako/codec/encoder.rb
53
54
  - lib/kobako/codec/error.rb
54
55
  - lib/kobako/codec/factory.rb
56
+ - lib/kobako/codec/handle_walk.rb
55
57
  - lib/kobako/codec/utils.rb
56
58
  - lib/kobako/errors.rb
57
59
  - lib/kobako/fault.rb
@@ -90,6 +92,7 @@ files:
90
92
  - sig/kobako/codec/encoder.rbs
91
93
  - sig/kobako/codec/error.rbs
92
94
  - sig/kobako/codec/factory.rbs
95
+ - sig/kobako/codec/handle_walk.rbs
93
96
  - sig/kobako/codec/utils.rbs
94
97
  - sig/kobako/errors.rbs
95
98
  - sig/kobako/fault.rbs