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
@@ -1,5 +1,91 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.19.0](https://github.com/elct9620/kobako/compare/kobako-runtime-v0.18.0...kobako-runtime-v0.19.0) (2026-10-26)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * **runtime:** a struct literal no longer builds OpenOptions, Metadata, DirEntry, Snapshot, Capture, or Usage outside kobako-runtime; use their `new` or `Default` and assign each field.
9
+ * the Guest ABI is version 5, so a Guest Binary built against version 4 is refused at Sandbox construction until rebuilt. The Yielder trait of kobako-runtime gains frame and takes the frame in yield_to_block; the Guest trait of kobako-core and the MrbGuest trait of kobako-mruby take the frame in yield_to_block; Downcall::Yield carries frame and args.
10
+ * **runtime:** the Runtime trait's invoke takes the invocation's Grants as a fourth argument, so every engine implementing it must accept them.
11
+
12
+ ### Features
13
+
14
+ * check what a rename moves as it moves, refusing a directory beneath a Policy ([23794bf](https://github.com/elct9620/kobako/commit/23794bfcb54e148126e29873fa9b52d9e3de8d8c))
15
+ * **runtime:** bound the files and directories a Memory or Temporary holds ([8d0be0a](https://github.com/elct9620/kobako/commit/8d0be0ab3dc8c11bcb96865b0bf1a0bbb8dd3b16))
16
+ * **runtime:** bound what a Memory or Temporary holds, 64 MiB by default ([2557d1b](https://github.com/elct9620/kobako/commit/2557d1ba7530aacfddf908aeddac561c4fbc5c8a))
17
+ * **runtime:** draw every device a host does not name from one source ([210d55b](https://github.com/elct9620/kobako/commit/210d55b1b4e0699dc5ef56b4b6930be01658a3c6))
18
+ * **runtime:** hand each invocation its Grants and let an engine declare the kinds it supports ([cba90ee](https://github.com/elct9620/kobako/commit/cba90eed09c8afcb23080cef1c9cbb3650648472)), closes [#78](https://github.com/elct9620/kobako/issues/78)
19
+ * **runtime:** keep a directory descriptor's identity its own while open ([6267642](https://github.com/elct9620/kobako/commit/6267642ea831917be76a0101e8d206ccfa8834c1))
20
+ * **runtime:** let a dispatch handler abandon its invocation ([179da9e](https://github.com/elct9620/kobako/commit/179da9ee1f31fed9e6d0c149faee0ad55f8db487))
21
+ * **runtime:** let a Filesystem's file refuse its close ([af16007](https://github.com/elct9620/kobako/commit/af1600797b098796dd6f329672c7d04e2e1cd2fa)), closes [#78](https://github.com/elct9620/kobako/issues/78)
22
+ * **runtime:** let a Mount decide its own access as the one kind of Grant ([5c9189e](https://github.com/elct9620/kobako/commit/5c9189eea8ac61cf165dca1b38e459c4f14acdd0)), closes [#78](https://github.com/elct9620/kobako/issues/78)
23
+ * **runtime:** let a Mount's Policy judge the spelling the host stores ([5281057](https://github.com/elct9620/kobako/commit/52810573f22d2a3edfae9b34b7767a5f440fba15))
24
+ * **runtime:** let the records a Filesystem or an engine builds gain fields ([c0ef88d](https://github.com/elct9620/kobako/commit/c0ef88d0b6df16d651e4c49226e41667307d772f))
25
+ * **runtime:** name a file grown past what a Filesystem keeps ([7bac3e6](https://github.com/elct9620/kobako/commit/7bac3e65534097b85d93f5967b6c73a979869a78))
26
+ * **runtime:** name each code a Filesystem may fail with ([1d980fa](https://github.com/elct9620/kobako/commit/1d980fa4328bad42e8a8665adfec9fc844690e97))
27
+ * **runtime:** name the POSIX error each FilesystemError stands for ([01c301b](https://github.com/elct9620/kobako/commit/01c301b4af9f489594eb7a98ab48c508e5b61ca4))
28
+ * **runtime:** refuse a Memory seed path through `..` ([b31434d](https://github.com/elct9620/kobako/commit/b31434d386ebde838c15755619c67da95311ecf6))
29
+ * **runtime:** refuse a Mount at a path that is no absolute guest path ([a525758](https://github.com/elct9620/kobako/commit/a5257589f9d831b9a3b6d1952df6e5c8469630e1))
30
+ * **runtime:** report a link a lookup does not follow as a link ([8c1e0b3](https://github.com/elct9620/kobako/commit/8c1e0b3e63fbc91b10f11cd91817ce94de24c7e6))
31
+ * **runtime:** report the identity of what a path holds ([392bc0e](https://github.com/elct9620/kobako/commit/392bc0e9f2fb935934a0031bf7d64dec0b27df6a))
32
+ * **runtime:** say whether a path beneath a Mount may pass a link ([7706a25](https://github.com/elct9620/kobako/commit/7706a2537bf8e5975b2b227bef0c05cb48c09f4b))
33
+ * **runtime:** seed a Memory from a list that may not hold, answering why ([8ac2dfd](https://github.com/elct9620/kobako/commit/8ac2dfdf73b84fe2e53405a653d861ddca9ea98c))
34
+ * **runtime:** ship the Memory, Temporary, Directory, and Overlay filesystems ([c60c453](https://github.com/elct9620/kobako/commit/c60c4535e966ffd501e03d7be7fef0a44d860b0b)), closes [#78](https://github.com/elct9620/kobako/issues/78)
35
+ * **runtime:** stack an Overlay from Layers, each read-only or writable ([6c88188](https://github.com/elct9620/kobako/commit/6c88188cd7992c218f8c5a3be30981e685804078)), closes [#78](https://github.com/elct9620/kobako/issues/78)
36
+
37
+
38
+ ### Bug Fixes
39
+
40
+ * append through a Filesystem's file only in one step ([0509ca7](https://github.com/elct9620/kobako/commit/0509ca70d2d5a832303973ba0f7280be0731fd3d))
41
+ * ask a mount's block once for a read ([f89bd16](https://github.com/elct9620/kobako/commit/f89bd16c1a71ed1d385ab9d3ac5974ac3f0a9103))
42
+ * follow no link swapped in after a Policy judges a path ([ed93213](https://github.com/elct9620/kobako/commit/ed9321303dd45e113fc413e99e1240118cc4bbe4))
43
+ * hold an Overlay's lock across each call, waiting without the GVL ([b8e7342](https://github.com/elct9620/kobako/commit/b8e734273fdc577a40be97c43c46d9548d66c625))
44
+ * keep a link within the directory a descriptor opened ([952dd05](https://github.com/elct9620/kobako/commit/952dd0556969683f44798da94f9fc7a17c1f6d55))
45
+ * run a stored block as the block of the Call that carried it ([bf33dc1](https://github.com/elct9620/kobako/commit/bf33dc1fd40c83498c6c12b0be52b3a835a144cf))
46
+ * **runtime:** answer a host failure as the error naming it ([effd43a](https://github.com/elct9620/kobako/commit/effd43a85a3ba69aaa068d2c384c3b5cb466161c))
47
+ * **runtime:** append to a Directory file in one host write ([4a5450a](https://github.com/elct9620/kobako/commit/4a5450a67e202e45299175c4fe7528cf50489f0e))
48
+ * **runtime:** copy a file up whole when its Layer writes in parts ([89d87f7](https://github.com/elct9620/kobako/commit/89d87f7225611786467968ec34eba5a8223b5fc5))
49
+ * **runtime:** fail an Overlay call a Layer cannot answer instead of guessing ([5ba0db3](https://github.com/elct9620/kobako/commit/5ba0db33c56ed837401bcb62345f81b4b50c317a))
50
+ * **runtime:** hold each Memory entry under its own name ([8f1ba8a](https://github.com/elct9620/kobako/commit/8f1ba8a50d3d8ca3a695115d51b605be1f18e29e))
51
+ * **runtime:** judge a link an Overlay's Layer holds as the link itself ([959c1f3](https://github.com/elct9620/kobako/commit/959c1f3dab6f6948baabbd914bbb86dfff090f7b))
52
+ * **runtime:** keep an Overlay rename to one Layer and answer a landed change as done ([e3405b7](https://github.com/elct9620/kobako/commit/e3405b7139809ada202ffdb0d6bf1eef3dcbf056))
53
+ * **runtime:** leave a Memory file as it was on a write of no bytes ([9f8fd23](https://github.com/elct9620/kobako/commit/9f8fd237b9b0042590b149f9b2051e0773d8b9af))
54
+ * **runtime:** leave an Overlay unchanged when a removal or rename is refused ([a7bee4b](https://github.com/elct9620/kobako/commit/a7bee4b2a465a0ef0ad2e376c281dca82a0df0e1))
55
+ * **runtime:** let a file or link in a Layer hide what lies below it ([fd579f6](https://github.com/elct9620/kobako/commit/fd579f679cfa8a83ec7d139066bc1a4570af398b))
56
+ * **runtime:** make every Filesystem answer the methods that keep a guarantee ([00f5af6](https://github.com/elct9620/kobako/commit/00f5af63f34ac7722249746d0b0eb566da618803))
57
+ * **runtime:** move a directory made again as the writable Layer's own ([ac3e864](https://github.com/elct9620/kobako/commit/ac3e864bbb0ce5d61def45e0403239be405481d3))
58
+ * **runtime:** move a directory onto one that holds only markers ([934f0c3](https://github.com/elct9620/kobako/commit/934f0c39e0ad1189bdb1cb0461671245dea32f93))
59
+ * **runtime:** open a Directory file the runtime neither reads nor writes ([6b30858](https://github.com/elct9620/kobako/commit/6b308583383d6803894b2c7af1a9ef05d72b0e7d)), closes [#78](https://github.com/elct9620/kobako/issues/78)
60
+ * **runtime:** open a file already there without writing to create it ([7f76a1a](https://github.com/elct9620/kobako/commit/7f76a1af575739ae16c5daeb1df8268af44cea63))
61
+ * **runtime:** panic on files a Memory cannot be seeded with ([cf5c835](https://github.com/elct9620/kobako/commit/cf5c835d7df8bf82972487280c6a6c79be955a68))
62
+ * **runtime:** put an Overlay's markers back when the change fails ([78ddeed](https://github.com/elct9620/kobako/commit/78ddeeddda8b9f797a80ec3796b28e04cf99ffc9))
63
+ * **runtime:** refuse a backslash in a Directory path on Windows ([88b5719](https://github.com/elct9620/kobako/commit/88b57195325b168395248a82b94a5ebf7e5f4142))
64
+ * **runtime:** refuse a Directory append on Windows rather than take two steps ([a528cc9](https://github.com/elct9620/kobako/commit/a528cc9577f1b2e1359699e2400be93c1f3a9be7))
65
+ * **runtime:** refuse a file moved beneath itself as no directory ([bfabb52](https://github.com/elct9620/kobako/commit/bfabb52b27080ee9e5000bd5524ea201a7e33d80))
66
+ * **runtime:** refuse a host name that is not UTF-8 as an illegal sequence ([c4ff030](https://github.com/elct9620/kobako/commit/c4ff030ffa8e29fa1b10df4aaf6af65162c76353))
67
+ * **runtime:** refuse a Memory file grown past what can be allocated ([302e2d4](https://github.com/elct9620/kobako/commit/302e2d4fcd5b31fee4e953e8993bb47d9a2a673a))
68
+ * **runtime:** refuse an Overlay change landing beneath a read-only Layer ([e7b2f19](https://github.com/elct9620/kobako/commit/e7b2f19156df9773f669cbe8a7aaefc17591cca3))
69
+ * **runtime:** refuse to open a FIFO, socket, or device beneath a Directory ([bdcaf78](https://github.com/elct9620/kobako/commit/bdcaf78bf131998648c65ac51ced4a588a79211f))
70
+ * **runtime:** remove no directory as a file on any host ([c9c0820](https://github.com/elct9620/kobako/commit/c9c0820fd39c0744b9d9c367b977f6587d1f9589))
71
+ * **runtime:** rename and copy up through an Overlay as overlayfs does ([ada5a86](https://github.com/elct9620/kobako/commit/ada5a86a8647d89666e9de808eb13ba638882e51))
72
+ * **runtime:** replace neither a FIFO nor a directory with the other through an Overlay ([8fed062](https://github.com/elct9620/kobako/commit/8fed062438e105c6a784bf4bde1582fda9e3c9c2))
73
+ * **runtime:** report a merged directory's identity alike through an Overlay's lstat ([ded3b4a](https://github.com/elct9620/kobako/commit/ded3b4aba78efa678318c38b139b5c9c76b5d3fd))
74
+ * **runtime:** require cap-std 4.0.3 for the trailing-slash lookup fix ([549cfe0](https://github.com/elct9620/kobako/commit/549cfe07fc8b9affdc8a1765a9e4bc5963ef546e))
75
+ * **runtime:** reserve an Overlay's marker name in any case ([ef39923](https://github.com/elct9620/kobako/commit/ef399230eabe01ad6eed632b2753880ae1fc322c))
76
+ * **runtime:** reserve exactly what a Memory file grows by ([96f8141](https://github.com/elct9620/kobako/commit/96f8141442cac2170a8bf8a76055d4f4659b1100))
77
+ * **runtime:** spell a Directory path's last name without following a link there ([c5e5ae7](https://github.com/elct9620/kobako/commit/c5e5ae74ec1f6ee07e24da08d7b097fb6a882961))
78
+ * **runtime:** spell a path on XFS by listing rather than trusting exact names ([f89495d](https://github.com/elct9620/kobako/commit/f89495dcfd7c6d05d46ebc5dbae0039856cc15c6))
79
+ * **wasmtime:** hold the whole invocation to its deadline ([231e325](https://github.com/elct9620/kobako/commit/231e32592699008adf3105050bee8b5528ea27a8))
80
+ * **wasmtime:** place an append at the end as the file stands when it lands ([d7291c4](https://github.com/elct9620/kobako/commit/d7291c4f32fb1f5f2494c69c76796476bbcf4d43))
81
+ * **wasmtime:** refuse a link an open asks not to follow ([123a01b](https://github.com/elct9620/kobako/commit/123a01b01f59cc69c0e3a23f9aeb01aa89132c07))
82
+
83
+
84
+ ### Performance Improvements
85
+
86
+ * **runtime:** list an Overlay directory in time linear to its entries ([be3f446](https://github.com/elct9620/kobako/commit/be3f446f782cbd72b114f7b6072e3b50c391f093))
87
+ * **runtime:** stop an Overlay's marker lookup at a directory a Layer lacks ([494fa09](https://github.com/elct9620/kobako/commit/494fa090e90806c50e4e8baaa4f1001efc388b45))
88
+
3
89
  ## [0.18.0](https://github.com/elct9620/kobako/compare/kobako-runtime-v0.17.0...kobako-runtime-v0.18.0) (2026-10-13)
4
90
 
5
91
 
@@ -4,9 +4,9 @@ Engine-neutral host runtime contract for
4
4
  [kobako](https://github.com/elct9620/kobako), an in-process Wasm
5
5
  sandbox for running untrusted mruby scripts.
6
6
 
7
- A kobako host drives a Guest Binary through a wasm engine; this crate
8
- is the surface where the two meet, free of any engine or frontend
9
- type, so the engine stays swappable.
7
+ A kobako host drives a Guest Binary through a wasm engine. This crate
8
+ is where the two meet, free of any engine or frontend type, so the
9
+ engine stays swappable.
10
10
 
11
11
  | Module | What it declares |
12
12
  |---|---|
@@ -14,19 +14,24 @@ type, so the engine stays swappable.
14
14
  | `snapshot` | each invocation's `Completion` (outcome or trap), both output `Capture`s, and `Usage` |
15
15
  | `error` | the neutral failure types: `Trap`, `SetupError`, and `InvokeError` over both |
16
16
  | `profile` | the isolation `Profile` a runtime declares |
17
+ | `grant` | the `Grant` a frontend hands each invocation, and the `GrantKind`s a runtime supports |
18
+ | `mount` | the `Mount` at a guest path, and the `Policy` judging its paths |
19
+ | `filesystem` | the `Filesystem` trait, its `Access`, and the four kinds kobako ships |
17
20
  | `dispatch` / `yielder` | the `DispatchHandler` and `Yielder` traits a frontend supplies for guest→host dispatch and block-yield re-entry |
18
21
 
19
- Engine implementations (such as `kobako-wasmtime`) implement
20
- `Runtime`; host frontends (such as the kobako Ruby gem's native ext)
21
- map the neutral types onto their own language surface.
22
+ Engine implementations such as `kobako-wasmtime` implement `Runtime`.
23
+ Host frontends such as the kobako Ruby gem's native ext map the neutral
24
+ types onto their own language surface.
22
25
 
23
26
  ## Usage
24
27
 
28
+ Add the crate to an engine or a frontend that speaks the contract.
29
+
25
30
  ```toml
26
31
  [dependencies]
27
- kobako-runtime = "0.18.0" # x-release-please-version
32
+ kobako-runtime = "0.19.0" # x-release-please-version
28
33
  ```
29
34
 
30
35
  ## License
31
36
 
32
- Apache-2.0
37
+ Licensed under [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0).
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.19.0](https://github.com/elct9620/kobako/compare/kobako-transport-v0.18.0...kobako-transport-v0.19.0) (2026-10-26)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * in kobako-transport, YieldReply::Break carries no payload and Reply gains a Break arm, so a Guest Binary built against the earlier version 5 wire must be rebuilt.
9
+ * the Guest ABI is version 5, so a Guest Binary built against version 4 is refused at Sandbox construction until rebuilt. The Yielder trait of kobako-runtime gains frame and takes the frame in yield_to_block; the Guest trait of kobako-core and the MrbGuest trait of kobako-mruby take the frame in yield_to_block; Downcall::Yield carries frame and args.
10
+
11
+ ### Features
12
+
13
+ * let a block's break or return unwind a Service as a plain method ([4e9eca0](https://github.com/elct9620/kobako/commit/4e9eca05f1647c8b6409fc00d08317b431c0c648))
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * run a stored block as the block of the Call that carried it ([bf33dc1](https://github.com/elct9620/kobako/commit/bf33dc1fd40c83498c6c12b0be52b3a835a144cf))
19
+
3
20
  ## [0.18.0](https://github.com/elct9620/kobako/compare/kobako-transport-v0.17.0...kobako-transport-v0.18.0) (2026-10-13)
4
21
 
5
22
 
@@ -51,7 +51,7 @@ reaches the same types through `kobako-core`.
51
51
 
52
52
  ```toml
53
53
  [dependencies]
54
- kobako-transport = "0.18.0" # x-release-please-version
54
+ kobako-transport = "0.19.0" # x-release-please-version
55
55
  ```
56
56
 
57
57
  ## License
@@ -1,5 +1,124 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.19.0](https://github.com/elct9620/kobako/compare/kobako-wasmtime-v0.18.0...kobako-wasmtime-v0.19.0) (2026-10-26)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * **io:** File.open raises ArgumentError for a mode such as bw, where b leads, or wbt, holding both b and t, as CRuby does, instead of opening the file.
9
+ * **wasmtime:** a call through a directory descriptor answers ENOENT when the directory at its path is not the one it opened, where it used to reach that directory.
10
+ * **wasmtime:** a struct literal no longer builds the wasmtime driver's Config outside its crate; start from `Config::default()` and assign each field.
11
+ * **runtime:** a struct literal no longer builds OpenOptions, Metadata, DirEntry, Snapshot, Capture, or Usage outside kobako-runtime; use their `new` or `Default` and assign each field.
12
+ * the wasmtime Config and the SDK Options gain a setup_timeout field, so a struct literal that names every field must add it; one built from Options::default() is unaffected.
13
+ * **wasmtime:** a Service answer past 16 MiB now raises a Service failure in the guest where it used to raise the transport error, and an answer the host cannot write into guest memory now traps the invocation.
14
+ * the Guest ABI is version 5, so a Guest Binary built against version 4 is refused at Sandbox construction until rebuilt. The Yielder trait of kobako-runtime gains frame and takes the frame in yield_to_block; the Guest trait of kobako-core and the MrbGuest trait of kobako-mruby take the frame in yield_to_block; Downcall::Yield carries frame and args.
15
+ * **io:** putc, IO#read and SystemCallError.new raise RangeError for those numbers instead of writing, refusing or ignoring them.
16
+ * **guest:** the default memory_limit is now 4 MiB. JSON.parse in the guest answers an Integer for every integer within 64 bits, where it used to answer a Float past 32 bits. An integer past 64 bits now raises
17
+ * **wasmtime:** a struct literal building the wasmtime driver's Config must set the new `open_file_limit` field.
18
+ * **io:** a script writing to a file through `IO#write` beneath a Mount now raises on a failed write where it used to go on.
19
+ * **io:** a script rescuing IOError for a failed read or write beneath a Mount must rescue the EIO error class, or SystemCallError, instead.
20
+ * **guest:** a Service or Extension backend bound at the path File fails its first invocation, naming the segment the Guest Binary now defines.
21
+ * **runtime:** the Runtime trait's invoke takes the invocation's Grants as a fourth argument, so every engine implementing it must accept them.
22
+
23
+ ### Features
24
+
25
+ * check what a rename moves as it moves, refusing a directory beneath a Policy ([23794bf](https://github.com/elct9620/kobako/commit/23794bfcb54e148126e29873fa9b52d9e3de8d8c))
26
+ * **guest:** carry mruby-bigint so an Integer has no width of its own ([a74266d](https://github.com/elct9620/kobako/commit/a74266d3e7b1295b75770b62894b232195f9b3bb))
27
+ * **guest:** ship File in the default Guest Binary over the filesystem Grants ([535527b](https://github.com/elct9620/kobako/commit/535527b2c6beb82fe37758df62c3804ce5c7191a)), closes [#78](https://github.com/elct9620/kobako/issues/78)
28
+ * **guest:** widen the guest Integer to 64 bits ([7236a26](https://github.com/elct9620/kobako/commit/7236a26285dfdef175048f659c1094dd3bbb5b4d))
29
+ * **io:** create a file only where nothing is through File.open's wx ([56c5665](https://github.com/elct9620/kobako/commit/56c5665e4c87ac30b8035aaed207ce840efad25c))
30
+ * **io:** open a file by an Integer mode of File::Constants flags ([e1f484c](https://github.com/elct9620/kobako/commit/e1f484c713df4d894744833836cf9a29ba9677ee))
31
+ * **io:** open a file through wasi-libc so a create needs no write ([6d50ca4](https://github.com/elct9620/kobako/commit/6d50ca4d79b70956d113f0798255300aa8a7fe92))
32
+ * let a Host App bound how long a Guest Binary takes to be set up ([2addab0](https://github.com/elct9620/kobako/commit/2addab002550539e3ebb24bdd599dd424c2dc3d9))
33
+ * **runtime:** hand each invocation its Grants and let an engine declare the kinds it supports ([cba90ee](https://github.com/elct9620/kobako/commit/cba90eed09c8afcb23080cef1c9cbb3650648472)), closes [#78](https://github.com/elct9620/kobako/issues/78)
34
+ * **runtime:** keep a directory descriptor's identity its own while open ([6267642](https://github.com/elct9620/kobako/commit/6267642ea831917be76a0101e8d206ccfa8834c1))
35
+ * **runtime:** let a dispatch handler abandon its invocation ([179da9e](https://github.com/elct9620/kobako/commit/179da9ee1f31fed9e6d0c149faee0ad55f8db487))
36
+ * **runtime:** let a Filesystem's file refuse its close ([af16007](https://github.com/elct9620/kobako/commit/af1600797b098796dd6f329672c7d04e2e1cd2fa)), closes [#78](https://github.com/elct9620/kobako/issues/78)
37
+ * **runtime:** let a Mount decide its own access as the one kind of Grant ([5c9189e](https://github.com/elct9620/kobako/commit/5c9189eea8ac61cf165dca1b38e459c4f14acdd0)), closes [#78](https://github.com/elct9620/kobako/issues/78)
38
+ * **runtime:** let a Mount's Policy judge the spelling the host stores ([5281057](https://github.com/elct9620/kobako/commit/52810573f22d2a3edfae9b34b7767a5f440fba15))
39
+ * **runtime:** let the records a Filesystem or an engine builds gain fields ([c0ef88d](https://github.com/elct9620/kobako/commit/c0ef88d0b6df16d651e4c49226e41667307d772f))
40
+ * **runtime:** name a file grown past what a Filesystem keeps ([7bac3e6](https://github.com/elct9620/kobako/commit/7bac3e65534097b85d93f5967b6c73a979869a78))
41
+ * **runtime:** name each code a Filesystem may fail with ([1d980fa](https://github.com/elct9620/kobako/commit/1d980fa4328bad42e8a8665adfec9fc844690e97))
42
+ * **runtime:** refuse a Mount at a path that is no absolute guest path ([a525758](https://github.com/elct9620/kobako/commit/a5257589f9d831b9a3b6d1952df6e5c8469630e1))
43
+ * **wasmtime:** answer a Filesystem out of space as ENOSPC ([c648ebf](https://github.com/elct9620/kobako/commit/c648ebf63a871b7d4417110de00decf1738a19d6))
44
+ * **wasmtime:** cap the descriptors one invocation holds open ([03409c1](https://github.com/elct9620/kobako/commit/03409c1437f71312c584a92e22054b90241535a3))
45
+ * **wasmtime:** let Config gain a cap without breaking a frontend ([55d8093](https://github.com/elct9620/kobako/commit/55d80933b958bab67f1b94deb7633272dc56f972))
46
+ * **wasmtime:** present each filesystem Grant to the guest as a preopen ([68149a7](https://github.com/elct9620/kobako/commit/68149a7adc912172b72e7a34bd39082a3b2a9e95)), closes [#78](https://github.com/elct9620/kobako/issues/78)
47
+
48
+
49
+ ### Bug Fixes
50
+
51
+ * append through a Filesystem's file only in one step ([0509ca7](https://github.com/elct9620/kobako/commit/0509ca70d2d5a832303973ba0f7280be0731fd3d))
52
+ * ask a mount's block once for a read ([f89bd16](https://github.com/elct9620/kobako/commit/f89bd16c1a71ed1d385ab9d3ac5974ac3f0a9103))
53
+ * follow no link swapped in after a Policy judges a path ([ed93213](https://github.com/elct9620/kobako/commit/ed9321303dd45e113fc413e99e1240118cc4bbe4))
54
+ * hold an Overlay's lock across each call, waiting without the GVL ([b8e7342](https://github.com/elct9620/kobako/commit/b8e734273fdc577a40be97c43c46d9548d66c625))
55
+ * **io:** build Errno and IOError as CRuby does ([da77c47](https://github.com/elct9620/kobako/commit/da77c4725d3701ba982f5425b1fcf2fb0038ac89))
56
+ * **io:** give File::Constants CRuby's Linux values ([14cadd8](https://github.com/elct9620/kobako/commit/14cadd88ac5a5dcb8f73b252b68c493488b3e78a))
57
+ * **io:** keep the number a SystemCallError is built with ([5fd327a](https://github.com/elct9620/kobako/commit/5fd327add59173cd5756fecb41d97aebcba7b881))
58
+ * **io:** raise each code the engine answers as its own Errno ([eb6382e](https://github.com/elct9620/kobako/commit/eb6382e506a30e82576fa12ab9859e7d35be2b17))
59
+ * **io:** raise Errno::EIO for a file failure no other code names ([8a0447d](https://github.com/elct9620/kobako/commit/8a0447d2d09ea83e6f7771cf0411bfd6deec3d1a)), closes [#78](https://github.com/elct9620/kobako/issues/78)
60
+ * **io:** raise RangeError for a number past what putc, read and errno take ([6f87cc0](https://github.com/elct9620/kobako/commit/6f87cc08dff7146415f80ca25cd75ddbec4391c0))
61
+ * **io:** raise the error a failed file write names ([bcc8e00](https://github.com/elct9620/kobako/commit/bcc8e00662741fcac3b91f58c0b60f4a79d2ab9f))
62
+ * **io:** write a file to the end when its Filesystem takes it in parts ([029b439](https://github.com/elct9620/kobako/commit/029b43939a3a48bc2925057df69bfcb85b1a0548))
63
+ * keep a link within the directory a descriptor opened ([952dd05](https://github.com/elct9620/kobako/commit/952dd0556969683f44798da94f9fc7a17c1f6d55))
64
+ * run a stored block as the block of the Call that carried it ([bf33dc1](https://github.com/elct9620/kobako/commit/bf33dc1fd40c83498c6c12b0be52b3a835a144cf))
65
+ * **runtime:** make every Filesystem answer the methods that keep a guarantee ([00f5af6](https://github.com/elct9620/kobako/commit/00f5af63f34ac7722249746d0b0eb566da618803))
66
+ * **runtime:** report a merged directory's identity alike through an Overlay's lstat ([ded3b4a](https://github.com/elct9620/kobako/commit/ded3b4aba78efa678318c38b139b5c9c76b5d3fd))
67
+ * **wasmtime:** answer a Call the host cannot serve with the reason ([cf60dcc](https://github.com/elct9620/kobako/commit/cf60dccc63a0d0cfc959f701b7212c78beafa528))
68
+ * **wasmtime:** answer a path past Linux's limits as NAMETOOLONG ([af43917](https://github.com/elct9620/kobako/commit/af43917e30a634d6c1bd70813044967bd1057ba3))
69
+ * **wasmtime:** answer a stat that follows no link with the link itself ([ad0072e](https://github.com/elct9620/kobako/commit/ad0072e03ecc363487598a507de20a8f7aec2927))
70
+ * **wasmtime:** answer a wait to write a file by what its Mount permits ([bf863db](https://github.com/elct9620/kobako/commit/bf863db998edeab60f9276fc53e8adcf8cf98364))
71
+ * **wasmtime:** answer an offset past the largest signed offset as EINVAL ([b94788e](https://github.com/elct9620/kobako/commit/b94788e1c1fc9d86f647da4396bcba3eaec16242))
72
+ * **wasmtime:** answer an unlink with a trailing slash by the name itself ([94e7250](https://github.com/elct9620/kobako/commit/94e72505cfc027319c2139e15488eb2682268d49))
73
+ * **wasmtime:** answer descriptor flags, advice, and clock waits as preview1 does ([c1aec63](https://github.com/elct9620/kobako/commit/c1aec632445c3bf216be6375552c799d7877670f))
74
+ * **wasmtime:** answer dot paths, creates, and far seeks as Linux does ([68c234e](https://github.com/elct9620/kobako/commit/68c234e06859b93fb986bdbab92cca944ce39700))
75
+ * **wasmtime:** answer EINVAL for a guest path holding a NUL ([1c681d6](https://github.com/elct9620/kobako/commit/1c681d6e723f259ab2b3acc5e3a33d85499a2ef5))
76
+ * **wasmtime:** answer ENOENT for an open of a missing path that makes nothing ([48e3944](https://github.com/elct9620/kobako/commit/48e3944c64d7ef410fcc4595d80ba0284f257a09))
77
+ * **wasmtime:** answer every preview1 call that reads a descriptor from kobako's own table ([d0e39ae](https://github.com/elct9620/kobako/commit/d0e39aebd6d729d49111340af7f2af4e37aa7909)), closes [#78](https://github.com/elct9620/kobako/issues/78)
78
+ * **wasmtime:** answer fd_allocate beneath a Mount as unsupported ([e3d2071](https://github.com/elct9620/kobako/commit/e3d20713e4474cd637dacfece99e52b80d7ad2f6))
79
+ * **wasmtime:** answer what stands at a path before a Mount refuses an open ([81e02dc](https://github.com/elct9620/kobako/commit/81e02dc5e7d500b2971ab5d4a670d38601f89389))
80
+ * **wasmtime:** ask a Policy once for an open that may create ([a4613cb](https://github.com/elct9620/kobako/commit/a4613cb8cff89af51f55ce090433c61268105789))
81
+ * **wasmtime:** bound a buffer outside memory before a file's access is checked ([8b76f76](https://github.com/elct9620/kobako/commit/8b76f764a6336d2e77baa2ca6fe63dfd7663ce19))
82
+ * **wasmtime:** bound reads, writable waits, and a FIFO's names as preview1 hosts do ([6d89e55](https://github.com/elct9620/kobako/commit/6d89e55541f3366815dd7ed271e813a6ba41bcb3))
83
+ * **wasmtime:** bound what one preview1 call copies to wasmtime's hostcall fuel ([097c554](https://github.com/elct9620/kobako/commit/097c55426c1e71467bb1e372abc190331dd3e601))
84
+ * **wasmtime:** check path_open's flags as wasmtime-wasi does ([22eb494](https://github.com/elct9620/kobako/commit/22eb4944117260831e92fe616b02888078c02b0c))
85
+ * **wasmtime:** close the file fd_renumber moves a descriptor onto ([0f6148d](https://github.com/elct9620/kobako/commit/0f6148d536ed3e9e96749c2e4a60bf6275332655))
86
+ * **wasmtime:** give each writer of a cached artifact its own temp file ([995a46e](https://github.com/elct9620/kobako/commit/995a46e99dc1c485a303bb7f023b4e668a2801a3))
87
+ * **wasmtime:** grant the compile instance no ambient authority ([c3edc71](https://github.com/elct9620/kobako/commit/c3edc71ab99dac57cbabfc685a7cc60a5a5c06ac))
88
+ * **wasmtime:** hold the whole invocation to its deadline ([231e325](https://github.com/elct9620/kobako/commit/231e32592699008adf3105050bee8b5528ea27a8))
89
+ * **wasmtime:** judge the cache directory itself, not where a link leads ([6baf6fd](https://github.com/elct9620/kobako/commit/6baf6fd2ad845cea83049c4b2bb51174aa205cd0))
90
+ * **wasmtime:** keep a write and its file position within the largest signed offset ([29d4c34](https://github.com/elct9620/kobako/commit/29d4c341fc5a47ee43fdd249918e1f3e68120f86))
91
+ * **wasmtime:** key the compiled-artifact cache by the engine that compiles it ([b43bad2](https://github.com/elct9620/kobako/commit/b43bad2fe176c153ed82a3a8825698414df78dfa))
92
+ * **wasmtime:** leave a link named with a trailing slash in place ([9b3cdea](https://github.com/elct9620/kobako/commit/9b3cdea6dc00353c5c4896ec29b88eebdaddc8ab))
93
+ * **wasmtime:** list a directory once for each listing a guest reads ([c333001](https://github.com/elct9620/kobako/commit/c3330011725c3dba01ea248ed7d1dfea31085af0))
94
+ * **wasmtime:** look up what stands before a dot path as Linux does ([0898eaf](https://github.com/elct9620/kobako/commit/0898eafb55397c84ca9007561ddb35dd007ed2b8))
95
+ * **wasmtime:** place an append at the end as the file stands when it lands ([d7291c4](https://github.com/elct9620/kobako/commit/d7291c4f32fb1f5f2494c69c76796476bbcf4d43))
96
+ * **wasmtime:** reach the artifact cache through the directory it checked ([462fe91](https://github.com/elct9620/kobako/commit/462fe918d516cd639e405b06a5e280a9e58624df))
97
+ * **wasmtime:** refuse a `..` that steps out of a host link ([4599386](https://github.com/elct9620/kobako/commit/45993868c7334376f5d1a455afbd15fe4a2146bc))
98
+ * **wasmtime:** refuse a directory made in an opened directory's place ([5e67d4c](https://github.com/elct9620/kobako/commit/5e67d4cd2a52e3aa37bdd615fe1ae101a618db88))
99
+ * **wasmtime:** refuse a link an open asks not to follow ([123a01b](https://github.com/elct9620/kobako/commit/123a01b01f59cc69c0e3a23f9aeb01aa89132c07))
100
+ * **wasmtime:** refuse a link beneath a Policy before the Policy judges the path ([0e08e7b](https://github.com/elct9620/kobako/commit/0e08e7b463344ae34b5feb1787f8af8a6c719063))
101
+ * **wasmtime:** refuse a link to a directory an open asks not to follow ([eec218f](https://github.com/elct9620/kobako/commit/eec218fdd5584f641070032cf1110ef1683eaae5))
102
+ * **wasmtime:** refuse a path climbing above the directory it is opened through ([ae52746](https://github.com/elct9620/kobako/commit/ae52746761624249b7ff1e1fa09ece4ea8130ced))
103
+ * **wasmtime:** refuse a path through a link beneath a Mount with a Policy ([3da1641](https://github.com/elct9620/kobako/commit/3da16416692ade01db2d9cf366d54d3ec5f50605))
104
+ * **wasmtime:** refuse a rename of a file onto a path ending in a slash ([486a0ab](https://github.com/elct9620/kobako/commit/486a0ab3584772b58e181d5de57ef505e610eb78))
105
+ * **wasmtime:** refuse an argument preview1 cannot hold in wasmtime-wasi's order ([9c76e21](https://github.com/elct9620/kobako/commit/9c76e2181a0dabd81f02723154cc4290215fcf70))
106
+ * **wasmtime:** refuse to remove or move a Mount's root ([9f2e000](https://github.com/elct9620/kobako/commit/9f2e000115a4dd4aecfcc4b1cd39b23f6f20fe05))
107
+ * **wasmtime:** report a host FIFO or device as of an unknown filetype ([5a212e7](https://github.com/elct9620/kobako/commit/5a212e7a7c0f069ffdcc56b850fab3778863d9ee))
108
+ * **wasmtime:** require wasmtime 49.0.4 for the aarch64 br_table fix ([390e30b](https://github.com/elct9620/kobako/commit/390e30ba51ed4175820f2bb230e3ad5b0ad1e9a5))
109
+ * **wasmtime:** resolve a `..` and a trailing slash as a host does ([d2d04c1](https://github.com/elct9620/kobako/commit/d2d04c1fff24d8829b2cf4fcbf628565f35eeadc))
110
+ * **wasmtime:** resolve a final dot through the name before it ([7a0d3d8](https://github.com/elct9620/kobako/commit/7a0d3d8b23d47d4ba5c942682841434e74d6bf6a))
111
+ * **wasmtime:** resolve a link a stat names with a trailing slash ([6da98fa](https://github.com/elct9620/kobako/commit/6da98facbccaa9bf6d8f8280a56841e19a7c879b))
112
+ * **wasmtime:** size a file opened only to read as wasmtime-wasi and Linux answer ([810f5c8](https://github.com/elct9620/kobako/commit/810f5c8e863dc5bdbe82f8a19c7559fd7eee03f9))
113
+ * **wasmtime:** sync a cached artifact before renaming it into place ([097efc7](https://github.com/elct9620/kobako/commit/097efc77599545bb2a5e729c75d23082470ed8f4))
114
+ * **wasmtime:** take wasmtime 49.0.3 for its sandbox advisories ([7672592](https://github.com/elct9620/kobako/commit/76725923cac50473c7e3a21cc5121e3cbba0cba5))
115
+ * **wasmtime:** trap a guest field address past the address space ([de5d47e](https://github.com/elct9620/kobako/commit/de5d47e10aa5d978573e46a7cb3453ff248d006e))
116
+
117
+
118
+ ### Performance Improvements
119
+
120
+ * **io:** answer IO#read with a length in one read the file holds ([e9161a2](https://github.com/elct9620/kobako/commit/e9161a2018c1617157025de275f77890e865b7d1)), closes [#78](https://github.com/elct9620/kobako/issues/78)
121
+
3
122
  ## [0.18.0](https://github.com/elct9620/kobako/compare/kobako-wasmtime-v0.17.0...kobako-wasmtime-v0.18.0) (2026-10-13)
4
123
 
5
124
 
@@ -10,10 +10,12 @@ contract surface.
10
10
 
11
11
  | Mechanic | What the driver holds |
12
12
  |---|---|
13
- | Compilation | process-wide Engine and compiled-Module caches, with an on-disk AOT (`.cwasm`) artifact cache keyed by Guest Binary content |
13
+ | Compilation | process-wide Engine and compiled-Module caches |
14
+ | Disk cache | AOT `.cwasm` artifacts on Unix, keyed by Guest Binary content and engine |
14
15
  | Instantiation | a pre-linked `InstancePre` per guest path; every invocation runs on a fresh instance and discards its Store afterwards |
15
- | Bounds | the epoch-based wall-clock timeout and the per-invocation linear-memory cap |
16
+ | Bounds | epoch-based wall-clock deadlines on setup and on each invocation, and the per-invocation linear-memory cap |
16
17
  | Ambient denial | under the default hermetic profile, frozen clocks and a constant RNG |
18
+ | Filesystems | a preopen per Mount, and its own capped descriptor table |
17
19
 
18
20
  The kobako Ruby gem's native ext is the first frontend; a Rust host
19
21
  SDK consumes the same surface.
@@ -22,7 +24,7 @@ SDK consumes the same surface.
22
24
 
23
25
  ```toml
24
26
  [dependencies]
25
- kobako-wasmtime = "0.18.0" # x-release-please-version
27
+ kobako-wasmtime = "0.19.0" # x-release-please-version
26
28
  ```
27
29
 
28
30
  ## License
data/data/kobako.wasm CHANGED
Binary file
Binary file
Binary file
Binary file
@@ -18,24 +18,12 @@ module Kobako
18
18
  end
19
19
  raise ArgumentError, "flag value must be a String, got #{value.class}" unless value.is_a?(String)
20
20
 
21
- key = utf8!(name.to_s, "flag name")
21
+ key = Catalog.to_utf8!(name.to_s, "flag name")
22
22
  raise ArgumentError, "flag #{key.inspect} already set" if @entries.key?(key)
23
23
 
24
- @entries[key] = [utf8!(value, "flag value"), !advisory]
24
+ @entries[key] = [Catalog.to_utf8!(value, "flag value"), !advisory]
25
25
  nil
26
26
  end
27
-
28
- private
29
-
30
- # The native side carries a flag only as UTF-8 text, so text read as
31
- # bytes is re-tagged, and bytes that are not UTF-8 are refused here
32
- # rather than failing every invocation.
33
- def utf8!(text, what)
34
- utf8 = text.dup.force_encoding(Encoding::UTF_8)
35
- raise ArgumentError, "#{what} must be UTF-8 text" unless utf8.valid_encoding?
36
-
37
- utf8
38
- end
39
27
  end
40
28
  end
41
29
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kobako
4
+ module Catalog
5
+ class Grants # :nodoc:
6
+ def initialize
7
+ @entries = {} # : Hash[String, Mount]
8
+ end
9
+
10
+ # Each Grant decides what it cannot stand beside.
11
+ def register(grant)
12
+ reason = @entries.each_value.lazy.filter_map { |other| grant.conflict(other) }.first
13
+ raise ArgumentError, reason if reason
14
+
15
+ @entries[grant.key] = grant
16
+ nil
17
+ end
18
+
19
+ def include?(grant)
20
+ @entries.key?(grant.key)
21
+ end
22
+
23
+ # Each Grant as the native side reads it, an override standing in for
24
+ # the Grant it shares a key with.
25
+ def entries(overrides = {})
26
+ @entries.merge(overrides).values.map(&:to_native)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kobako
4
+ module Catalog
5
+ class Mount < Data.define(:at, :access, :filesystem, :policy) # :nodoc:
6
+ # The path a Context replaces this Mount at.
7
+ def key = at
8
+
9
+ # Why +other+ cannot be mounted beside this Mount, or +nil+: a path
10
+ # means one Mount, and never sits inside another.
11
+ def conflict(other)
12
+ return "path #{at.inspect} is already mounted" if other.at == at
13
+
14
+ "path #{at.inspect} nests with the mounted path #{other.at.inspect}" if nested?(other.at)
15
+ end
16
+
17
+ # The Mount as the native side reads it.
18
+ def to_native = [at, access, filesystem, policy]
19
+
20
+ private
21
+
22
+ def nested?(other)
23
+ [at, other].include?("/") || at.start_with?("#{other}/") || other.start_with?("#{at}/")
24
+ end
25
+ end
26
+ end
27
+ end
@@ -7,6 +7,9 @@ require_relative "../transport/exposure"
7
7
  module Kobako
8
8
  module Catalog
9
9
  class Services # :nodoc:
10
+ # The Guest Binary keeps this namespace for constants it may add later.
11
+ RESERVED_NAMESPACE = "Kobako"
12
+
10
13
  def initialize
11
14
  @bindings = {} # : Hash[String, Kobako::Transport::Exposure]
12
15
  end
@@ -14,6 +17,10 @@ module Kobako
14
17
  # The binding records +object+'s Exposure as it stands now.
15
18
  def bind(path, object)
16
19
  path_str = validate_path!(path)
20
+ if reserved?(path_str)
21
+ raise ArgumentError,
22
+ "Service path #{path_str} is in the reserved #{RESERVED_NAMESPACE} namespace"
23
+ end
17
24
  raise ArgumentError, "Service path #{path_str} conflicts with an existing binding" if collision?(path_str)
18
25
 
19
26
  @bindings[path_str] = Kobako::Transport::Exposure.of(object)
@@ -48,6 +55,10 @@ module Kobako
48
55
  "bind path must be constant-form segments joined by '::' (got #{path.inspect})"
49
56
  end
50
57
 
58
+ def reserved?(path)
59
+ path.split("::").first == RESERVED_NAMESPACE
60
+ end
61
+
51
62
  # Keeps a name from being both a bound Service and a grouping prefix.
52
63
  def collision?(path)
53
64
  @bindings.each_key.any? do |existing|
@@ -7,7 +7,7 @@ module Kobako
7
7
  module Catalog
8
8
  class Snippets # :nodoc:
9
9
  def initialize
10
- @entries = [] # : Array[Kobako::Snippet::Source | Kobako::Snippet::Binary]
10
+ @entries = [] # : Array[Kobako::Snippet::Source | Kobako::Snippet::Bytecode]
11
11
  @compiled = {} # : Hash[Kobako::Snippet::Source, String]
12
12
  @compile_tried = false
13
13
  end
@@ -48,13 +48,9 @@ module Kobako
48
48
 
49
49
  private
50
50
 
51
- # The native side frames a source body only as UTF-8 text, so source
52
- # read as bytes is re-tagged, and bytes that are not UTF-8 are refused
53
- # here rather than failing every invocation.
54
51
  def register_source!(code, name)
55
52
  code, name = ensure_source_args!(code, name)
56
- body = code.dup.force_encoding(Encoding::UTF_8)
57
- raise ArgumentError, "code must be UTF-8 text" unless body.valid_encoding?
53
+ body = Catalog.to_utf8!(code, "code")
58
54
 
59
55
  name_sym = normalize_name(name)
60
56
  if @entries.any? { |e| e.is_a?(Snippet::Source) && e.name == name_sym }
@@ -80,7 +76,7 @@ module Kobako
80
76
  def register_binary!(bytes)
81
77
  raise ArgumentError, "binary must be a String, got #{bytes.class}" unless bytes.is_a?(String)
82
78
 
83
- @entries << Snippet::Binary.new(body: bytes.dup.force_encoding(Encoding::ASCII_8BIT))
79
+ @entries << Snippet::Bytecode.new(body: bytes.dup.force_encoding(Encoding::ASCII_8BIT))
84
80
  nil
85
81
  end
86
82
 
@@ -90,9 +86,9 @@ module Kobako
90
86
  case entry
91
87
  when Snippet::Source
92
88
  compiled = @compiled[entry]
93
- compiled ? [Snippet::Binary::KIND, nil, compiled] : [Snippet::Source::KIND, entry.name.to_s, entry.body]
89
+ compiled ? [Snippet::Bytecode::KIND, nil, compiled] : [Snippet::Source::KIND, entry.name.to_s, entry.body]
94
90
  else
95
- [Snippet::Binary::KIND, nil, entry.body]
91
+ [Snippet::Bytecode::KIND, nil, entry.body]
96
92
  end
97
93
  end
98
94
 
@@ -5,8 +5,19 @@ require_relative "catalog/services"
5
5
  require_relative "catalog/snippets"
6
6
  require_relative "catalog/flags"
7
7
  require_relative "catalog/extensions"
8
+ require_relative "catalog/mount"
9
+ require_relative "catalog/grants"
8
10
 
9
11
  module Kobako
10
12
  module Catalog # :nodoc:
13
+ # The native side carries a registered text only as UTF-8, so text read
14
+ # as bytes is re-tagged, and bytes that are not UTF-8 are refused at
15
+ # registration rather than failing every invocation.
16
+ def self.to_utf8!(text, what)
17
+ utf8 = text.dup.force_encoding(Encoding::UTF_8)
18
+ raise ArgumentError, "#{what} must be UTF-8 text" unless utf8.valid_encoding?
19
+
20
+ utf8
21
+ end
11
22
  end
12
23
  end
@@ -13,6 +13,7 @@ module Kobako
13
13
  # from the decoded payload reports a broken invariant as
14
14
  # InvalidTypeError without its own Utils.with_boundary.
15
15
  def self.decode(bytes)
16
+ ValueBudget.assert_within!(bytes, State.current.value_budget)
16
17
  value = FACTORY.load(bytes.b)
17
18
  validate_utf8!(value)
18
19
  block_given? ? yield(value) : value
@@ -63,7 +63,7 @@ module Kobako
63
63
  # shape. The sighting is recorded so a Handle-free decode can skip the
64
64
  # downstream resolution walk.
65
65
  def unpack_handle(payload, state)
66
- state.record_handle!
66
+ state.record_handle
67
67
  bytes = payload.b
68
68
  raise InvalidTypeError, "Handle payload must be 4 bytes, got #{bytes.bytesize}" unless bytes.bytesize == 4
69
69
 
@@ -2,8 +2,9 @@
2
2
 
3
3
  module Kobako
4
4
  module Codec
5
- # Whether a Capability Handle crossed the decode in flight, kept per
6
- # thread so plain instance variables stay sound.
5
+ # Whether a Capability Handle crossed the decode in flight, and the
6
+ # value budget a decode is held to, kept per thread so plain instance
7
+ # variables stay sound.
7
8
  class State # :nodoc:
8
9
  # Thread-local slot holding the calling thread's State.
9
10
  STATE_KEY = :__kobako_codec_state__
@@ -18,6 +19,21 @@ module Kobako
18
19
 
19
20
  def initialize
20
21
  @carried_handle = false
22
+ @value_budget = nil
23
+ end
24
+
25
+ # The most values a decode on this thread may build, or nil for no
26
+ # budget.
27
+ attr_reader :value_budget
28
+
29
+ # A nested invocation on the same thread restores the outer one's
30
+ # budget when it returns.
31
+ def within_value_budget(budget)
32
+ outer = @value_budget
33
+ @value_budget = budget
34
+ yield
35
+ ensure
36
+ @value_budget = outer
21
37
  end
22
38
 
23
39
  # ExtTypes#unpack_handle is the sole chokepoint every Handle passes
@@ -30,7 +46,7 @@ module Kobako
30
46
 
31
47
  # Record that an ext 0x01 Capability Handle crossed the current
32
48
  # decode; #track_handles reports it to the bracketing caller.
33
- def record_handle!
49
+ def record_handle
34
50
  @carried_handle = true
35
51
  end
36
52
  end