diaspore 0.2.0__tar.gz

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 (47) hide show
  1. diaspore-0.2.0/.gitignore +29 -0
  2. diaspore-0.2.0/LICENSE +21 -0
  3. diaspore-0.2.0/PKG-INFO +150 -0
  4. diaspore-0.2.0/README.md +130 -0
  5. diaspore-0.2.0/docs/dspb.md +97 -0
  6. diaspore-0.2.0/docs/security.md +94 -0
  7. diaspore-0.2.0/docs/spec.md +714 -0
  8. diaspore-0.2.0/pyproject.toml +68 -0
  9. diaspore-0.2.0/src/diaspore/__init__.py +69 -0
  10. diaspore-0.2.0/src/diaspore/cli.py +326 -0
  11. diaspore-0.2.0/src/diaspore/compiler.py +1289 -0
  12. diaspore-0.2.0/src/diaspore/dspb.py +704 -0
  13. diaspore-0.2.0/src/diaspore/encoding.py +143 -0
  14. diaspore-0.2.0/src/diaspore/ir.py +464 -0
  15. diaspore-0.2.0/src/diaspore/py.typed +0 -0
  16. diaspore-0.2.0/src/diaspore/stdlib/_pyparse.py +1749 -0
  17. diaspore-0.2.0/src/diaspore/stdlib/_pyunparse.py +253 -0
  18. diaspore-0.2.0/src/diaspore/stdlib/ast.py +1338 -0
  19. diaspore-0.2.0/src/diaspore/stdlib/asyncio.py +127 -0
  20. diaspore-0.2.0/src/diaspore/stdlib/base64.py +128 -0
  21. diaspore-0.2.0/src/diaspore/stdlib/binascii.py +44 -0
  22. diaspore-0.2.0/src/diaspore/stdlib/collections/__init__.py +182 -0
  23. diaspore-0.2.0/src/diaspore/stdlib/collections/abc.py +110 -0
  24. diaspore-0.2.0/src/diaspore/stdlib/contextlib.py +116 -0
  25. diaspore-0.2.0/src/diaspore/stdlib/copy.py +72 -0
  26. diaspore-0.2.0/src/diaspore/stdlib/dataclasses.py +312 -0
  27. diaspore-0.2.0/src/diaspore/stdlib/fractions.py +101 -0
  28. diaspore-0.2.0/src/diaspore/stdlib/functools.py +78 -0
  29. diaspore-0.2.0/src/diaspore/stdlib/gc.py +11 -0
  30. diaspore-0.2.0/src/diaspore/stdlib/gzip.py +105 -0
  31. diaspore-0.2.0/src/diaspore/stdlib/hashlib.py +187 -0
  32. diaspore-0.2.0/src/diaspore/stdlib/io.py +55 -0
  33. diaspore-0.2.0/src/diaspore/stdlib/itertools.py +174 -0
  34. diaspore-0.2.0/src/diaspore/stdlib/operator.py +188 -0
  35. diaspore-0.2.0/src/diaspore/stdlib/os/__init__.py +82 -0
  36. diaspore-0.2.0/src/diaspore/stdlib/os/path.py +122 -0
  37. diaspore-0.2.0/src/diaspore/stdlib/pathlib.py +361 -0
  38. diaspore-0.2.0/src/diaspore/stdlib/queue.py +107 -0
  39. diaspore-0.2.0/src/diaspore/stdlib/socket.py +241 -0
  40. diaspore-0.2.0/src/diaspore/stdlib/string.py +54 -0
  41. diaspore-0.2.0/src/diaspore/stdlib/threading.py +268 -0
  42. diaspore-0.2.0/src/diaspore/stdlib/types.py +86 -0
  43. diaspore-0.2.0/src/diaspore/stdlib/unittest.py +295 -0
  44. diaspore-0.2.0/src/diaspore/stdlib/weakref.py +76 -0
  45. diaspore-0.2.0/src/diaspore/stdlib/zlib.py +380 -0
  46. diaspore-0.2.0/src/diaspore/validator.py +315 -0
  47. diaspore-0.2.0/src/diaspore/vm.py +3905 -0
