kobako 0.28.0-aarch64-linux → 0.29.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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.release-please-manifest.json +1 -1
  3. data/CHANGELOG.md +170 -0
  4. data/README.md +154 -36
  5. data/ROADMAP.md +5 -0
  6. data/SECURITY.md +1 -1
  7. data/crates/kobako-runtime/CHANGELOG.md +86 -0
  8. data/crates/kobako-runtime/README.md +13 -8
  9. data/crates/kobako-transport/CHANGELOG.md +17 -0
  10. data/crates/kobako-transport/README.md +1 -1
  11. data/crates/kobako-wasmtime/CHANGELOG.md +119 -0
  12. data/crates/kobako-wasmtime/README.md +5 -3
  13. data/data/kobako.wasm +0 -0
  14. data/lib/kobako/3.3/kobako.so +0 -0
  15. data/lib/kobako/3.4/kobako.so +0 -0
  16. data/lib/kobako/4.0/kobako.so +0 -0
  17. data/lib/kobako/catalog/flags.rb +2 -14
  18. data/lib/kobako/catalog/grants.rb +30 -0
  19. data/lib/kobako/catalog/mount.rb +27 -0
  20. data/lib/kobako/catalog/services.rb +11 -0
  21. data/lib/kobako/catalog/snippets.rb +5 -9
  22. data/lib/kobako/catalog.rb +11 -0
  23. data/lib/kobako/codec/decoder.rb +1 -0
  24. data/lib/kobako/codec/ext_types.rb +1 -1
  25. data/lib/kobako/codec/state.rb +19 -3
  26. data/lib/kobako/codec/value_budget.rb +86 -0
  27. data/lib/kobako/codec.rb +7 -0
  28. data/lib/kobako/context.rb +38 -11
  29. data/lib/kobako/errors.rb +15 -14
  30. data/lib/kobako/filesystem.rb +38 -0
  31. data/lib/kobako/pool.rb +2 -2
  32. data/lib/kobako/sandbox.rb +40 -12
  33. data/lib/kobako/sandbox_options.rb +39 -12
  34. data/lib/kobako/snippet/{binary.rb → bytecode.rb} +1 -1
  35. data/lib/kobako/snippet.rb +1 -1
  36. data/lib/kobako/transport/block_failure.rb +35 -0
  37. data/lib/kobako/transport/dispatcher.rb +30 -26
  38. data/lib/kobako/transport/exposure.rb +5 -7
  39. data/lib/kobako/transport/reflection.rb +79 -23
  40. data/lib/kobako/transport/yielder.rb +8 -30
  41. data/lib/kobako/transport.rb +1 -0
  42. data/lib/kobako/version.rb +1 -1
  43. data/lib/kobako.rb +1 -0
  44. data/sig/kobako/catalog/flags.rbs +0 -4
  45. data/sig/kobako/catalog/grants.rbs +13 -0
  46. data/sig/kobako/catalog/mount.rbs +28 -0
  47. data/sig/kobako/catalog/services.rbs +4 -0
  48. data/sig/kobako/catalog/snippets.rbs +1 -1
  49. data/sig/kobako/catalog.rbs +1 -0
  50. data/sig/kobako/codec/state.rbs +7 -1
  51. data/sig/kobako/codec/value_budget.rbs +23 -0
  52. data/sig/kobako/codec.rbs +2 -0
  53. data/sig/kobako/context.rbs +14 -6
  54. data/sig/kobako/errors.rbs +4 -4
  55. data/sig/kobako/filesystem.rbs +88 -0
  56. data/sig/kobako/guest_yielder.rbs +9 -0
  57. data/sig/kobako/pool.rbs +1 -1
  58. data/sig/kobako/runtime.rbs +21 -49
  59. data/sig/kobako/sandbox.rbs +7 -1
  60. data/sig/kobako/sandbox_options.rbs +24 -2
  61. data/sig/kobako/snapshot.rbs +20 -0
  62. data/sig/kobako/snippet/bytecode.rbs +12 -0
  63. data/sig/kobako/transport/block_failure.rbs +13 -0
  64. data/sig/kobako/transport/dispatcher.rbs +3 -3
  65. data/sig/kobako/transport/exposure.rbs +1 -1
  66. data/sig/kobako/transport/reflection.rbs +14 -1
  67. data/sig/kobako/transport/yielder.rbs +3 -7
  68. data/sig/kobako/transport.rbs +2 -2
  69. metadata +26 -8
  70. data/sig/kobako/snippet/binary.rbs +0 -12
