kobako 0.23.0-aarch64-linux → 0.25.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 +71 -0
- data/README.md +19 -18
- data/ROADMAP.md +12 -12
- data/crates/kobako-runtime/CHANGELOG.md +7 -0
- data/crates/kobako-runtime/README.md +1 -1
- data/crates/kobako-transport/CHANGELOG.md +7 -0
- data/crates/kobako-transport/README.md +1 -1
- data/crates/kobako-wasmtime/CHANGELOG.md +9 -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/capture.rb +8 -22
- data/lib/kobako/catalog/handles.rb +33 -9
- data/lib/kobako/catalog/services.rb +9 -7
- data/lib/kobako/context.rb +8 -8
- data/lib/kobako/handle.rb +10 -40
- data/lib/kobako/sandbox.rb +5 -0
- data/lib/kobako/transport/dispatcher.rb +28 -26
- data/lib/kobako/transport/exposure.rb +100 -0
- data/lib/kobako/transport/reflection.rb +19 -20
- data/lib/kobako/transport.rb +4 -2
- data/lib/kobako/usage.rb +11 -22
- data/lib/kobako/version.rb +1 -1
- data/release-please-config.json +1 -1
- data/sig/kobako/catalog/handles.rbs +2 -0
- data/sig/kobako/catalog/services.rbs +1 -1
- data/sig/kobako/context.rbs +1 -1
- data/sig/kobako/transport/dispatcher.rbs +7 -7
- data/sig/kobako/transport/exposure.rbs +43 -0
- data/sig/kobako/transport/reflection.rbs +1 -3
- data/sig/kobako/transport.rbs +11 -1
- metadata +4 -2
data/lib/kobako/handle.rb
CHANGED
|
@@ -1,38 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Kobako
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# SPEC pins the binary layout to fixext 4 with a 4-byte big-endian u32
|
|
10
|
-
# payload ({docs/wire-codec.md}[link:../../docs/wire-codec.md]
|
|
11
|
-
# § Ext Types → ext 0x01). ID 0 is reserved as the invalid sentinel;
|
|
12
|
-
# the maximum valid ID is 0x7fff_ffff (2^31 - 1).
|
|
13
|
-
#
|
|
14
|
-
# The constructor is internal to the Host Gem. +Kobako::Handle.new+ is
|
|
15
|
-
# privatised so Host App code cannot fabricate a Handle from a bare
|
|
16
|
-
# integer; legitimate Handle instances enter Host App code only as
|
|
17
|
-
# fields on raised error objects. +#with+ — Data's copy-with-changes
|
|
18
|
-
# constructor — is removed for the same reason: a legitimate Handle
|
|
19
|
-
# must not derive a sibling with a caller-chosen id. The Host Gem itself constructs
|
|
20
|
-
# Handles through +.restore+, which exists at exactly two call
|
|
21
|
-
# sites: +Kobako::Codec::ExtTypes#unpack_handle+ (wire decode) and
|
|
22
|
-
# +Kobako::Codec::HandleWalk.deep_wrap+ / +Kobako::Transport::Dispatcher#wrap_as_handle+
|
|
23
|
-
# (allocator paths). Both live inside +lib/kobako/+ and are not part
|
|
24
|
-
# of any public surface.
|
|
25
|
-
#
|
|
26
|
-
# The mruby counterpart +Kobako::Handle+ lives inside the Wasm guest
|
|
27
|
-
# under the same canonical name and shares neither code nor instances
|
|
28
|
-
# with this host-side class.
|
|
4
|
+
# A Capability Handle as it crosses the wire (ext 0x01, laid out in
|
|
5
|
+
# {docs/wire-codec.md}[link:../../docs/wire-codec.md]), in either
|
|
6
|
+
# direction. Host App code cannot construct one: +.new+ is private and
|
|
7
|
+
# +#with+ removed, so no Handle is ever made from a caller-chosen id.
|
|
8
|
+
# The guest's +Kobako::Handle+ shares only the name.
|
|
29
9
|
class Handle < Data.define(:id)
|
|
30
|
-
#
|
|
31
|
-
# the invalid sentinel and is never allocated.
|
|
10
|
+
# ID 0 is the invalid sentinel and is never allocated.
|
|
32
11
|
MIN_ID = 1
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
# on either side of the wire without re-encoding.
|
|
12
|
+
# The positive half of a signed 32-bit integer, so an id fits either
|
|
13
|
+
# side of the wire unchanged.
|
|
36
14
|
MAX_ID = 0x7fff_ffff
|
|
37
15
|
|
|
38
16
|
def initialize(id:)
|
|
@@ -45,16 +23,8 @@ module Kobako
|
|
|
45
23
|
private_class_method :new
|
|
46
24
|
undef_method :with
|
|
47
25
|
|
|
48
|
-
# Host Gem
|
|
49
|
-
#
|
|
50
|
-
# invariant checks still run, while keeping the public +.new+
|
|
51
|
-
# privatised against Host App callers.
|
|
52
|
-
#
|
|
53
|
-
# Two collaborators call this: the codec when an ext 0x01 frame is
|
|
54
|
-
# decoded off the wire, and the allocator paths when a host-side
|
|
55
|
-
# Ruby object is registered into the Sandbox's +Catalog::Handles+. Both
|
|
56
|
-
# paths live inside +lib/kobako/+ and treat this method as a
|
|
57
|
-
# package-private constructor.
|
|
26
|
+
# The Host Gem's own constructor, for the wire decoder and the Handle
|
|
27
|
+
# allocator; it runs the same id checks +.new+ would.
|
|
58
28
|
def self.restore(id)
|
|
59
29
|
allocate.tap { |handle| handle.send(:initialize, id: id) }
|
|
60
30
|
end
|
data/lib/kobako/sandbox.rb
CHANGED
|
@@ -66,6 +66,11 @@ module Kobako
|
|
|
66
66
|
# (+"MyService::KV"+ or a top-level +"File"+). Returns +self+ for
|
|
67
67
|
# chaining.
|
|
68
68
|
#
|
|
69
|
+
# The guest reaches the public methods +object+'s own class and +object+
|
|
70
|
+
# itself define in source, fixed at this call — nothing inherited, mixed
|
|
71
|
+
# in, or built into the platform. An +object+ defining a private
|
|
72
|
+
# +respond_to_guest?(name)+ decides instead, asked on every call.
|
|
73
|
+
#
|
|
69
74
|
# Called with only a +path+, it declares a fillable Service:
|
|
70
75
|
# +bind(path)+ reserves the path for +Kobako::Unresolved+, so the guest
|
|
71
76
|
# sees the constant while the host defers the object it stands for. A
|
|
@@ -95,9 +95,9 @@ module Kobako
|
|
|
95
95
|
# so the reply-shaping and the failure boundary stay one glance wide.
|
|
96
96
|
def run(call, resolver, handler, yielder)
|
|
97
97
|
arguments, carried_handle = decode_arguments(call.payload)
|
|
98
|
-
|
|
98
|
+
exposure = resolve_target(call.target, resolver, handler)
|
|
99
99
|
args, kwargs = resolve_call_args(arguments, handler, carried_handle)
|
|
100
|
-
catch(BREAK_THROW) { invoke(
|
|
100
|
+
catch(BREAK_THROW) { invoke(exposure, call.method_name, args, kwargs, yielder) }
|
|
101
101
|
end
|
|
102
102
|
|
|
103
103
|
# Decode the Call's payload into its arguments, reporting whether any
|
|
@@ -150,20 +150,22 @@ module Kobako
|
|
|
150
150
|
fault("runtime", "#{error.class}: #{error.message}")
|
|
151
151
|
end
|
|
152
152
|
|
|
153
|
-
# Dispatch +method+ on
|
|
154
|
-
#
|
|
155
|
-
# the
|
|
156
|
-
#
|
|
157
|
-
#
|
|
153
|
+
# Dispatch +method+ on the object behind +exposure+, once the Exposure
|
|
154
|
+
# the guest's reference carries permits it. +kwargs+ is already
|
|
155
|
+
# Symbol-keyed (the +Payload::Arguments+ invariant pins it). The
|
|
156
|
+
# empty-kwargs branch omits the +**+ splat so Ruby 3.x's strict kwargs
|
|
157
|
+
# separation does not reject calls to no-kwarg methods when the wire
|
|
158
|
+
# carries the uniform empty-map shape.
|
|
158
159
|
#
|
|
159
160
|
# +yielder+ is the host-side Yielder materialised when the guest
|
|
160
161
|
# call site supplied a block; its Yielder#to_proc
|
|
161
162
|
# rides the +&block+ slot. +&nil+ is a no-op block argument in Ruby,
|
|
162
163
|
# so the same call site handles both cases without an explicit
|
|
163
164
|
# conditional.
|
|
164
|
-
def invoke(
|
|
165
|
+
def invoke(exposure, method, args, kwargs, yielder = nil)
|
|
165
166
|
name = method.to_sym
|
|
166
|
-
reject_unreachable!(
|
|
167
|
+
reject_unreachable!(exposure, name)
|
|
168
|
+
target = exposure.object
|
|
167
169
|
block = yielder&.to_proc
|
|
168
170
|
if kwargs.empty?
|
|
169
171
|
target.public_send(name, *args, &block)
|
|
@@ -173,12 +175,12 @@ module Kobako
|
|
|
173
175
|
end
|
|
174
176
|
|
|
175
177
|
# Guard the +public_send+ below: Reflection decides what counts as
|
|
176
|
-
# Service behaviour
|
|
177
|
-
# the guest's +undefined+ fault. Both the ambient-surface
|
|
178
|
-
# the
|
|
179
|
-
#
|
|
180
|
-
def reject_unreachable!(
|
|
181
|
-
reason = Reflection.refusal(
|
|
178
|
+
# Service behaviour through this reference, and its refusal reason
|
|
179
|
+
# becomes the guest's +undefined+ fault. Both the ambient-surface
|
|
180
|
+
# floor and the reference's Exposure answer through it, so a rejected
|
|
181
|
+
# name discloses nothing about which of the two refused.
|
|
182
|
+
def reject_unreachable!(exposure, name)
|
|
183
|
+
reason = Reflection.refusal(exposure, name)
|
|
182
184
|
raise UndefinedTargetError, reason if reason
|
|
183
185
|
end
|
|
184
186
|
|
|
@@ -192,18 +194,18 @@ module Kobako
|
|
|
192
194
|
raise UndefinedTargetError, e.message
|
|
193
195
|
end
|
|
194
196
|
|
|
195
|
-
# Resolve a Call target to the
|
|
196
|
-
# Catalog::Handles) holds. The native side already
|
|
197
|
-
# two forms off the core envelope's +kind+ tag: a
|
|
198
|
-
# constant's path, an Integer is a Capability Handle
|
|
199
|
-
# else-branch is needed — the envelope layer is the system
|
|
200
|
-
# that enforces the invariant.
|
|
197
|
+
# Resolve a Call target to the Exposure the path +resolver+ (or
|
|
198
|
+
# Catalog::Handles) holds for it. The native side already
|
|
199
|
+
# discriminated the two forms off the core envelope's +kind+ tag: a
|
|
200
|
+
# String is a bound constant's path, an Integer is a Capability Handle
|
|
201
|
+
# id. No else-branch is needed — the envelope layer is the system
|
|
202
|
+
# boundary that enforces the invariant.
|
|
201
203
|
def resolve_target(target, resolver, handler)
|
|
202
204
|
case target
|
|
203
205
|
when String
|
|
204
206
|
resolve_path(target, resolver)
|
|
205
207
|
when Integer
|
|
206
|
-
|
|
208
|
+
resolve_handle(target, handler)
|
|
207
209
|
end
|
|
208
210
|
end
|
|
209
211
|
|
|
@@ -213,10 +215,10 @@ module Kobako
|
|
|
213
215
|
raise UndefinedTargetError, e.message
|
|
214
216
|
end
|
|
215
217
|
|
|
216
|
-
# Resolve +id+
|
|
217
|
-
# surfaces as UndefinedTargetError.
|
|
218
|
-
def
|
|
219
|
-
handler.
|
|
218
|
+
# Resolve +id+ to the Exposure its Handle was minted with. An unknown
|
|
219
|
+
# id surfaces as UndefinedTargetError.
|
|
220
|
+
def resolve_handle(id, handler)
|
|
221
|
+
handler.exposure(id)
|
|
220
222
|
rescue Kobako::SandboxError => e
|
|
221
223
|
raise UndefinedTargetError, e.message
|
|
222
224
|
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "delegate"
|
|
4
|
+
|
|
5
|
+
require_relative "reflection"
|
|
6
|
+
|
|
7
|
+
module Kobako
|
|
8
|
+
module Transport
|
|
9
|
+
# The methods a host object lets the guest call through one reference
|
|
10
|
+
# to it — a bound path or a Capability Handle — fixed when the reference
|
|
11
|
+
# is made. An object defining its own private +respond_to_guest?(name)+
|
|
12
|
+
# is asked on every dispatch; any other exposes only what its own class
|
|
13
|
+
# and the object itself define in source, since the methods a Host App
|
|
14
|
+
# cannot foresee handing over are the ones it never wrote.
|
|
15
|
+
#
|
|
16
|
+
# Built on the +class X < Data.define(...)+ subclass form so the class
|
|
17
|
+
# body is fully Steep-visible; see +.rubocop.yml+ for the rationale.
|
|
18
|
+
class Exposure < Data.define(:object, :names)
|
|
19
|
+
PREDICATE = :respond_to_guest?
|
|
20
|
+
private_constant :PREDICATE
|
|
21
|
+
|
|
22
|
+
# Kernel's own reflection, bound onto each object so a forwarder or a
|
|
23
|
+
# BasicObject answers from its own method table rather than through
|
|
24
|
+
# +method_missing+ / +respond_to_missing?+.
|
|
25
|
+
CLASS_OF = Kernel.instance_method(:class)
|
|
26
|
+
SINGLETON_CLASS_OF = Kernel.instance_method(:singleton_class)
|
|
27
|
+
SINGLETON_METHODS = Kernel.instance_method(:singleton_methods)
|
|
28
|
+
PRIVATE_METHODS = Kernel.instance_method(:private_methods)
|
|
29
|
+
private_constant :CLASS_OF, :SINGLETON_CLASS_OF, :SINGLETON_METHODS, :PRIVATE_METHODS
|
|
30
|
+
|
|
31
|
+
CALLABLE = Set.new(Reflection::CALLABLE_ALLOW).freeze
|
|
32
|
+
NOTHING = Set.new.freeze
|
|
33
|
+
private_constant :CALLABLE, :NOTHING
|
|
34
|
+
|
|
35
|
+
# The Exposure +object+ carries from this moment on. +surfaces+ caches
|
|
36
|
+
# each class's own surface for a caller that makes many references at
|
|
37
|
+
# once (a Handle table), so two objects of one class enumerate it once.
|
|
38
|
+
def self.of(object, surfaces = {})
|
|
39
|
+
klass = CLASS_OF.bind_call(object)
|
|
40
|
+
names = narrows_itself?(object, klass) ? nil : default_names(object, klass, surfaces)
|
|
41
|
+
new(object: object, names: names)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Whether the guest may call +name+ through this reference. The
|
|
45
|
+
# object's own predicate is consulted with the private surface
|
|
46
|
+
# included, so the guest's +public_send+ can never reach it.
|
|
47
|
+
def exposes?(name)
|
|
48
|
+
return names.include?(name) if names
|
|
49
|
+
|
|
50
|
+
object.__send__(PREDICATE, name) ? true : false
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class << self
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
# Whether +object+ defines the narrowing predicate itself — read off
|
|
57
|
+
# the method tables, so a forwarder's target or a catch-all
|
|
58
|
+
# +respond_to_missing?+ cannot answer for it.
|
|
59
|
+
def narrows_itself?(object, klass)
|
|
60
|
+
klass.method_defined?(PREDICATE) || klass.private_method_defined?(PREDICATE) ||
|
|
61
|
+
PRIVATE_METHODS.bind_call(object, false).include?(PREDICATE) ||
|
|
62
|
+
SINGLETON_METHODS.bind_call(object, false).include?(PREDICATE)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# A callable keeps its callable names; a class-level surface or a
|
|
66
|
+
# forwarder has no surface of its own to expose.
|
|
67
|
+
def default_names(object, klass, surfaces)
|
|
68
|
+
case object
|
|
69
|
+
when Proc, Method then CALLABLE
|
|
70
|
+
when Module, Delegator then NOTHING
|
|
71
|
+
else with_singleton(object, surfaces[klass] ||= class_names(object, klass))
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def class_names(object, klass)
|
|
76
|
+
names = authored(klass)
|
|
77
|
+
case object
|
|
78
|
+
when Struct, Data then names.concat(object.members)
|
|
79
|
+
end
|
|
80
|
+
Set.new(names).freeze
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def with_singleton(object, names)
|
|
84
|
+
return names if SINGLETON_METHODS.bind_call(object, false).empty?
|
|
85
|
+
|
|
86
|
+
names.union(authored(SINGLETON_CLASS_OF.bind_call(object))).freeze
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# The public methods +owner+ itself defines in source. A method with
|
|
90
|
+
# no source, or whose source is the platform's own, is built in.
|
|
91
|
+
def authored(owner)
|
|
92
|
+
owner.public_instance_methods(false).select do |name|
|
|
93
|
+
file, = owner.instance_method(name).source_location
|
|
94
|
+
file && !file.start_with?("<internal:")
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -32,18 +32,19 @@ module Kobako
|
|
|
32
32
|
|
|
33
33
|
# The sole methods reachable on a GADGET_OWNERS target: invoking it
|
|
34
34
|
# (+call+ / +[]+ / +yield+) and the harmless +arity+ / +lambda?+
|
|
35
|
-
# describers that aid guest-side debugging.
|
|
35
|
+
# describers that aid guest-side debugging. Also the whole of what a
|
|
36
|
+
# callable exposes by default, so the floor and the Exposure agree.
|
|
36
37
|
CALLABLE_ALLOW = %i[call [] yield arity lambda?].freeze
|
|
37
|
-
private_constant :CALLABLE_ALLOW
|
|
38
38
|
|
|
39
39
|
module_function
|
|
40
40
|
|
|
41
|
-
# The reason +name+ is unreachable
|
|
42
|
-
# dispatch may proceed. Composes the ambient-surface floor with the
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
def refusal(
|
|
46
|
-
ambient_refusal(
|
|
41
|
+
# The reason +name+ is unreachable through +exposure+, or +nil+ when
|
|
42
|
+
# the dispatch may proceed. Composes the ambient-surface floor with the
|
|
43
|
+
# reference's Exposure, in that order: the Exposure only narrows and
|
|
44
|
+
# can never re-open what the floor rejects.
|
|
45
|
+
def refusal(exposure, name)
|
|
46
|
+
ambient_refusal(exposure.object, name) ||
|
|
47
|
+
(exposure.exposes?(name) ? nil : "method #{name.inspect} is not exposed to the guest")
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
# Guard against ambient reflection methods. A public method whose
|
|
@@ -55,7 +56,17 @@ module Kobako
|
|
|
55
56
|
# only when the target opts into it via +respond_to?+ (dynamic
|
|
56
57
|
# +method_missing+ Services), since the dangerous methods are all
|
|
57
58
|
# concretely defined and therefore never reach that branch.
|
|
59
|
+
#
|
|
60
|
+
# +method_missing+ named explicitly is refused whatever its owner:
|
|
61
|
+
# it is Ruby's dynamic-dispatch hook, and a public override (a
|
|
62
|
+
# +Delegator+) binds and calls the private method the guest passes as
|
|
63
|
+
# its first argument (+Kernel#system+). A dynamic +method_missing+
|
|
64
|
+
# Service is untouched — the guest reaches it by the virtual name,
|
|
65
|
+
# which resolves through the +NameError+ branch below, never by
|
|
66
|
+
# naming +method_missing+.
|
|
58
67
|
def ambient_refusal(target, name)
|
|
68
|
+
return "method #{name.inspect} is not a Service method" if name == :method_missing
|
|
69
|
+
|
|
59
70
|
owner = target.public_method(name).owner
|
|
60
71
|
return nil unless ambient_owner?(owner, target)
|
|
61
72
|
return nil if GADGET_OWNERS.include?(owner) && CALLABLE_ALLOW.include?(name)
|
|
@@ -79,18 +90,6 @@ module Kobako
|
|
|
79
90
|
GADGET_OWNERS.include?(owner) ||
|
|
80
91
|
(target.is_a?(Module) && owner.singleton_class?)
|
|
81
92
|
end
|
|
82
|
-
|
|
83
|
-
# Consult the target's opt-in narrowing predicate. A bound object may
|
|
84
|
-
# define a private +respond_to_guest?(name)+ to restrict which of its
|
|
85
|
-
# methods the guest reaches; a falsy answer refuses the dispatch. It
|
|
86
|
-
# is consulted with the private surface included so the guest's
|
|
87
|
-
# +public_send+ dispatch can never reach +respond_to_guest?+ itself.
|
|
88
|
-
def narrowing_refusal(target, name)
|
|
89
|
-
return nil unless target.respond_to?(:respond_to_guest?, true)
|
|
90
|
-
return nil if target.__send__(:respond_to_guest?, name)
|
|
91
|
-
|
|
92
|
-
"method #{name.inspect} is not exposed to the guest"
|
|
93
|
-
end
|
|
94
93
|
end
|
|
95
94
|
end
|
|
96
95
|
end
|
data/lib/kobako/transport.rb
CHANGED
|
@@ -4,6 +4,7 @@ require_relative "transport/call"
|
|
|
4
4
|
require_relative "transport/run"
|
|
5
5
|
require_relative "transport/yielder"
|
|
6
6
|
require_relative "transport/error"
|
|
7
|
+
require_relative "transport/exposure"
|
|
7
8
|
require_relative "transport/reflection"
|
|
8
9
|
require_relative "transport/dispatcher"
|
|
9
10
|
|
|
@@ -12,8 +13,9 @@ module Kobako
|
|
|
12
13
|
# host side of one Call/Reply exchange: the call value objects +Call+
|
|
13
14
|
# (guest→host, as the native side decoded it) and +Run+ (host→guest), the
|
|
14
15
|
# +Dispatcher+ that answers a routed Call, the +Yielder+ that re-enters
|
|
15
|
-
# the guest for a block, the +Reflection+ floor a dispatch must clear,
|
|
16
|
-
# +
|
|
16
|
+
# the guest for a block, the +Reflection+ floor a dispatch must clear, the
|
|
17
|
+
# +Exposure+ each reference authorizes a call against, and +Error+ for a
|
|
18
|
+
# wire violation the host detects. Each invocation's
|
|
17
19
|
# +Context+ composes them into the dispatch +Proc+ it passes +Runtime+ for
|
|
18
20
|
# that run.
|
|
19
21
|
#
|
data/lib/kobako/usage.rb
CHANGED
|
@@ -1,30 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Kobako
|
|
4
|
-
#
|
|
5
|
-
#
|
|
4
|
+
# What one invocation spent against its caps, measured the way the caps
|
|
5
|
+
# measure it:
|
|
6
6
|
#
|
|
7
|
-
# * +wall_time+ —
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# readout — is excluded.
|
|
14
|
-
# * +memory_peak+ — the Integer high-water mark, in bytes, of the
|
|
15
|
-
# per-invocation +memory.grow+ delta past the linear-memory size
|
|
16
|
-
# captured at invocation entry. Same baseline accounting as
|
|
17
|
-
# +memory_limit+: the mruby image's initial allocation and any
|
|
18
|
-
# prior-invocation watermark sit outside the measurement. On
|
|
19
|
-
# +MemoryLimitError+ +memory_peak+ never exceeds the configured
|
|
20
|
-
# cap because the rejected +desired+ value is not promoted into
|
|
21
|
-
# the high-water.
|
|
7
|
+
# * +wall_time+ — Float seconds inside the guest, the span the
|
|
8
|
+
# +timeout+ deadline governs; Service callbacks count, reading the
|
|
9
|
+
# result and the captures afterwards does not.
|
|
10
|
+
# * +memory_peak+ — Integer bytes of memory the invocation grew,
|
|
11
|
+
# against the same baseline as +memory_limit+; it never exceeds the
|
|
12
|
+
# cap, even when the cap was hit.
|
|
22
13
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
# after rescuing a trap to diagnose how much of the budget the failing
|
|
27
|
-
# invocation consumed.
|
|
14
|
+
# Filled on every outcome, traps included, so a Host App that rescues a
|
|
15
|
+
# trap can read from the error's +#execution+ how much of the budget the
|
|
16
|
+
# invocation used.
|
|
28
17
|
#
|
|
29
18
|
# Built on the +class X < Data.define(...)+ subclass form (the
|
|
30
19
|
# Steep-friendly shape — see +.rubocop.yml+ for the rationale).
|
data/lib/kobako/version.rb
CHANGED
data/release-please-config.json
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
"last-release-sha": "98509af508988f708bf0d7a76a718bb0428a177e",
|
|
6
6
|
"packages": {
|
|
7
7
|
".": {
|
|
8
|
-
"component": "kobako",
|
|
9
8
|
"include-component-in-tag": false,
|
|
10
9
|
"release-type": "ruby",
|
|
10
|
+
"version-file": "lib/kobako/version.rb",
|
|
11
11
|
"exclude-paths": ["wasm", "crates"]
|
|
12
12
|
},
|
|
13
13
|
"wasm/kobako-core": {
|
data/sig/kobako/context.rbs
CHANGED
|
@@ -9,7 +9,7 @@ module Kobako
|
|
|
9
9
|
|
|
10
10
|
def bind: (Symbol | String path, untyped object) -> self
|
|
11
11
|
|
|
12
|
-
def lookup: (Symbol | String path) ->
|
|
12
|
+
def lookup: (Symbol | String path) -> Kobako::Transport::Exposure
|
|
13
13
|
|
|
14
14
|
def eval: (String code) ?{ (Kobako::Context) -> void } -> Kobako::Execution
|
|
15
15
|
|
|
@@ -14,9 +14,9 @@ module Kobako
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
def self?.dispatch: (Kobako::Transport::Call call, Kobako::Transport::_ServiceRegistry resolver, Kobako::
|
|
17
|
+
def self?.dispatch: (Kobako::Transport::Call call, Kobako::Transport::_ServiceRegistry resolver, Kobako::Transport::_HandleTable handler, Kobako::Transport::_GuestYielder yield_to_guest) -> [bool, String, String?]
|
|
18
18
|
|
|
19
|
-
def self?.run: (Kobako::Transport::Call call, Kobako::Transport::_ServiceRegistry resolver, Kobako::
|
|
19
|
+
def self?.run: (Kobako::Transport::Call call, Kobako::Transport::_ServiceRegistry resolver, Kobako::Transport::_HandleTable handler, Kobako::Transport::Yielder? yielder) -> untyped
|
|
20
20
|
|
|
21
21
|
def self?.resolve_call_args: (Kobako::Payload::Arguments arguments, Kobako::Codec::_HandleTable handler, bool carried_handle) -> [Array[untyped], Hash[Symbol, untyped]]
|
|
22
22
|
|
|
@@ -24,18 +24,18 @@ module Kobako
|
|
|
24
24
|
|
|
25
25
|
def self?.caught_fault: (StandardError error, Kobako::Transport::Yielder? yielder) -> [String, String]
|
|
26
26
|
|
|
27
|
-
def self?.invoke: (
|
|
27
|
+
def self?.invoke: (Kobako::Transport::Exposure exposure, String method, Array[untyped] args, Hash[Symbol, untyped] kwargs, ?Kobako::Transport::Yielder? yielder) -> untyped
|
|
28
28
|
|
|
29
|
-
def self?.reject_unreachable!: (
|
|
29
|
+
def self?.reject_unreachable!: (Kobako::Transport::Exposure exposure, Symbol name) -> void
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def self?.resolve_arg: (untyped value, Kobako::Codec::_HandleTable handler) -> untyped
|
|
33
33
|
|
|
34
|
-
def self?.resolve_target: (String | Integer target, Kobako::Transport::_ServiceRegistry resolver, Kobako::
|
|
34
|
+
def self?.resolve_target: (String | Integer target, Kobako::Transport::_ServiceRegistry resolver, Kobako::Transport::_HandleTable handler) -> Kobako::Transport::Exposure
|
|
35
35
|
|
|
36
|
-
def self?.resolve_path: (String path, Kobako::Transport::_ServiceRegistry resolver) ->
|
|
36
|
+
def self?.resolve_path: (String path, Kobako::Transport::_ServiceRegistry resolver) -> Kobako::Transport::Exposure
|
|
37
37
|
|
|
38
|
-
def self?.
|
|
38
|
+
def self?.resolve_handle: (Integer id, Kobako::Transport::_HandleTable handler) -> Kobako::Transport::Exposure
|
|
39
39
|
|
|
40
40
|
def self?.encode_ok: (untyped value, Kobako::Codec::_HandleTable handler) -> String
|
|
41
41
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Kobako
|
|
2
|
+
module Transport
|
|
3
|
+
class Exposure < Data
|
|
4
|
+
PREDICATE: Symbol
|
|
5
|
+
CLASS_OF: UnboundMethod
|
|
6
|
+
SINGLETON_CLASS_OF: UnboundMethod
|
|
7
|
+
SINGLETON_METHODS: UnboundMethod
|
|
8
|
+
PRIVATE_METHODS: UnboundMethod
|
|
9
|
+
CALLABLE: Set[Symbol]
|
|
10
|
+
NOTHING: Set[Symbol]
|
|
11
|
+
|
|
12
|
+
attr_reader object: untyped
|
|
13
|
+
attr_reader names: Set[Symbol]?
|
|
14
|
+
|
|
15
|
+
def self.new: (object: untyped, names: Set[Symbol]?) -> Exposure
|
|
16
|
+
| (untyped, Set[Symbol]?) -> Exposure
|
|
17
|
+
|
|
18
|
+
def self.of: (untyped object, ?Hash[Module, Set[Symbol]] surfaces) -> Exposure
|
|
19
|
+
|
|
20
|
+
def initialize: (object: untyped, names: Set[Symbol]?) -> void
|
|
21
|
+
|
|
22
|
+
def with: (?object: untyped, ?names: Set[Symbol]?) -> Exposure
|
|
23
|
+
|
|
24
|
+
def ==: (untyped other) -> bool
|
|
25
|
+
|
|
26
|
+
def hash: () -> Integer
|
|
27
|
+
|
|
28
|
+
def exposes?: (Symbol name) -> bool
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def self.narrows_itself?: (untyped object, Module klass) -> bool
|
|
33
|
+
|
|
34
|
+
def self.default_names: (untyped object, Module klass, Hash[Module, Set[Symbol]] surfaces) -> Set[Symbol]
|
|
35
|
+
|
|
36
|
+
def self.class_names: (untyped object, Module klass) -> Set[Symbol]
|
|
37
|
+
|
|
38
|
+
def self.with_singleton: (untyped object, Set[Symbol] names) -> Set[Symbol]
|
|
39
|
+
|
|
40
|
+
def self.authored: (Module owner) -> Array[Symbol]
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -5,13 +5,11 @@ module Kobako
|
|
|
5
5
|
GADGET_OWNERS: Array[Module]
|
|
6
6
|
CALLABLE_ALLOW: Array[Symbol]
|
|
7
7
|
|
|
8
|
-
def self?.refusal: (
|
|
8
|
+
def self?.refusal: (Kobako::Transport::Exposure exposure, Symbol name) -> String?
|
|
9
9
|
|
|
10
10
|
def self?.ambient_refusal: (untyped target, Symbol name) -> String?
|
|
11
11
|
|
|
12
12
|
def self?.ambient_owner?: (Module owner, untyped target) -> bool
|
|
13
|
-
|
|
14
|
-
def self?.narrowing_refusal: (untyped target, Symbol name) -> String?
|
|
15
13
|
end
|
|
16
14
|
end
|
|
17
15
|
end
|
data/sig/kobako/transport.rbs
CHANGED
|
@@ -20,7 +20,17 @@ module Kobako
|
|
|
20
20
|
# production conformer; modelled structurally so the Transport
|
|
21
21
|
# layer needs no upward dependency on Catalog.
|
|
22
22
|
interface _ServiceRegistry
|
|
23
|
-
def lookup: (String target) ->
|
|
23
|
+
def lookup: (String target) -> Exposure
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# The per-invocation Handle table as a dispatch reads it: the codec's
|
|
27
|
+
# allocate / restore pair, plus the Exposure a Handle was minted with,
|
|
28
|
+
# which authorizes a call made through it. Kobako::Catalog::Handles is
|
|
29
|
+
# the production conformer.
|
|
30
|
+
interface _HandleTable
|
|
31
|
+
include Kobako::Codec::_HandleTable
|
|
32
|
+
|
|
33
|
+
def exposure: (Integer id) -> Exposure
|
|
24
34
|
end
|
|
25
35
|
end
|
|
26
36
|
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.25.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-
|
|
11
|
+
date: 2026-09-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: msgpack
|
|
@@ -83,6 +83,7 @@ files:
|
|
|
83
83
|
- lib/kobako/transport/call.rb
|
|
84
84
|
- lib/kobako/transport/dispatcher.rb
|
|
85
85
|
- lib/kobako/transport/error.rb
|
|
86
|
+
- lib/kobako/transport/exposure.rb
|
|
86
87
|
- lib/kobako/transport/reflection.rb
|
|
87
88
|
- lib/kobako/transport/run.rb
|
|
88
89
|
- lib/kobako/transport/yielder.rb
|
|
@@ -125,6 +126,7 @@ files:
|
|
|
125
126
|
- sig/kobako/transport/call.rbs
|
|
126
127
|
- sig/kobako/transport/dispatcher.rbs
|
|
127
128
|
- sig/kobako/transport/error.rbs
|
|
129
|
+
- sig/kobako/transport/exposure.rbs
|
|
128
130
|
- sig/kobako/transport/reflection.rbs
|
|
129
131
|
- sig/kobako/transport/run.rbs
|
|
130
132
|
- sig/kobako/transport/yielder.rbs
|