@@ -0,0 +1,29 @@
1
+ # Python
2
+ .venv/
3
+ __pycache__/
4
+ *.pyc
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+
8
+ # Node
9
+ node_modules/
10
+ runtimes/ts/dist/
11
+ runtimes/ts/LICENSE
12
+ runtimes/ts/*.tgz
13
+
14
+ # Build output (see `make generate`, `make build` and `make site`)
15
+ build/
16
+ *.dsp.json
17
+ *.dsp.json.gz
18
+ *.dspb
19
+ *.dspb.gz
20
+ *.flow.json
21
+ site/diaspore.wasm
22
+ site/wasm_exec.js
23
+ site/stdlib.json
24
+ site/build.json
25
+ site/ir.schema.json
26
+ tests/fuzz_failures/
27
+ runtimes/go/dspc/stdlib.json.gz
28
+ runtimes/ts/stdlib/
29
+ runtimes/ts/.stdlib-stamp
diaspore-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 diaspore contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,150 @@
1
+ Metadata-Version: 2.5
2
+ Name: diaspore
3
+ Version: 0.2.0
4
+ Summary: Compile a Python subset to portable JSON for Python, Go, TypeScript, and Lua runtimes
5
+ Project-URL: Homepage, https://radkawar.github.io/diaspore
6
+ Project-URL: Repository, https://github.com/radkawar/diaspore
7
+ License: MIT
8
+ License-File: LICENSE
9
+ Keywords: compiler,interpreter,portable,python,sandbox
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Software Development :: Compilers
17
+ Classifier: Topic :: Software Development :: Interpreters
18
+ Requires-Python: >=3.12
19
+ Description-Content-Type: text/markdown
20
+
21
+ # Diaspore
22
+
23
+ Write Python. Ship JSON. Run it anywhere, sandboxed.
24
+
25
+ Diaspore compiles a large subset of Python into a portable JSON bundle and runs
26
+ it with identical output on four runtimes: Python, Go, TypeScript and Lua. A
27
+ bundle has no ambient authority, runs on a fuel budget, and can pause itself
28
+ into a JSON snapshot that any other runtime can resume.
29
+
30
+ [Playground](https://radkawar.github.io/diaspore) |
31
+ [Specification](https://github.com/radkawar/diaspore/blob/main/docs/spec.md) | [Security model](https://github.com/radkawar/diaspore/blob/main/docs/security.md) |
32
+ [Examples](https://github.com/radkawar/diaspore/blob/main/examples) | [Releases](https://github.com/radkawar/diaspore/releases)
33
+
34
+ ```sh
35
+ diaspore build app.py -o app.dsp.json # compile once
36
+ diaspore run app.dsp.json # Python
37
+ diaspore-go run app.dsp.json # Go
38
+ npx diaspore-ts run app.dsp.json # TypeScript
39
+ lua5.4 runtimes/lua/cli.lua run app.dsp.json # Lua
40
+ ```
41
+
42
+ ## Features
43
+
44
+ - **Portable.** One JSON artifact: diffable, signable, storable in a database
45
+ column, validated before it runs.
46
+ - **Sandboxed.** Network, file system and task spawning are denied unless
47
+ granted. `--max-steps` caps CPU; exhausting it is an uncatchable trap.
48
+ - **Embeddable.** Hosts expose functions as an importable module and call into
49
+ the sandbox. Python, Go, TypeScript and Lua hosts share one model.
50
+ - **Durable.** `flow.suspend()` pauses a program into a snapshot. Resume it
51
+ later, in another process, on another runtime.
52
+ - **Self-hosted.** The compiler is written in the subset it compiles. The Go and
53
+ TypeScript runtimes embed it, so they build Python without Python, and so does
54
+ the [browser playground](https://radkawar.github.io/diaspore).
55
+ - **Conformant.** Every corpus program must match CPython byte for byte on every
56
+ runtime, backed by differential fuzzing.
57
+
58
+ ## Runtimes
59
+
60
+ | Runtime | Install | Notes |
61
+ | --- | --- | --- |
62
+ | diaspore-py | `uv tool install diaspore` | Reference VM, compiler and CLI |
63
+ | diaspore-go | [Release binaries](https://github.com/radkawar/diaspore/releases); library: `go get github.com/radkawar/diaspore/runtimes/go` | Near CPython speed; also compiles to WebAssembly |
64
+ | diaspore-ts | [`npm install diaspore`](https://www.npmjs.com/package/diaspore) | Node 22+, no runtime dependencies |
65
+ | diaspore-lua | [Release tarball](https://github.com/radkawar/diaspore/releases) | Pure Lua 5.4; no tasks, regex or big integers |
66
+
67
+ Sources: [src/diaspore](https://github.com/radkawar/diaspore/blob/main/src/diaspore), [runtimes/go](https://github.com/radkawar/diaspore/blob/main/runtimes/go),
68
+ [runtimes/ts](https://github.com/radkawar/diaspore/blob/main/runtimes/ts), [runtimes/lua](https://github.com/radkawar/diaspore/blob/main/runtimes/lua).
69
+
70
+ ## Getting started
71
+
72
+ Install the compiler and reference runtime with
73
+ [uv](https://docs.astral.sh/uv/):
74
+
75
+ ```sh
76
+ uv tool install diaspore
77
+ diaspore build main.py -o main.dsp.json
78
+ diaspore run main.dsp.json
79
+ ```
80
+
81
+ Run the same bundle from Node, or embed it:
82
+
83
+ ```sh
84
+ npm install diaspore
85
+ npx diaspore-ts run main.dsp.json
86
+ ```
87
+
88
+ To build everything from source you need Go 1.26+; Node 23.6+ and Lua 5.4 are
89
+ needed only for their runtimes.
90
+
91
+ ```sh
92
+ git clone https://github.com/radkawar/diaspore && cd diaspore
93
+ uv sync
94
+ make build # embedded compiler + build/diaspore-go
95
+ ```
96
+
97
+ Then try the [examples](https://github.com/radkawar/diaspore/blob/main/examples), starting with
98
+ [embedding](https://github.com/radkawar/diaspore/blob/main/examples/embedding): one sandboxed plugin hosted from all four
99
+ languages.
100
+
101
+ ## Embedding
102
+
103
+ ```python
104
+ from diaspore import Machine, compile_bundle
105
+
106
+ bundle = compile_bundle("plugin.py", extra_modules={"host"})
107
+ vm = Machine(bundle, bindings={"host": {"lookup": lookup}}, max_steps=1_000_000)
108
+ vm.run()
109
+ price = vm.call("plugin", "price", order)
110
+ ```
111
+
112
+ The same pattern in [Go](https://github.com/radkawar/diaspore/blob/main/runtimes/go#embedding),
113
+ [TypeScript](https://github.com/radkawar/diaspore/blob/main/runtimes/ts#embedding) and [Lua](https://github.com/radkawar/diaspore/blob/main/runtimes/lua#embedding).
114
+
115
+ ## Language
116
+
117
+ Functions, closures, classes with multiple inheritance, generators,
118
+ `async`/`await`, exceptions including `except*`, `match`, comprehensions,
119
+ f-strings, arbitrary-precision integers, multi-module packages, and a portable
120
+ standard library (`json`, `math`, `re`, `time`, `random`, `collections`,
121
+ `itertools`, `functools` and more). Unsupported syntax is a compile error with a
122
+ `file:line`, never a silent runtime failure. The exact surface is in
123
+ [docs/spec.md](https://github.com/radkawar/diaspore/blob/main/docs/spec.md).
124
+
125
+ ## Repository
126
+
127
+ ```
128
+ src/diaspore/ compiler, reference VM, CLI, standard library
129
+ selfhost/ dspc, the self-hosted compiler
130
+ runtimes/ go, ts and lua runtimes
131
+ examples/ runnable examples for every runtime
132
+ site/ playground and project site
133
+ docs/ specification, security model, binary format
134
+ tests/ conformance corpus and test suites
135
+ ```
136
+
137
+ ## Development
138
+
139
+ ```sh
140
+ make test # every suite on every runtime
141
+ make lint # ruff, go vet, staticcheck, gofmt, tsc
142
+ make fuzz # differential fuzzing against CPython
143
+ make serve # build and serve the site on localhost:8000
144
+ ```
145
+
146
+ Run `make help` for the full list.
147
+
148
+ ## License
149
+
150
+ [MIT](https://github.com/radkawar/diaspore/blob/main/LICENSE)
@@ -0,0 +1,130 @@
1
+ # Diaspore
2
+
3
+ Write Python. Ship JSON. Run it anywhere, sandboxed.
4
+
5
+ Diaspore compiles a large subset of Python into a portable JSON bundle and runs
6
+ it with identical output on four runtimes: Python, Go, TypeScript and Lua. A
7
+ bundle has no ambient authority, runs on a fuel budget, and can pause itself
8
+ into a JSON snapshot that any other runtime can resume.
9
+
10
+ [Playground](https://radkawar.github.io/diaspore) |
11
+ [Specification](https://github.com/radkawar/diaspore/blob/main/docs/spec.md) | [Security model](https://github.com/radkawar/diaspore/blob/main/docs/security.md) |
12
+ [Examples](https://github.com/radkawar/diaspore/blob/main/examples) | [Releases](https://github.com/radkawar/diaspore/releases)
13
+
14
+ ```sh
15
+ diaspore build app.py -o app.dsp.json # compile once
16
+ diaspore run app.dsp.json # Python
17
+ diaspore-go run app.dsp.json # Go
18
+ npx diaspore-ts run app.dsp.json # TypeScript
19
+ lua5.4 runtimes/lua/cli.lua run app.dsp.json # Lua
20
+ ```
21
+
22
+ ## Features
23
+
24
+ - **Portable.** One JSON artifact: diffable, signable, storable in a database
25
+ column, validated before it runs.
26
+ - **Sandboxed.** Network, file system and task spawning are denied unless
27
+ granted. `--max-steps` caps CPU; exhausting it is an uncatchable trap.
28
+ - **Embeddable.** Hosts expose functions as an importable module and call into
29
+ the sandbox. Python, Go, TypeScript and Lua hosts share one model.
30
+ - **Durable.** `flow.suspend()` pauses a program into a snapshot. Resume it
31
+ later, in another process, on another runtime.
32
+ - **Self-hosted.** The compiler is written in the subset it compiles. The Go and
33
+ TypeScript runtimes embed it, so they build Python without Python, and so does
34
+ the [browser playground](https://radkawar.github.io/diaspore).
35
+ - **Conformant.** Every corpus program must match CPython byte for byte on every
36
+ runtime, backed by differential fuzzing.
37
+
38
+ ## Runtimes
39
+
40
+ | Runtime | Install | Notes |
41
+ | --- | --- | --- |
42
+ | diaspore-py | `uv tool install diaspore` | Reference VM, compiler and CLI |
43
+ | diaspore-go | [Release binaries](https://github.com/radkawar/diaspore/releases); library: `go get github.com/radkawar/diaspore/runtimes/go` | Near CPython speed; also compiles to WebAssembly |
44
+ | diaspore-ts | [`npm install diaspore`](https://www.npmjs.com/package/diaspore) | Node 22+, no runtime dependencies |
45
+ | diaspore-lua | [Release tarball](https://github.com/radkawar/diaspore/releases) | Pure Lua 5.4; no tasks, regex or big integers |
46
+
47
+ Sources: [src/diaspore](https://github.com/radkawar/diaspore/blob/main/src/diaspore), [runtimes/go](https://github.com/radkawar/diaspore/blob/main/runtimes/go),
48
+ [runtimes/ts](https://github.com/radkawar/diaspore/blob/main/runtimes/ts), [runtimes/lua](https://github.com/radkawar/diaspore/blob/main/runtimes/lua).
49
+
50
+ ## Getting started
51
+
52
+ Install the compiler and reference runtime with
53
+ [uv](https://docs.astral.sh/uv/):
54
+
55
+ ```sh
56
+ uv tool install diaspore
57
+ diaspore build main.py -o main.dsp.json
58
+ diaspore run main.dsp.json
59
+ ```
60
+
61
+ Run the same bundle from Node, or embed it:
62
+
63
+ ```sh
64
+ npm install diaspore
65
+ npx diaspore-ts run main.dsp.json
66
+ ```
67
+
68
+ To build everything from source you need Go 1.26+; Node 23.6+ and Lua 5.4 are
69
+ needed only for their runtimes.
70
+
71
+ ```sh
72
+ git clone https://github.com/radkawar/diaspore && cd diaspore
73
+ uv sync
74
+ make build # embedded compiler + build/diaspore-go
75
+ ```
76
+
77
+ Then try the [examples](https://github.com/radkawar/diaspore/blob/main/examples), starting with
78
+ [embedding](https://github.com/radkawar/diaspore/blob/main/examples/embedding): one sandboxed plugin hosted from all four
79
+ languages.
80
+
81
+ ## Embedding
82
+
83
+ ```python
84
+ from diaspore import Machine, compile_bundle
85
+
86
+ bundle = compile_bundle("plugin.py", extra_modules={"host"})
87
+ vm = Machine(bundle, bindings={"host": {"lookup": lookup}}, max_steps=1_000_000)
88
+ vm.run()
89
+ price = vm.call("plugin", "price", order)
90
+ ```
91
+
92
+ The same pattern in [Go](https://github.com/radkawar/diaspore/blob/main/runtimes/go#embedding),
93
+ [TypeScript](https://github.com/radkawar/diaspore/blob/main/runtimes/ts#embedding) and [Lua](https://github.com/radkawar/diaspore/blob/main/runtimes/lua#embedding).
94
+
95
+ ## Language
96
+
97
+ Functions, closures, classes with multiple inheritance, generators,
98
+ `async`/`await`, exceptions including `except*`, `match`, comprehensions,
99
+ f-strings, arbitrary-precision integers, multi-module packages, and a portable
100
+ standard library (`json`, `math`, `re`, `time`, `random`, `collections`,
101
+ `itertools`, `functools` and more). Unsupported syntax is a compile error with a
102
+ `file:line`, never a silent runtime failure. The exact surface is in
103
+ [docs/spec.md](https://github.com/radkawar/diaspore/blob/main/docs/spec.md).
104
+
105
+ ## Repository
106
+
107
+ ```
108
+ src/diaspore/ compiler, reference VM, CLI, standard library
109
+ selfhost/ dspc, the self-hosted compiler
110
+ runtimes/ go, ts and lua runtimes
111
+ examples/ runnable examples for every runtime
112
+ site/ playground and project site
113
+ docs/ specification, security model, binary format
114
+ tests/ conformance corpus and test suites
115
+ ```
116
+
117
+ ## Development
118
+
119
+ ```sh
120
+ make test # every suite on every runtime
121
+ make lint # ruff, go vet, staticcheck, gofmt, tsc
122
+ make fuzz # differential fuzzing against CPython
123
+ make serve # build and serve the site on localhost:8000
124
+ ```
125
+
126
+ Run `make help` for the full list.
127
+
128
+ ## License
129
+
130
+ [MIT](https://github.com/radkawar/diaspore/blob/main/LICENSE)
@@ -0,0 +1,97 @@
1
+ # DSPB: the optional binary bundle container
2
+
3
+ DSPB encodes the same semantic model as a JSON bundle in a compact binary
4
+ container. JSON remains the canonical form and default output. Every DSPB
5
+ implementation MUST preserve this invariant:
6
+
7
+ decode(encode(bundle)) == compact(bundle) (exact structural equality)
8
+
9
+ Digests (`bundle_digest`), validation, and all semantics operate on the
10
+ decoded model, so containers never affect meaning. Loaders sniff by magic
11
+ bytes; `.dspb.gz` (gzip over DSPB) is valid - gzip decoding re-sniffs its
12
+ payload. Reference implementation: `src/diaspore/dspb.py` (normative where this
13
+ document is ambiguous). Round-trip conformance: `tests/test_dspb.py`.
14
+
15
+ ## Primitives
16
+
17
+ - varint - unsigned LEB128 (7 bits per byte, high bit = continuation).
18
+ - str-ref - varint index into the string table.
19
+ - byte - one raw byte.
20
+
21
+ ## Layout
22
+
23
+ ```
24
+ magic 6 bytes "DSPB01"
25
+ strtab varint count, then per string: varint byte-length + UTF-8 bytes
26
+ semver varint (1 - same value as JSON's "diaspore" field)
27
+ main str-ref
28
+ modules varint count, then per module:
29
+ name str-ref, file str-ref,
30
+ src-flag byte (0|1), if 1: str-list (varint count + str-refs)
31
+ body node-list
32
+ node-list varint count + that many nodes
33
+ ```
34
+
35
+ ## Nodes
36
+
37
+ Every node: opcode byte (index into the OPS table below), flags byte
38
+ (bit 0 = `ln` present -> varint follows; higher bits are the op's optional
39
+ fields in the listed order), then fields in fixed order.
40
+
41
+ Enum tables (indices are normative):
42
+
43
+ ```
44
+ OPS = const name attr index slicelit starred call binop unary boolop
45
+ compare cond list tuple set dict fstring func funcexpr yield
46
+ yieldfrom namedexpr expr assign augassign if while for break
47
+ continue pass return class raise try with import importfrom del
48
+ BIN_KINDS = add sub mul div floordiv mod pow lshift rshift bitand bitor
49
+ bitxor matmul
50
+ CMP_KINDS = eq ne lt le gt ge in notin is isnot
51
+ UNARY = neg pos not invert
52
+ CONST = int float str bytes bool none ellipsis complex
53
+ CONV = (none) r s a
54
+ ```
55
+
56
+ Flag-bit optionals per op (bit 1 upward): `slicelit`: lower, upper, step;
57
+ `yield`/`return`: v; `raise`: exc, cause; `import`: alias.
58
+
59
+ Per-op payloads (after flags/ln). `N` = node, `L` = node-list,
60
+ `S` = str-ref, `SL` = varint count + str-refs:
61
+
62
+ | op | payload |
63
+ |---|---|
64
+ | const | kind byte; int/float/str/bytes -> S; complex -> S re, S im (float-strings); bool -> byte 0/1; none/ellipsis -> nothing |
65
+ | name | S id |
66
+ | attr | N o, S n |
67
+ | index | N o, N k |
68
+ | slicelit | optional N lower/upper/step per flags |
69
+ | starred / yieldfrom / expr | N v |
70
+ | call | N f, L args, varint kw-count x (byte named? [1 -> S name], N v) |
71
+ | binop | kind byte, N l, N r |
72
+ | augassign | kind byte, N target, N v |
73
+ | unary | kind byte, N v |
74
+ | boolop | byte (0=and, 1=or), L values |
75
+ | compare | N left, varint count x kind byte, L comps |
76
+ | cond | N test, N then, N else |
77
+ | list / tuple / set | L elts |
78
+ | dict | varint count x (byte has-key? [1 -> N k], N v) |
79
+ | fstring | varint count x part: byte flag (0 = text -> S; else bit0=value: N v, conv byte, bit1 -> N spec) |
80
+ | func / funcexpr | S name, byte flags (bit0 gen, bit1 coro), byte pflags (bit0 vararg, bit1 kwarg), SL args, L defaults, [S vararg], SL kwonly, varint kwdefault-count x (byte present? [1 -> N]), [S kwarg], SL locals, SL gdecl, SL ndecl, L body |
81
+ | yield / return | [N v] per flags |
82
+ | namedexpr | N target, N v |
83
+ | assign | L targets, N v |
84
+ | if / while | N test, L then/body, L orelse |
85
+ | for | N target, N iter, L body, L orelse |
86
+ | break / continue / pass | nothing |
87
+ | class | S name, byte kwflag, [kwargs: varint count x (byte named? [1->S n], N v)], L bases, L body |
88
+ | raise | [N exc], [N cause] per flags |
89
+ | try | byte star, L body, varint handler-count x (byte hflags: bit0 t, bit1 name; [N t], [S name], L body), L orelse, L finalbody |
90
+ | with | varint item-count x (byte has-name, N ctx, [N name]), L body |
91
+ | import | S module, byte bind (0 absent, 1 root, 2 none), [S alias] per flags |
92
+ | importfrom | S module, varint count x (S n, S alias) |
93
+ | del | L targets |
94
+
95
+ Decoding materializes the compact JSON form (spec section 2.2): empty lists,
96
+ false `gen`/`coro`/`star`, and absent optionals are omitted from the produced
97
+ dicts. Key order does not affect structural equality.
@@ -0,0 +1,94 @@
1
+ # Diaspore security model
2
+
3
+ Diaspore runs Python-subset programs with explicit capabilities and resource
4
+ limits. The threat model assumes an adversary controls source code or a bundle,
5
+ but not the runtime, host process, embedding code, or deployment configuration.
6
+ The runtime must prevent access to host objects and authority not granted by the
7
+ host. Resource isolation also requires operating-system controls.
8
+
9
+ ## Untrusted inputs
10
+
11
+ The compiler is not a security boundary. Treat bundles as untrusted data even
12
+ when they were produced by `dspc` (`selfhost/dspc.py`). The typed IR is defined in
13
+ `src/diaspore/ir.py`; generate its JSON Schema with `diaspore schema` or
14
+ `make schema`, or use the [published schema](https://radkawar.github.io/diaspore/ir.schema.json).
15
+ Schema validation does not establish that a program is safe or will terminate.
16
+ Apply input-size limits to source, bundles, compressed containers, and snapshots
17
+ before loading them.
18
+
19
+ ## Capabilities and bindings
20
+
21
+ Without grants, programs can compute, allocate, use the configured standard
22
+ streams, inspect supplied arguments, and call available native modules such as
23
+ `math`, `json`, `random`, `time`, and `re`. Clock access and randomness do not
24
+ require capabilities. Standard input is also available through `input()`.
25
+
26
+ | Capability | Authority | Scoped grants |
27
+ |---|---|---|
28
+ | `net` | TCP listeners and outbound connections | `--allow-net listen:HOST:PORT` or `connect:HOST:PORT`; `*` matches any host or port |
29
+ | `fs` | File access through `open` | `--allow-fs read:PATH` or `write:PATH`; resolved-path prefix matching |
30
+ | `spawn` | Tasks, channels, and locks | `--allow-spawn`; concurrency model in [spec section 11.9](spec.md#11-native-modules) |
31
+
32
+ A bare grant permits all operations covered by that capability. Scoped grants
33
+ deny operations not listed. Denied operations raise `PermissionError`.
34
+ Availability of native modules and capabilities differs by runtime; consult the
35
+ runtime README before deploying a policy.
36
+
37
+ Filesystem checks resolve symlinks before matching paths. They are not a
38
+ replacement for isolated mounts, especially where another process can modify
39
+ the filesystem between checking and opening a path. Network policy matches the
40
+ requested address, not a pinned DNS result. Use IP-based policies or a binding
41
+ that enforces destination policy when DNS changes are a concern.
42
+
43
+ Environment access, subprocesses, and FFI are not exposed as native sandbox APIs.
44
+ Where supported, `exec`, `eval`, and `compile` compile Diaspore-subset code and
45
+ execute it inside the VM; they do not execute arbitrary host Python.
46
+
47
+ Host bindings run with host privileges. Validate their inputs, keep their
48
+ interfaces narrow, and expose only the authority the program needs. A binding
49
+ can invalidate the sandbox's isolation if it evaluates input as host code or
50
+ performs unrestricted file or network operations.
51
+
52
+ ## Resource limits
53
+
54
+ - Fuel (`--max-steps`) meters statements, calls, and selected bulk operations.
55
+ Exhaustion is an uncatchable trap with exit code 3.
56
+ - Recursion depth (`--max-depth`, default 1000) raises a catchable
57
+ `RecursionError` when exceeded.
58
+ - Fuel does not bound peak memory, time blocked in I/O or host bindings, or open
59
+ descriptors. Set process memory and CPU limits, descriptor limits, and an
60
+ external timeout for hostile workloads. Limit compiler resources as well as
61
+ runtime resources.
62
+
63
+ ## Runtime isolation
64
+
65
+ The four runtimes are diaspore-py, diaspore-go, diaspore-ts, and diaspore-lua.
66
+ Their implementations and trusted dependencies differ. The Python reference VM
67
+ uses allowlisted operations on CPython values; Go, TypeScript, and Lua implement
68
+ sandbox values and operations within their respective host environments.
69
+ Memory safety and allowlists do not prove that an interpreter is escape-free.
70
+
71
+ For untrusted multi-tenant workloads, run each tenant in a separate restricted
72
+ process or container. Grant minimal filesystem and network access to that
73
+ process, regardless of which runtime it uses. Do not rely on an interpreter bug
74
+ being limited to a wrong result or a controlled crash.
75
+
76
+ ## Durable flows and nondeterminism
77
+
78
+ Durable mode forbids `net`, `fs`, and `spawn` capabilities. Supported effects,
79
+ including host-binding results, are journaled for replay; snapshots contain JSON
80
+ data rather than interpreter internals (see [spec section 14](spec.md#14-durable-flows-suspend--resume)).
81
+
82
+ Snapshots contain effect results and can therefore contain secrets. Protect
83
+ their confidentiality and integrity. The bundle digest binds a snapshot to a
84
+ program; it does not authenticate the journal or its author. Accept snapshots
85
+ only from trusted storage or authenticate them at the application boundary.
86
+
87
+ Clock values, randomness, set iteration order, object identities, and allocation
88
+ behavior can be observable. Diaspore does not provide timing-side-channel
89
+ isolation. Durable programs must remain deterministic between journaled effects.
90
+
91
+ ## Reporting
92
+
93
+ Report vulnerabilities by opening a
94
+ [GitHub security advisory](https://github.com/radkawar/diaspore/security/advisories/new).