@@ -3,18 +3,20 @@
3
3
  require_relative "../codec"
4
4
  require_relative "../errors"
5
5
  require_relative "../payload"
6
+ require_relative "block_failure"
6
7
  require_relative "call"
7
8
  require_relative "reflection"
8
9
  require_relative "yielder"
9
10
 
10
11
  module Kobako
11
12
  module Transport
12
- # Answers a routed Call with +[true, body, nil]+ or
13
- # +[false, message, fault_type]+ and never raises, so every failure
14
- # reaches the guest as a fault.
13
+ # Answers a routed Call with one arm per Reply variant: +[:ok, body, nil]+,
14
+ # +[:fault, message, fault_type]+, or +[:break, "", nil]+ — a block
15
+ # exit the guest kept carries nothing. It never raises, so every
16
+ # failure reaches the guest as a fault.
15
17
  module Dispatcher # :nodoc:
16
- # Throw tag for the Yielder's break unwind back to the
17
- # dispatcher's +catch+ frame. +private_constant+ is a
18
+ # Thrown rather than raised, so a Service unwound by a block exit runs
19
+ # its +ensure+ and cannot +rescue+ the exit. +private_constant+ is a
18
20
  # convention boundary — not a defence.
19
21
  BREAK_THROW = :__kobako_break__
20
22
  private_constant :BREAK_THROW
@@ -23,15 +25,18 @@ module Kobako
23
25
 
24
26
  class UnreadableRequestError < Kobako::Codec::Error; end # :nodoc:
25
27
 
26
- # The category kobako's own refusals answer under, keyed by the class
27
- # each is raised as and ordered most specific first. A class absent
28
- # here is the Service's own exception, which answers under +runtime+
29
- # wearing the +<class>: <message>+ shape that says so.
28
+ # The category each failure answering with its message alone takes,
29
+ # keyed by the class raised and ordered most specific first. kobako's
30
+ # own refusals are worded so none reads as a Service's exception, and
31
+ # +ArgumentError+, raised by a Service and by a call that will not
32
+ # bind alike, is named by +argument+ already. A class absent here is
33
+ # the Service's own exception, which answers under +runtime+ wearing
34
+ # the +<class>: <message>+ shape that names it.
30
35
  #
31
36
  # +Kobako::Codec::Error+ is the floor rather than a path of its own:
32
37
  # a codec fault reaching the boundary unnamed is the exchange failing,
33
38
  # and must not be dressed as something a Service raised.
34
- OWN_FAULTS = {
39
+ BARE_FAULTS = {
35
40
  HandleExhaustedError => "internal",
36
41
  UndefinedTargetError => "undefined",
37
42
  ArgumentError => "argument",
@@ -40,23 +45,24 @@ module Kobako
40
45
  Kobako::Codec::Error => "internal",
41
46
  Kobako::SandboxError => "runtime"
42
47
  }.freeze
43
- private_constant :OWN_FAULTS
48
+ private_constant :BARE_FAULTS
44
49
 
45
50
  # The per-invocation state arrives as arguments so the Dispatcher
46
51
  # stays stateless and neither the resolver nor the Context publishes
47
52
  # accessors for it.
48
- def self.dispatch(call, resolver, handles, guest_yielder)
49
- yielder = Yielder.new(guest_yielder, BREAK_THROW, handles) if call.block_given
50
- [true, encode_ok(run(call, resolver, handles, yielder), handles), nil] # : [bool, String, String?]
53
+ def self.dispatch(call, resolver, handles, failure, guest_yielder)
54
+ yielder = Yielder.new(guest_yielder, BREAK_THROW, handles, failure) if call.block_given
55
+ catch(BREAK_THROW) { return [:ok, encode_ok(run(call, resolver, handles, yielder), handles), nil] }
56
+ [:break, "", nil] # : [Symbol, String, String?]
51
57
  # StandardError is the boundary by intent: a Service method's
52
58
  # application fault folds into a guest-rescuable fault, while a
53
59
  # host-process failure (NoMemoryError, SignalException, a bare Exception)
54
60
  # stays uncaught and traps the invocation rather than being masked as a
55
61
  # rescuable fault.
56
62
  rescue StandardError => e
57
- [false, *caught_fault(e, yielder)] # : [bool, String, String?]
63
+ [:fault, *caught_fault(e, failure)] # : [Symbol, String, String?]
58
64
  ensure
59
- yielder&.invalidate!
65
+ yielder&.invalidate
60
66
  end
61
67
 
62
68
  class << self
@@ -66,7 +72,7 @@ module Kobako
66
72
  arguments, carried_handle = decode_arguments(call.payload)
67
73
  exposure = resolve_target(call.target, resolver, handles)
68
74
  args, kwargs = resolve_call_args(arguments, handles, carried_handle)
69
- catch(BREAK_THROW) { invoke(exposure, call.method_name, args, kwargs, yielder) }
75
+ invoke(exposure, call.method_name, args, kwargs, yielder)
70
76
  end
71
77
 
72
78
  # A codec fault here is a request that never became a call, restated
@@ -84,21 +90,19 @@ module Kobako
84
90
  arguments.kwargs.transform_values { |v| resolve_arg(v, handles) }]
