kobako 0.28.0 → 0.30.0
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 +377 -0
- data/Cargo.lock +181 -154
- data/README.md +99 -459
- data/ROADMAP.md +7 -1
- data/SECURITY.md +1 -1
- data/crates/kobako-runtime/CHANGELOG.md +354 -0
- data/crates/kobako-runtime/Cargo.toml +38 -7
- data/crates/kobako-runtime/README.md +17 -8
- data/crates/kobako-runtime/src/dispatch.rs +9 -1
- data/crates/kobako-runtime/src/endpoint/buffer.rs +192 -0
- data/crates/kobako-runtime/src/endpoint/capture.rs +115 -0
- data/crates/kobako-runtime/src/endpoint/dispatch.rs +253 -0
- data/crates/kobako-runtime/src/endpoint/invoke.rs +194 -0
- data/crates/kobako-runtime/src/endpoint/memory_cap.rs +238 -0
- data/crates/kobako-runtime/src/endpoint.rs +166 -0
- data/crates/kobako-runtime/src/filesystem/bind/fid.rs +82 -0
- data/crates/kobako-runtime/src/filesystem/bind/lookup.rs +236 -0
- data/crates/kobako-runtime/src/filesystem/bind/walk.rs +249 -0
- data/crates/kobako-runtime/src/filesystem/bind.rs +2665 -0
- data/crates/kobako-runtime/src/filesystem/overlay/file.rs +89 -0
- data/crates/kobako-runtime/src/filesystem/overlay/inode.rs +106 -0
- data/crates/kobako-runtime/src/filesystem/overlay/path.rs +285 -0
- data/crates/kobako-runtime/src/filesystem/overlay/stack/copy_up.rs +135 -0
- data/crates/kobako-runtime/src/filesystem/overlay/stack/dir.rs +263 -0
- data/crates/kobako-runtime/src/filesystem/overlay/stack/namei.rs +135 -0
- data/crates/kobako-runtime/src/filesystem/overlay/stack/readdir.rs +57 -0
- data/crates/kobako-runtime/src/filesystem/overlay/stack.rs +301 -0
- data/crates/kobako-runtime/src/filesystem/overlay.rs +3469 -0
- data/crates/kobako-runtime/src/filesystem/path.rs +21 -0
- data/crates/kobako-runtime/src/filesystem/pipe.rs +221 -0
- data/crates/kobako-runtime/src/filesystem/rdir.rs +101 -0
- data/crates/kobako-runtime/src/filesystem/tmpfs/tmpfile.rs +32 -0
- data/crates/kobako-runtime/src/filesystem/tmpfs/whiteout.rs +85 -0
- data/crates/kobako-runtime/src/filesystem/tmpfs/xattr.rs +22 -0
- data/crates/kobako-runtime/src/filesystem/tmpfs.rs +1985 -0
- data/crates/kobako-runtime/src/filesystem/wrap.rs +224 -0
- data/crates/kobako-runtime/src/filesystem.rs +26 -0
- data/crates/kobako-runtime/src/grant.rs +20 -0
- data/crates/kobako-runtime/src/hashtable.rs +44 -0
- data/crates/kobako-runtime/src/lib.rs +16 -1
- data/crates/kobako-runtime/src/locking/seqlock.rs +66 -0
- data/crates/kobako-runtime/src/locking.rs +218 -0
- data/crates/kobako-runtime/src/mount.rs +105 -0
- data/crates/kobako-runtime/src/profile.rs +140 -4
- data/crates/kobako-runtime/src/runtime.rs +12 -0
- data/crates/kobako-runtime/src/sched.rs +210 -0
- data/crates/kobako-runtime/src/security.rs +696 -0
- data/crates/kobako-runtime/src/snapshot.rs +20 -5
- data/crates/kobako-runtime/src/vfs/attr.rs +162 -0
- data/crates/kobako-runtime/src/vfs/cred.rs +334 -0
- data/crates/kobako-runtime/src/vfs/dentry.rs +1412 -0
- data/crates/kobako-runtime/src/vfs/errno.rs +153 -0
- data/crates/kobako-runtime/src/vfs/file.rs +1915 -0
- data/crates/kobako-runtime/src/vfs/inode.rs +429 -0
- data/crates/kobako-runtime/src/vfs/kern_path.rs +217 -0
- data/crates/kobako-runtime/src/vfs/mount.rs +59 -0
- data/crates/kobako-runtime/src/vfs/namei.rs +5708 -0
- data/crates/kobako-runtime/src/vfs/openat2.rs +116 -0
- data/crates/kobako-runtime/src/vfs/path.rs +64 -0
- data/crates/kobako-runtime/src/vfs/readdir.rs +163 -0
- data/crates/kobako-runtime/src/vfs/stat.rs +157 -0
- data/crates/kobako-runtime/src/vfs/super_block.rs +122 -0
- data/crates/kobako-runtime/src/vfs/utimes.rs +289 -0
- data/crates/kobako-runtime/src/vfs.rs +60 -0
- data/crates/kobako-runtime/src/yielder.rs +11 -6
- data/crates/kobako-runtime/tests/linux_baseline/calls.rs +171 -0
- data/crates/kobako-runtime/tests/linux_baseline/concurrent.rs +276 -0
- data/crates/kobako-runtime/tests/linux_baseline/kobako.rs +323 -0
- data/crates/kobako-runtime/tests/linux_baseline/linux-baseline-expected.txt +16 -0
- data/crates/kobako-runtime/tests/linux_baseline/linux.rs +449 -0
- data/crates/kobako-runtime/tests/linux_baseline/main.rs +611 -0
- data/crates/kobako-runtime/tests/linux_baseline/permissions.rs +236 -0
- data/crates/kobako-transport/CHANGELOG.md +23 -0
- data/crates/kobako-transport/Cargo.toml +3 -3
- data/crates/kobako-transport/README.md +6 -5
- data/crates/kobako-transport/src/abi.rs +1 -1
- data/crates/kobako-transport/src/envelope/bytes.rs +33 -25
- data/crates/kobako-transport/src/envelope/call.rs +5 -5
- data/crates/kobako-transport/src/envelope/compile_reply.rs +2 -2
- data/crates/kobako-transport/src/envelope/error_record.rs +3 -3
- data/crates/kobako-transport/src/envelope/fault.rs +4 -3
- data/crates/kobako-transport/src/envelope/outcome.rs +3 -3
- data/crates/kobako-transport/src/envelope/preamble.rs +24 -24
- data/crates/kobako-transport/src/envelope/reply.rs +34 -16
- data/crates/kobako-transport/src/envelope/request.rs +19 -9
- data/crates/kobako-transport/src/envelope/run.rs +1 -1
- data/crates/kobako-transport/src/envelope/unsupported.rs +2 -2
- data/crates/kobako-transport/src/envelope.rs +2 -2
- data/crates/kobako-wasmtime/CHANGELOG.md +265 -0
- data/crates/kobako-wasmtime/Cargo.toml +25 -19
- data/crates/kobako-wasmtime/README.md +13 -7
- data/crates/kobako-wasmtime/src/abi.rs +75 -49
- data/crates/kobako-wasmtime/src/ambient.rs +64 -6
- data/crates/kobako-wasmtime/src/cache.rs +188 -77
- data/crates/kobako-wasmtime/src/config.rs +77 -5
- data/crates/kobako-wasmtime/src/descriptors.rs +200 -0
- data/crates/kobako-wasmtime/src/driver.rs +70 -135
- data/crates/kobako-wasmtime/src/exports.rs +5 -16
- data/crates/kobako-wasmtime/src/guest.rs +38 -0
- data/crates/kobako-wasmtime/src/imports.rs +52 -0
- data/crates/kobako-wasmtime/src/instance_pre.rs +18 -46
- data/crates/kobako-wasmtime/src/invocation.rs +43 -74
- data/crates/kobako-wasmtime/src/lib.rs +5 -4
- data/crates/kobako-wasmtime/src/limiter.rs +6 -230
- data/crates/kobako-wasmtime/src/preview1/differential/mount.rs +632 -0
- data/crates/kobako-wasmtime/src/preview1/differential.rs +486 -0
- data/crates/kobako-wasmtime/src/preview1/errno.rs +135 -0
- data/crates/kobako-wasmtime/src/preview1/fd.rs +1420 -0
- data/crates/kobako-wasmtime/src/preview1/memory.rs +172 -0
- data/crates/kobako-wasmtime/src/preview1/mount_view/wrap.rs +211 -0
- data/crates/kobako-wasmtime/src/preview1/mount_view.rs +3766 -0
- data/crates/kobako-wasmtime/src/preview1/path.rs +302 -0
- data/crates/kobako-wasmtime/src/preview1/poll.rs +381 -0
- data/crates/kobako-wasmtime/src/preview1/sock.rs +13 -0
- data/crates/kobako-wasmtime/src/preview1/testsuite-expected.txt +6 -0
- data/crates/kobako-wasmtime/src/preview1/testsuite.rs +157 -0
- data/crates/kobako-wasmtime/src/preview1.rs +512 -0
- data/crates/kobako-wasmtime/src/trap.rs +45 -25
- data/crates/kobako-wasmtime/src/wasi.rs +333 -0
- data/crates/kobako-wasmtime/tests/integration/compile_posture.rs +43 -0
- data/crates/kobako-wasmtime/tests/integration/guest_file.rs +1085 -0
- data/crates/kobako-wasmtime/tests/integration/main.rs +29 -0
- data/crates/kobako-wasmtime/tests/{preamble_flags.rs → integration/preamble_flags.rs} +4 -3
- data/crates/kobako-wasmtime/tests/{snippet_compile.rs → integration/snippet_compile.rs} +5 -4
- data/crates/kobako-wasmtime/tests/{support → integration/support}/mod.rs +9 -13
- data/crates/kobako-wasmtime/tests/integration/unanswered_call.rs +86 -0
- data/crates/kobako-wasmtime/tests/{unsupported_call.rs → integration/unsupported_call.rs} +2 -1
- data/crates/kobako-wasmtime/witx/typenames.witx +750 -0
- data/crates/kobako-wasmtime/witx/wasi_snapshot_preview1.witx +441 -0
- data/data/kobako.wasm +0 -0
- data/ext/kobako/Cargo.toml +4 -2
- data/ext/kobako/src/runtime/bridge.rs +154 -81
- data/ext/kobako/src/runtime/errors.rs +1 -1
- data/ext/kobako/src/runtime/escape.rs +67 -0
- data/ext/kobako/src/runtime/filesystem/grants.rs +107 -0
- data/ext/kobako/src/runtime/filesystem/ruby.rs +708 -0
- data/ext/kobako/src/runtime/filesystem.rs +208 -0
- data/ext/kobako/src/runtime/gvl.rs +49 -8
- data/ext/kobako/src/runtime/pinned_value.rs +31 -0
- data/ext/kobako/src/runtime/snapshot.rs +127 -0
- data/ext/kobako/src/runtime.rs +125 -199
- data/lib/kobako/catalog/extensions.rb +5 -5
- data/lib/kobako/catalog/flags.rb +2 -14
- data/lib/kobako/catalog/grants.rb +30 -0
- data/lib/kobako/catalog/handles.rb +6 -6
- data/lib/kobako/catalog/mount.rb +19 -0
- data/lib/kobako/catalog/services.rb +13 -2
- data/lib/kobako/catalog/snippets.rb +11 -15
- data/lib/kobako/catalog.rb +11 -0
- data/lib/kobako/codec/decoder.rb +10 -9
- data/lib/kobako/codec/ext_types.rb +4 -6
- data/lib/kobako/codec/handle_walk.rb +4 -6
- data/lib/kobako/codec/nesting.rb +7 -7
- data/lib/kobako/codec/state.rb +19 -3
- data/lib/kobako/codec/utils.rb +1 -1
- data/lib/kobako/codec/value_budget.rb +86 -0
- data/lib/kobako/codec.rb +7 -0
- data/lib/kobako/context.rb +40 -13
- data/lib/kobako/errors.rb +15 -14
- data/lib/kobako/filesystem.rb +69 -0
- data/lib/kobako/payload/arguments.rb +2 -2
- data/lib/kobako/pool.rb +6 -6
- data/lib/kobako/sandbox.rb +55 -27
- data/lib/kobako/sandbox_options.rb +39 -13
- data/lib/kobako/snippet/{binary.rb → bytecode.rb} +2 -2
- data/lib/kobako/snippet/source.rb +1 -1
- data/lib/kobako/snippet.rb +1 -1
- data/lib/kobako/transport/block_failure.rb +35 -0
- data/lib/kobako/transport/dispatcher.rb +33 -29
- data/lib/kobako/transport/exposure.rb +7 -9
- data/lib/kobako/transport/reflection.rb +79 -23
- data/lib/kobako/transport/run.rb +5 -5
- data/lib/kobako/transport/yielder.rb +9 -31
- data/lib/kobako/transport.rb +1 -0
- data/lib/kobako/version.rb +1 -1
- data/lib/kobako.rb +35 -0
- data/release-please-config.json +1 -0
- data/sig/kobako/catalog/extensions.rbs +3 -3
- data/sig/kobako/catalog/flags.rbs +0 -4
- data/sig/kobako/catalog/grants.rbs +13 -0
- data/sig/kobako/catalog/handles.rbs +3 -3
- data/sig/kobako/catalog/mount.rbs +24 -0
- data/sig/kobako/catalog/services.rbs +5 -1
- data/sig/kobako/catalog/snippets.rbs +4 -4
- data/sig/kobako/catalog.rbs +1 -0
- data/sig/kobako/codec/decoder.rbs +1 -1
- data/sig/kobako/codec/handle_walk.rbs +1 -1
- data/sig/kobako/codec/nesting.rbs +2 -2
- data/sig/kobako/codec/state.rbs +7 -1
- data/sig/kobako/codec/utils.rbs +1 -1
- data/sig/kobako/codec/value_budget.rbs +23 -0
- data/sig/kobako/codec.rbs +3 -2
- data/sig/kobako/context.rbs +14 -6
- data/sig/kobako/errors.rbs +4 -4
- data/sig/kobako/filesystem.rbs +93 -0
- data/sig/kobako/guest_yielder.rbs +9 -0
- data/sig/kobako/payload/arguments.rbs +1 -1
- data/sig/kobako/pool.rbs +3 -3
- data/sig/kobako/runtime.rbs +21 -49
- data/sig/kobako/sandbox.rbs +9 -5
- data/sig/kobako/sandbox_options.rbs +25 -3
- data/sig/kobako/snapshot.rbs +20 -0
- data/sig/kobako/snippet/bytecode.rbs +12 -0
- data/sig/kobako/transport/block_failure.rbs +13 -0
- data/sig/kobako/transport/dispatcher.rbs +4 -4
- data/sig/kobako/transport/exposure.rbs +2 -2
- data/sig/kobako/transport/reflection.rbs +14 -1
- data/sig/kobako/transport/run.rbs +3 -3
- data/sig/kobako/transport/yielder.rbs +3 -7
- data/sig/kobako/transport.rbs +3 -3
- metadata +116 -15
- data/crates/kobako-wasmtime/src/capture.rs +0 -96
- data/crates/kobako-wasmtime/src/dispatch.rs +0 -107
- data/crates/kobako-wasmtime/src/guest_mem.rs +0 -265
- data/crates/kobako-wasmtime/src/io.rs +0 -286
- data/sig/kobako/snippet/binary.rbs +0 -12
|
@@ -3,17 +3,6 @@
|
|
|
3
3
|
module Kobako
|
|
4
4
|
module Transport
|
|
5
5
|
module Reflection # :nodoc:
|
|
6
|
-
# Modules whose instance methods are ambient Ruby reflection /
|
|
7
|
-
# metaprogramming surface (+send+, +public_send+, +instance_eval+,
|
|
8
|
-
# +method+, +tap+, +instance_variable_get+, ...) rather than Service
|
|
9
|
-
# behaviour. A guest-supplied method name resolving to one of these is
|
|
10
|
-
# rejected: only methods the bound object itself exposes as Service
|
|
11
|
-
# behaviour are reachable, and +public_send(:send, ...)+ would
|
|
12
|
-
# otherwise let a guest pivot through +send+ into the private
|
|
13
|
-
# +Kernel#eval+ / +#system+ surface (host RCE).
|
|
14
|
-
META_OWNERS = [BasicObject, Kernel, Object, Module, Class].freeze
|
|
15
|
-
private_constant :META_OWNERS
|
|
16
|
-
|
|
17
6
|
# Callable gadget types whose own public methods are reflection surface
|
|
18
7
|
# (+Proc#binding+ reaches +Binding#eval+, +Method#receiver+ / +#unbind+
|
|
19
8
|
# hand back the underlying object) rather than Service behaviour. Only
|
|
@@ -37,11 +26,33 @@ module Kobako
|
|
|
37
26
|
(exposure.exposes?(name) ? nil : "method #{name.inspect} is not exposed to the guest")
|
|
38
27
|
end
|
|
39
28
|
|
|
29
|
+
# Whether +method+ is written in Ruby rather than built into the
|
|
30
|
+
# platform or copied from the surface every object shares. A native
|
|
31
|
+
# method has no source, and a built-in one names an +<internal:>+ file,
|
|
32
|
+
# so a copy, alias or rebinding of either keeps that mark wherever it
|
|
33
|
+
# is reached from.
|
|
34
|
+
def self.authored?(method)
|
|
35
|
+
file, = method.source_location
|
|
36
|
+
!file.nil? && !file.start_with?("<internal:") && !ambient_copy?(method)
|
|
37
|
+
end
|
|
38
|
+
|
|
40
39
|
class << self
|
|
41
40
|
private
|
|
42
41
|
|
|
42
|
+
# Whether +method+ is a copy, alias or rebinding of a Ruby method
|
|
43
|
+
# +Class+ inherits, such as the +name!+ alias OpenStruct makes of a
|
|
44
|
+
# mixed-in +try+. The copy is owned by the class that made it, but
|
|
45
|
+
# keeps the original's name and source.
|
|
46
|
+
def ambient_copy?(method)
|
|
47
|
+
name = method.original_name
|
|
48
|
+
Class.ancestors.any? do |owner|
|
|
49
|
+
(owner.method_defined?(name, false) || owner.private_method_defined?(name, false)) &&
|
|
50
|
+
owner.instance_method(name).source_location == method.source_location
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
43
54
|
# Guard against ambient reflection methods. A public method whose
|
|
44
|
-
# owner
|
|
55
|
+
# owner +Class+ inherits or a GADGET_OWNERS module — or a singleton
|
|
45
56
|
# class, the owner of every class-level method (+File.popen+ /
|
|
46
57
|
# +Kernel.system+, unreachable via any fixed core-module list) — is
|
|
47
58
|
# rejected, except CALLABLE_ALLOW on a gadget target (a bound lambda
|
|
@@ -55,26 +66,71 @@ module Kobako
|
|
|
55
66
|
# +Delegator+) binds and calls the private method the guest passes as
|
|
56
67
|
# its first argument (+Kernel#system+). A dynamic +method_missing+
|
|
57
68
|
# Service is untouched — the guest reaches it by the virtual name,
|
|
58
|
-
# which resolves through the +
|
|
59
|
-
#
|
|
69
|
+
# which resolves through the +respond_to?+ opt-in, never by naming
|
|
70
|
+
# +method_missing+.
|
|
71
|
+
#
|
|
72
|
+
# A public method must also be authored, so a Service narrowing itself
|
|
73
|
+
# never reaches a built-in or ambient method by a copy, alias or
|
|
74
|
+
# rebinding an owner check cannot see; a non-public one is never
|
|
75
|
+
# reached through a dynamic opt-in either.
|
|
76
|
+
#
|
|
77
|
+
# A name with no method never reaches +instance_method+, which would
|
|
78
|
+
# keep a guest-chosen name as a Symbol for the life of the process.
|
|
60
79
|
def ambient_refusal(target, name)
|
|
61
|
-
return
|
|
80
|
+
return service_refusal(name) if name == :method_missing
|
|
81
|
+
|
|
82
|
+
klass = lookup_class(target)
|
|
83
|
+
return public_method_refusal(target, name, klass) if klass.public_method_defined?(name)
|
|
84
|
+
return "no public method #{name.inspect} on target" unless target.respond_to?(name)
|
|
85
|
+
return service_refusal(name) if klass.method_defined?(name) || klass.private_method_defined?(name)
|
|
62
86
|
|
|
63
|
-
|
|
87
|
+
owner_refusal(target, name, klass)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def public_method_refusal(target, name, klass)
|
|
91
|
+
method = klass.instance_method(name)
|
|
92
|
+
owner_refusal(target, name, method.owner) ||
|
|
93
|
+
(authored_for?(target, name, method, klass) ? nil : service_refusal(name))
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# A bound callable keeps its callable names and a record its member
|
|
97
|
+
# readers, though the platform defines both.
|
|
98
|
+
def authored_for?(target, name, method, klass)
|
|
99
|
+
return true if Reflection.authored?(method)
|
|
100
|
+
return true if GADGET_OWNERS.include?(method.owner) && CALLABLE_ALLOW.include?(name)
|
|
101
|
+
|
|
102
|
+
(klass <= Struct || klass <= Data) && target.members.include?(name)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def service_refusal(name)
|
|
106
|
+
"method #{name.inspect} is not a Service method"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def owner_refusal(target, name, owner)
|
|
64
110
|
return nil unless ambient_owner?(owner, target)
|
|
65
111
|
return nil if GADGET_OWNERS.include?(owner) && CALLABLE_ALLOW.include?(name)
|
|
66
112
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
113
|
+
service_refusal(name)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# The class a method lookup on +target+ starts at. A plain object's
|
|
117
|
+
# singleton class is taken only when it already holds a public
|
|
118
|
+
# method, since asking for it otherwise would create one.
|
|
119
|
+
def lookup_class(target)
|
|
120
|
+
return target.singleton_class if target.is_a?(Module) || target.singleton_methods.any?
|
|
70
121
|
|
|
71
|
-
|
|
122
|
+
target.class
|
|
72
123
|
end
|
|
73
124
|
|
|
74
|
-
#
|
|
75
|
-
#
|
|
125
|
+
# Whatever +Class+ inherits is surface every object shares rather
|
|
126
|
+
# than Service behaviour: the reflection +BasicObject+ through +Class+
|
|
127
|
+
# define (+send+ pivots into +Kernel#eval+, a host RCE), and every
|
|
128
|
+
# module a library mixes into them, such as a +try+ dispatching by
|
|
129
|
+
# name or a +to_json+ dumping instance variables. A plain object's
|
|
130
|
+
# own singleton method (+def obj.x+) stays reachable, since only a
|
|
131
|
+
# Module target counts its singleton class as ambient.
|
|
76
132
|
def ambient_owner?(owner, target)
|
|
77
|
-
|
|
133
|
+
owner >= Class ||
|
|
78
134
|
GADGET_OWNERS.include?(owner) ||
|
|
79
135
|
(target.is_a?(Module) && owner.singleton_class?)
|
|
80
136
|
end
|
data/lib/kobako/transport/run.rb
CHANGED
|
@@ -12,8 +12,8 @@ module Kobako
|
|
|
12
12
|
class Run < Data.define(:entrypoint, :args, :kwargs) # :nodoc:
|
|
13
13
|
def initialize(entrypoint:, args: [], kwargs: {})
|
|
14
14
|
entrypoint = normalize_entrypoint(entrypoint)
|
|
15
|
-
validate_args
|
|
16
|
-
validate_kwargs
|
|
15
|
+
validate_args(args)
|
|
16
|
+
validate_kwargs(kwargs)
|
|
17
17
|
super
|
|
18
18
|
end
|
|
19
19
|
|
|
@@ -21,7 +21,7 @@ module Kobako
|
|
|
21
21
|
# invocation's table. The walk starts one level down, since +args+ and
|
|
22
22
|
# +kwargs+ ride inside the payload document the wire's nesting bound
|
|
23
23
|
# is counted from.
|
|
24
|
-
def
|
|
24
|
+
def encode_payload(handles)
|
|
25
25
|
Payload::Arguments.new(
|
|
26
26
|
args: Codec::HandleWalk.deep_wrap(args, handles, 1),
|
|
27
27
|
kwargs: Codec::HandleWalk.deep_wrap(kwargs, handles, 1)
|
|
@@ -46,14 +46,14 @@ module Kobako
|
|
|
46
46
|
target_str.to_sym
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
def validate_args
|
|
49
|
+
def validate_args(args)
|
|
50
50
|
raise ArgumentError, "arguments must be an Array" unless args.is_a?(Array)
|
|
51
51
|
raise ArgumentError, forged_handle_message("arguments") if args.any?(Kobako::Handle)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
# Checked here so the Host App sees the host-side message before any
|
|
55
55
|
# encode boundary.
|
|
56
|
-
def validate_kwargs
|
|
56
|
+
def validate_kwargs(kwargs)
|
|
57
57
|
raise ArgumentError, "keyword arguments must be a Hash" unless kwargs.is_a?(Hash)
|
|
58
58
|
|
|
59
59
|
bad_keys = kwargs.each_key.grep_v(Symbol)
|
|
@@ -6,50 +6,34 @@ require_relative "../errors"
|
|
|
6
6
|
module Kobako
|
|
7
7
|
module Transport
|
|
8
8
|
class Yielder # :nodoc:
|
|
9
|
-
def initialize(guest_yielder, break_tag, handles)
|
|
9
|
+
def initialize(guest_yielder, break_tag, handles, failure)
|
|
10
10
|
@guest_yielder = guest_yielder
|
|
11
11
|
@break_tag = break_tag
|
|
12
12
|
@handles = handles
|
|
13
|
+
@failure = failure
|
|
13
14
|
@active = true
|
|
14
|
-
@raised = nil
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# Identity rather than class: a Service that rescued the block's
|
|
18
|
-
# failure and raised its own has reported something else, and the
|
|
19
|
-
# guest must hear about that instead.
|
|
20
|
-
#
|
|
21
|
-
# The class travels with the message because not every block failure
|
|
22
|
-
# is an exception the guest holds — a block value the guest refused
|
|
23
|
-
# has a class to raise under and no object to continue.
|
|
24
|
-
def fault_text(error)
|
|
25
|
-
raised = @raised
|
|
26
|
-
return if raised.nil? || !error.equal?(raised)
|
|
27
|
-
|
|
28
|
-
"#{raised.klass}: #{raised.message}"
|
|
29
15
|
end
|
|
30
16
|
|
|
31
17
|
# The ok value is consumed by the host Service, so a Capability Handle
|
|
32
|
-
# in it is restored.
|
|
33
|
-
#
|
|
34
|
-
# churning a new one.
|
|
18
|
+
# in it is restored. A block exit stays in the guest, so the Service
|
|
19
|
+
# is only unwound.
|
|
35
20
|
def yield(*args)
|
|
36
21
|
raise LocalJumpError, "guest block invoked after host dispatch frame returned" unless @active
|
|
37
22
|
|
|
38
23
|
arm, body, klass = @guest_yielder.call(encode_args(args))
|
|
39
24
|
raise UnsupportedError, "the Sandbox runtime does not support yielding to a block" if arm == :unsupported
|
|
40
|
-
raise remember(BlockError.new(body, klass: klass)) if arm == :error
|
|
25
|
+
raise @failure.remember(BlockError.new(body, klass: klass)) if arm == :error
|
|
41
26
|
|
|
42
|
-
|
|
43
|
-
throw @break_tag, value if arm == :break
|
|
27
|
+
throw @break_tag if arm == :break
|
|
44
28
|
|
|
45
|
-
restore(
|
|
29
|
+
restore(*decode_body(body))
|
|
46
30
|
end
|
|
47
31
|
|
|
48
32
|
def to_proc
|
|
49
33
|
method(:yield).to_proc
|
|
50
34
|
end
|
|
51
35
|
|
|
52
|
-
def invalidate
|
|
36
|
+
def invalidate
|
|
53
37
|
@active = false
|
|
54
38
|
end
|
|
55
39
|
|
|
@@ -58,18 +42,12 @@ module Kobako
|
|
|
58
42
|
# Restated so the Service reads a refusal of its own argument rather
|
|
59
43
|
# than a codec class it never named.
|
|
60
44
|
def encode_args(args)
|
|
61
|
-
Kobako::Codec::Nesting.assert_within_bound
|
|
45
|
+
Kobako::Codec::Nesting.assert_within_bound(args)
|
|
62
46
|
Kobako::Codec::Encoder.encode(args)
|
|
63
47
|
rescue Kobako::Codec::Error => e
|
|
64
48
|
raise YieldValueError, "Service yielded a value the block cannot receive: #{e.message}"
|
|
65
49
|
end
|
|
66
50
|
|
|
67
|
-
# Only the newest is kept: a Service that rescued an earlier one and
|
|
68
|
-
# yielded again has already handled it.
|
|
69
|
-
def remember(error)
|
|
70
|
-
@raised = error
|
|
71
|
-
end
|
|
72
|
-
|
|
73
51
|
# The tracking bracket opens only around this decode: the guest
|
|
74
52
|
# re-entry may run nested dispatches whose own brackets would
|
|
75
53
|
# otherwise pollute the signal.
|
data/lib/kobako/transport.rb
CHANGED
data/lib/kobako/version.rb
CHANGED
data/lib/kobako.rb
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Inside +lib/+, the code sits in tiers: a tier may use the tiers below it
|
|
4
|
+
# and never one above.
|
|
5
|
+
#
|
|
6
|
+
# Orchestration Sandbox, Pool, Runtime (+ ext), Context
|
|
7
|
+
# |
|
|
8
|
+
# Catalog setup-time registries + the per-invocation Handle table
|
|
9
|
+
# |
|
|
10
|
+
# Transport --+ call value objects + dispatch
|
|
11
|
+
# Outcome ----+ guest-result attribution
|
|
12
|
+
# | |
|
|
13
|
+
# Payload <---+ the [args, kwargs] shape a Call or Run carries
|
|
14
|
+
# | |
|
|
15
|
+
# Codec <-----+ byte-level payload wire
|
|
16
|
+
# |
|
|
17
|
+
# Root dependency-free value objects and error classes
|
|
18
|
+
#
|
|
19
|
+
# The Envelope has no tier here, because the native side frames and
|
|
20
|
+
# decodes it.
|
|
21
|
+
#
|
|
22
|
+
# These rules keep the tiers acyclic:
|
|
23
|
+
#
|
|
24
|
+
# [A type sits at the lowest tier that needs it]
|
|
25
|
+
# Kobako::Handle sits at the root, for Codec.
|
|
26
|
+
# [A native-defined handle that needs nothing in +lib/+ sits at the root]
|
|
27
|
+
# Kobako::Filesystem sits at the root, for the Catalog.
|
|
28
|
+
# [Outcome may require <tt>transport/error.rb</tt>]
|
|
29
|
+
# The gem contract fixes the class name.
|
|
30
|
+
# [<tt>Codec.track_handles</tt> wraps only the decode call]
|
|
31
|
+
# Wrapping more leaks its flag into re-entry.
|
|
32
|
+
#
|
|
33
|
+
# Namespace follows dependency direction, not which tier reads a type most.
|
|
34
|
+
# Kobako::Transport::Error stays in Transport despite the lateral edge from
|
|
35
|
+
# Outcome, because its file depends only on the root <tt>errors.rb</tt>.
|
|
36
|
+
|
|
3
37
|
require_relative "kobako/version"
|
|
4
38
|
|
|
5
39
|
begin
|
|
@@ -9,6 +43,7 @@ rescue LoadError
|
|
|
9
43
|
require "kobako/kobako"
|
|
10
44
|
end
|
|
11
45
|
|
|
46
|
+
require_relative "kobako/filesystem"
|
|
12
47
|
require_relative "kobako/errors"
|
|
13
48
|
require_relative "kobako/unresolved"
|
|
14
49
|
require_relative "kobako/extension"
|
data/release-please-config.json
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
|
|
3
3
|
"release-type": "ruby",
|
|
4
4
|
"bump-minor-pre-major": true,
|
|
5
|
+
"commit-search-depth": 1000,
|
|
5
6
|
"last-release-sha": "98509af508988f708bf0d7a76a718bb0428a177e",
|
|
6
7
|
"packages": {
|
|
7
8
|
".": {
|
|
@@ -5,17 +5,17 @@ module Kobako
|
|
|
5
5
|
|
|
6
6
|
def install: (untyped extension, snippets: Kobako::Catalog::Snippets, services: Kobako::Catalog::Services) -> self
|
|
7
7
|
|
|
8
|
-
def assert_dependencies
|
|
8
|
+
def assert_dependencies: () -> self
|
|
9
9
|
|
|
10
10
|
def resolve: () -> Hash[String, untyped]
|
|
11
11
|
|
|
12
12
|
private
|
|
13
13
|
|
|
14
|
-
def
|
|
14
|
+
def object_of: (untyped backend) -> untyped
|
|
15
15
|
|
|
16
16
|
def resolve_backend: (untyped extension, Hash[String, untyped] resolved, Hash[untyped, untyped] by_provider) -> void
|
|
17
17
|
|
|
18
|
-
def validate
|
|
18
|
+
def validate: (untyped extension) -> void
|
|
19
19
|
|
|
20
20
|
def unmet_dependency: () -> [untyped, untyped]?
|
|
21
21
|
|
|
@@ -13,11 +13,11 @@ module Kobako
|
|
|
13
13
|
|
|
14
14
|
private
|
|
15
15
|
|
|
16
|
-
def reject_unwrappable
|
|
16
|
+
def reject_unwrappable: (untyped object) -> void
|
|
17
17
|
|
|
18
|
-
def ensure_capacity
|
|
18
|
+
def ensure_capacity: () -> void
|
|
19
19
|
|
|
20
|
-
def require_bound
|
|
20
|
+
def require_bound: (Integer id) -> void
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Kobako
|
|
2
|
+
module Catalog
|
|
3
|
+
class Mount < Data
|
|
4
|
+
type access = Kobako::Filesystem::access
|
|
5
|
+
|
|
6
|
+
type policy = ^(String path, access access) -> boolish
|
|
7
|
+
|
|
8
|
+
type tuple = [String, access, Kobako::Filesystem::mountable, policy?]
|
|
9
|
+
|
|
10
|
+
attr_reader at: String
|
|
11
|
+
attr_reader access: access
|
|
12
|
+
attr_reader filesystem: Kobako::Filesystem::mountable
|
|
13
|
+
attr_reader policy: policy?
|
|
14
|
+
|
|
15
|
+
def self.new: (at: untyped, access: untyped, filesystem: untyped, policy: policy?) -> Mount
|
|
16
|
+
|
|
17
|
+
def key: () -> String
|
|
18
|
+
|
|
19
|
+
def conflict: (Mount other) -> String?
|
|
20
|
+
|
|
21
|
+
def to_native: () -> tuple
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
module Kobako
|
|
2
2
|
module Catalog
|
|
3
3
|
class Services
|
|
4
|
+
RESERVED_NAMESPACE: String
|
|
5
|
+
|
|
4
6
|
def initialize: () -> void
|
|
5
7
|
|
|
6
8
|
def bind: (Symbol | String path, untyped object) -> self
|
|
@@ -13,7 +15,9 @@ module Kobako
|
|
|
13
15
|
|
|
14
16
|
private
|
|
15
17
|
|
|
16
|
-
def validate_path
|
|
18
|
+
def validate_path: (Symbol | String path) -> String
|
|
19
|
+
|
|
20
|
+
def reserved?: (String path) -> bool
|
|
17
21
|
|
|
18
22
|
def collision?: (String path) -> bool
|
|
19
23
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Kobako
|
|
2
2
|
module Catalog
|
|
3
3
|
class Snippets
|
|
4
|
-
type entry = Kobako::Snippet::Source | Kobako::Snippet::
|
|
4
|
+
type entry = Kobako::Snippet::Source | Kobako::Snippet::Bytecode
|
|
5
5
|
|
|
6
6
|
type tuple = [Symbol, String?, String]
|
|
7
7
|
|
|
@@ -15,11 +15,11 @@ module Kobako
|
|
|
15
15
|
|
|
16
16
|
private
|
|
17
17
|
|
|
18
|
-
def register_source
|
|
18
|
+
def register_source: (String? code, (Symbol | String)? name) -> nil
|
|
19
19
|
|
|
20
|
-
def ensure_source_args
|
|
20
|
+
def ensure_source_args: (String? code, (Symbol | String)? name) -> [String, Symbol | String]
|
|
21
21
|
|
|
22
|
-
def register_binary
|
|
22
|
+
def register_binary: (String bytes) -> nil
|
|
23
23
|
|
|
24
24
|
def entry_tuple: (entry) -> tuple
|
|
25
25
|
|
data/sig/kobako/catalog.rbs
CHANGED
|
@@ -11,7 +11,7 @@ module Kobako
|
|
|
11
11
|
|
|
12
12
|
private
|
|
13
13
|
|
|
14
|
-
def self.guard_nesting
|
|
14
|
+
def self.guard_nesting: (Integer depth) -> void
|
|
15
15
|
|
|
16
16
|
def self.deep_wrap_hash: (Hash[untyped, untyped] hash, Kobako::Codec::_HandleTable handles, Integer depth) -> Hash[untyped, untyped]
|
|
17
17
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
module Kobako
|
|
2
2
|
module Codec
|
|
3
3
|
module Nesting
|
|
4
|
-
def self.assert_within_bound
|
|
4
|
+
def self.assert_within_bound: (untyped value, ?Integer depth) -> void
|
|
5
5
|
|
|
6
|
-
def self.assert_members_within_bound
|
|
6
|
+
def self.assert_members_within_bound: (Array[untyped] members, Integer depth) -> void
|
|
7
7
|
end
|
|
8
8
|
end
|
|
9
9
|
end
|
data/sig/kobako/codec/state.rbs
CHANGED
|
@@ -5,8 +5,14 @@ module Kobako
|
|
|
5
5
|
|
|
6
6
|
def self.current: () -> State
|
|
7
7
|
|
|
8
|
+
@carried_handle: bool
|
|
9
|
+
@value_budget: Integer?
|
|
10
|
+
|
|
11
|
+
attr_reader value_budget: Integer?
|
|
12
|
+
|
|
8
13
|
def track_handles: [T] { () -> T } -> [T, bool]
|
|
9
|
-
def record_handle
|
|
14
|
+
def record_handle: () -> void
|
|
15
|
+
def within_value_budget: [T] (Integer? budget) { () -> T } -> T
|
|
10
16
|
|
|
11
17
|
private
|
|
12
18
|
|
data/sig/kobako/codec/utils.rbs
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Kobako
|
|
2
|
+
module Codec
|
|
3
|
+
module ValueBudget
|
|
4
|
+
SCALARS: Hash[Integer, Integer]
|
|
5
|
+
|
|
6
|
+
COUNTS: Hash[Integer, [Integer, Integer]]
|
|
7
|
+
|
|
8
|
+
LENGTHS: Hash[Integer, [Integer, Integer]]
|
|
9
|
+
|
|
10
|
+
UINT: Hash[Integer, String]
|
|
11
|
+
|
|
12
|
+
def self.assert_within: (String bytes, Integer? budget) -> void
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def self.step: (String bytes, Integer pos) -> [Integer?, Integer]
|
|
17
|
+
|
|
18
|
+
def self.step_framed:(String bytes, Integer pos, Integer marker) -> [Integer?, Integer]
|
|
19
|
+
|
|
20
|
+
def self.uint: (String bytes, Integer pos, Integer width) -> Integer
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/sig/kobako/codec.rbs
CHANGED
|
@@ -2,8 +2,7 @@ module Kobako
|
|
|
2
2
|
module Codec
|
|
3
3
|
MAX_NESTING_DEPTH: Integer
|
|
4
4
|
|
|
5
|
-
# A value in the closed wire type set
|
|
6
|
-
# § Type Mapping): the scalar leaves, a Capability Handle, and Array / Hash
|
|
5
|
+
# A value in the closed wire type set: the scalar leaves, a Capability Handle, and Array / Hash
|
|
7
6
|
# containers of the same. The by-value payloads that cross the wire —
|
|
8
7
|
# dispatch arguments and success values — inhabit this type; a Fault is
|
|
9
8
|
# an envelope shape, not a wire_value.
|
|
@@ -14,6 +13,8 @@ module Kobako
|
|
|
14
13
|
|
|
15
14
|
def self.track_handles: [T] { () -> T } -> [T, bool]
|
|
16
15
|
|
|
16
|
+
def self.within_value_budget: [T] (Integer? budget) { () -> T } -> T
|
|
17
|
+
|
|
17
18
|
# The Handle allocator/resolver a wire walk works against: alloc
|
|
18
19
|
# registers a non-wire-representable object and returns its Handle,
|
|
19
20
|
# fetch resolves a wire Handle id back to the live object. The
|
data/sig/kobako/context.rbs
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
module Kobako
|
|
2
2
|
class Context
|
|
3
|
+
type preamble = [Array[String], Array[Kobako::Catalog::Snippets::tuple], Array[Kobako::Catalog::Flags::tuple]]
|
|
4
|
+
|
|
5
|
+
@mounts: Hash[String, Kobako::Catalog::Mount]?
|
|
6
|
+
|
|
3
7
|
def initialize: (
|
|
4
8
|
runtime: Kobako::Runtime,
|
|
5
9
|
services: Kobako::Catalog::Services,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
extensions: Kobako::Catalog::Extensions,
|
|
11
|
+
grants: Kobako::Catalog::Grants,
|
|
12
|
+
preamble: preamble
|
|
9
13
|
) -> void
|
|
10
14
|
|
|
11
15
|
def bind: (Symbol | String path, untyped object) -> self
|
|
12
16
|
|
|
17
|
+
def mount: (String at, Kobako::Filesystem::mountable filesystem, ?access: Kobako::Filesystem::access) ?{ (String path, Kobako::Filesystem::access access) -> boolish } -> self
|
|
18
|
+
|
|
13
19
|
def lookup: (Symbol | String path) -> Kobako::Transport::Exposure
|
|
14
20
|
|
|
15
21
|
def eval: (String code) ?{ (Kobako::Context) -> void } -> Kobako::Execution
|
|
@@ -18,18 +24,20 @@ module Kobako
|
|
|
18
24
|
|
|
19
25
|
private
|
|
20
26
|
|
|
27
|
+
def setup: () -> Kobako::Runtime::setup
|
|
28
|
+
|
|
21
29
|
def collect_overrides: () { (Kobako::Context) -> void } -> void
|
|
22
30
|
|
|
23
31
|
def dispatch_handler: () -> Kobako::Transport::dispatch_proc
|
|
24
32
|
|
|
25
|
-
def populate_observability
|
|
33
|
+
def populate_observability:(Kobako::Snapshot snapshot) -> void
|
|
26
34
|
|
|
27
35
|
def with_verb: (Kobako::TrapError err, Symbol verb) -> Kobako::TrapError
|
|
28
36
|
|
|
29
37
|
def build_execution: (untyped value, failed: bool) -> Kobako::Execution
|
|
30
38
|
|
|
31
|
-
def settle_outcome: (Kobako::
|
|
39
|
+
def settle_outcome: (Kobako::Snapshot snapshot, Symbol verb, Symbol? entrypoint) -> Kobako::Execution
|
|
32
40
|
|
|
33
|
-
def invoke
|
|
41
|
+
def invoke: (Symbol verb, ?entrypoint: Symbol?) { () -> Kobako::Snapshot } -> Kobako::Execution
|
|
34
42
|
end
|
|
35
43
|
end
|
data/sig/kobako/errors.rbs
CHANGED
|
@@ -2,14 +2,14 @@ module Kobako
|
|
|
2
2
|
class Error < StandardError
|
|
3
3
|
end
|
|
4
4
|
|
|
5
|
-
module
|
|
5
|
+
module Recorded
|
|
6
6
|
attr_reader execution: Kobako::Execution?
|
|
7
7
|
|
|
8
8
|
def with_execution: (Kobako::Execution execution) -> self
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
class TrapError < Error
|
|
12
|
-
include
|
|
12
|
+
include Recorded
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
class TimeoutError < TrapError
|
|
@@ -39,12 +39,12 @@ module Kobako
|
|
|
39
39
|
|
|
40
40
|
class SandboxError < Error
|
|
41
41
|
include Diagnosable
|
|
42
|
-
include
|
|
42
|
+
include Recorded
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
class ServiceError < Error
|
|
46
46
|
include Diagnosable
|
|
47
|
-
include
|
|
47
|
+
include Recorded
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
class NoServiceError < ServiceError
|