85
91
  end
86
92
 
87
- # The class prefix marks a Service's own exception and nothing else:
88
- # it is the +<class>: <message>+ shape a Host App is told to keep
89
- # secrets out of, so wearing it says the Service raised. kobako's own
90
- # refusals answer under their own wording instead of borrowing that
91
- # shape.
93
+ # The class prefix marks a Service's own exception that its category
94
+ # does not name: it is the +<class>: <message>+ shape a Host App is
95
+ # told to keep secrets out of, so wearing it says the Service raised.
92
96
  #
93
97
  # The guest's own block failing is not the Service's to report at
94
98
  # all, so the Yielder that raised it is asked first — it recognises
95
99
  # its own by identity and words the failure the guest's way.
96
- def caught_fault(error, yielder)
97
- block_failure = yielder&.fault_text(error)
100
+ def caught_fault(error, failure)
101
+ block_failure = failure.fault_text(error)
98
102
  return fault("block", block_failure) if block_failure
99
103
 
100
- own = OWN_FAULTS.find { |klass, _| error.is_a?(klass) }
101
- return fault(own.last, error.message) if own
104
+ bare = BARE_FAULTS.find { |klass, _| error.is_a?(klass) }
105
+ return fault(bare.last, error.message) if bare
102
106
 
103
107
  fault("runtime", "#{error.class}: #{error.message}")
104
108
  end
@@ -68,7 +68,7 @@ module Kobako
68
68
  end
69
69
 
70
70
  def class_names(object, klass)
71
- names = authored(klass)
71
+ names = authored_names(klass)
72
72
  case object
73
73
  when Struct, Data then names.concat(object.members)
74
74
  end
@@ -78,15 +78,13 @@ module Kobako
78
78
  def with_singleton(object, names)
79
79
  return names if SINGLETON_METHODS.bind_call(object, false).empty?
80
80
 
81
- names.union(authored(SINGLETON_CLASS_OF.bind_call(object))).freeze
81
+ names.union(authored_names(SINGLETON_CLASS_OF.bind_call(object))).freeze
82
82
  end
83
83
 
84
- # The public methods +owner+ itself defines in source. A method with
85
- # no source, or whose source is the platform's own, is built in.
86
- def authored(owner)
84
+ # The public methods +owner+ itself defines in Ruby source.
85
+ def authored_names(owner)
87
86
  owner.public_instance_methods(false).select do |name|
88
- file, = owner.instance_method(name).source_location
89
- file && !file.start_with?("<internal:")
87
+ Reflection.authored?(owner.instance_method(name))
90
88
  end
91
89
  end
92
90
  end
@@ -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 is a META_OWNERS or GADGET_OWNERS module — or a singleton
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 +NameError+ branch below, never by
59
- # naming +method_missing+.
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 "method #{name.inspect} is not a Service method" if name == :method_missing
80
+ return refused(name) if name == :method_missing
81
+
82
+ klass = lookup_class(target)
83
+ return defined_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 refused(name) if klass.method_defined?(name) || klass.private_method_defined?(name)
62
86
 
63
- owner = target.public_method(name).owner
87
+ owner_refusal(target, name, klass)
88
+ end
89
+
90
+ def defined_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 : refused(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 refused(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
- "method #{name.inspect} is not a Service method"
68
- rescue NameError
69
- return nil if target.respond_to?(name)
113
+ refused(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
- "no public method #{name.inspect} on target"
122
+ target.class
72
123
  end
73
124
 
74
- # A plain object's own singleton method (+def obj.x+) stays reachable,
75
- # since only a Module target counts its singleton class as ambient.
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
- META_OWNERS.include?(owner) ||
133
+ owner >= Class ||
78
134
  GADGET_OWNERS.include?(owner) ||
79
135
  (target.is_a?(Module) && owner.singleton_class?)
80
136
  end
@@ -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. The break value unwinds back to the guest, so it
33
- # passes through verbatim and rides back on the same id rather than
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
- value, carried_handle = decode_body(body)
43
- throw @break_tag, value if arm == :break
27
+ throw @break_tag if arm == :break
44
28
 
45
- restore(value, carried_handle)
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
 
@@ -64,12 +48,6 @@ module Kobako
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.
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "transport/call"
4
4
  require_relative "transport/run"
5
+ require_relative "transport/block_failure"
5
6
  require_relative "transport/yielder"
6
7
  require_relative "transport/error"
7
8
  require_relative "transport/exposure"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kobako
4
- VERSION = "0.28.0"
4
+ VERSION = "0.29.0"
5
5
  end
data/lib/kobako.rb CHANGED
@@ -9,6 +9,7 @@ rescue LoadError
9
9
  require "kobako/kobako"
10
10
  end
11
11
 
12
+ require_relative "kobako/filesystem"
12
13
  require_relative "kobako/errors"
13
14
  require_relative "kobako/unresolved"
14
15
  require_relative "kobako/extension"
@@ -8,10 +8,6 @@ module Kobako
8
8
  def entries: () -> Array[tuple]
9
9
 
10
10
  def register: (Symbol | String name, String value, advisory: bool) -> nil
11
-
12
- private
13
-
14
- def utf8!: (String text, String what) -> String
15
11
  end
16
12
  end
17
13
  end
@@ -0,0 +1,13 @@
1
+ module Kobako
2
+ module Catalog
3
+ class Grants
4
+ def initialize: () -> void
5
+
6
+ def register: (Mount grant) -> nil
7
+
8
+ def include?: (Mount grant) -> bool
9
+
10
+ def entries: (?Hash[String, Mount] overrides) -> Array[Mount::tuple]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,28 @@
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
+
23
+ private
24
+
25
+ def nested?: (String other) -> bool
26
+ end
27
+ end
28
+ 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
@@ -15,6 +17,8 @@ module Kobako
15
17
 
16
18
  def validate_path!: (Symbol | String path) -> String
17
19
 
20
+ def reserved?: (String path) -> bool
21
+
18
22
  def collision?: (String path) -> bool
19
23
  end
20
24
  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::Binary
4
+ type entry = Kobako::Snippet::Source | Kobako::Snippet::Bytecode
5
5
 
6
6
  type tuple = [Symbol, String?, String]
7
7
 
@@ -1,4 +1,5 @@
1
1
  module Kobako
2
2
  module Catalog
3
+ def self.to_utf8!: (String text, String what) -> String
3
4
  end
4
5
  end
@@ -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!: () -> void
14
+ def record_handle: () -> void
15
+ def within_value_budget: [T] (Integer? budget) { () -> T } -> T
10
16
 
11
17
  private
12
18
 
@@ -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
@@ -14,6 +14,8 @@ module Kobako
14
14
 
15
15
  def self.track_handles: [T] { () -> T } -> [T, bool]
16
16
 
17
+ def self.within_value_budget: [T] (Integer? budget) { () -> T } -> T
18
+
17
19
  # The Handle allocator/resolver a wire walk works against: alloc
18
20
  # registers a non-wire-representable object and returns its Handle,
19
21
  # fetch resolves a wire Handle id back to the live object. The
@@ -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
- snippets: Kobako::Catalog::Snippets,
7
- flags: Kobako::Catalog::Flags,
8
- extensions: Kobako::Catalog::Extensions
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!: (Kobako::Runtime::Snapshot snapshot) -> void
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::Runtime::Snapshot snapshot, Symbol verb, Symbol? entrypoint) -> Kobako::Execution
39
+ def settle_outcome: (Kobako::Snapshot snapshot, Symbol verb, Symbol? entrypoint) -> Kobako::Execution
32
40
 
33
- def invoke!: (Symbol verb, ?entrypoint: Symbol?) { () -> Kobako::Runtime::Snapshot } -> Kobako::Execution
41
+ def invoke!: (Symbol verb, ?entrypoint: Symbol?) { () -> Kobako::Snapshot } -> Kobako::Execution
34
42
  end
35
43
  end
@@ -2,14 +2,14 @@ module Kobako
2
2
  class Error < StandardError
3
3
  end
4
4
 
5
- module CarriesExecution
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 CarriesExecution
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 CarriesExecution
42
+ include Recorded
43
43
  end
44
44
 
45
45
  class ServiceError < Error
46
46
  include Diagnosable
47
- include CarriesExecution
47
+ include Recorded
48
48
  end
49
49
 
50
50
  class NoServiceError < ServiceError