shellsim 0.1.2__tar.gz → 0.1.4__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.
- {shellsim-0.1.2 → shellsim-0.1.4}/Cargo.lock +1 -1
- {shellsim-0.1.2 → shellsim-0.1.4}/Cargo.toml +5 -4
- shellsim-0.1.4/PKG-INFO +168 -0
- shellsim-0.1.4/README.md +144 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/pyproject.toml +26 -3
- {shellsim-0.1.2 → shellsim-0.1.4}/python/native/Cargo.lock +2 -2
- {shellsim-0.1.2 → shellsim-0.1.4}/python/native/Cargo.toml +4 -3
- {shellsim-0.1.2 → shellsim-0.1.4}/python/native/src/lib.rs +128 -17
- {shellsim-0.1.2 → shellsim-0.1.4}/python/shellsim/__init__.py +6 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/python/shellsim/__main__.py +0 -1
- {shellsim-0.1.2 → shellsim-0.1.4}/python/shellsim/_api.py +127 -19
- {shellsim-0.1.2 → shellsim-0.1.4}/python/shellsim/_cli.py +4 -11
- shellsim-0.1.4/python/shellsim/python.py +32 -0
- shellsim-0.1.4/src/commands/awk/ast.rs +146 -0
- shellsim-0.1.4/src/commands/awk/eval.rs +1180 -0
- shellsim-0.1.4/src/commands/awk/lexer.rs +367 -0
- shellsim-0.1.4/src/commands/awk/parser.rs +522 -0
- shellsim-0.1.4/src/commands/awk.rs +243 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/builtins.rs +453 -112
- shellsim-0.1.4/src/commands/dd.rs +308 -0
- shellsim-0.1.4/src/commands/find.rs +323 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/fs.rs +373 -178
- shellsim-0.1.4/src/commands/git/apply.rs +255 -0
- shellsim-0.1.4/src/commands/git/commit.rs +339 -0
- shellsim-0.1.4/src/commands/git/compare.rs +731 -0
- shellsim-0.1.4/src/commands/git/config.rs +356 -0
- shellsim-0.1.4/src/commands/git/conflict.rs +564 -0
- shellsim-0.1.4/src/commands/git/diff.rs +609 -0
- shellsim-0.1.4/src/commands/git/ignore.rs +381 -0
- shellsim-0.1.4/src/commands/git/log.rs +1055 -0
- shellsim-0.1.4/src/commands/git/merge.rs +722 -0
- shellsim-0.1.4/src/commands/git/mod.rs +794 -0
- shellsim-0.1.4/src/commands/git/plumbing.rs +1215 -0
- shellsim-0.1.4/src/commands/git/rebase.rs +475 -0
- shellsim-0.1.4/src/commands/git/refs.rs +699 -0
- shellsim-0.1.4/src/commands/git/repo.rs +1210 -0
- shellsim-0.1.4/src/commands/git/stash.rs +441 -0
- shellsim-0.1.4/src/commands/git/switch.rs +522 -0
- shellsim-0.1.4/src/commands/git/worktree.rs +1592 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/hashing.rs +76 -9
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/mod.rs +133 -6
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/net.rs +14 -4
- shellsim-0.1.4/src/commands/options.rs +271 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/patch.rs +100 -23
- shellsim-0.1.4/src/commands/pkg.rs +304 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/printf.rs +45 -9
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/proc.rs +220 -92
- shellsim-0.1.4/src/commands/regex_compat.rs +56 -0
- shellsim-0.1.4/src/commands/sed.rs +787 -0
- shellsim-0.1.4/src/commands/sort.rs +255 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/system.rs +120 -26
- shellsim-0.1.4/src/commands/text.rs +1980 -0
- shellsim-0.1.4/src/commands/unavailable.rs +39 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/util.rs +37 -2
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/zipcmd.rs +12 -1
- {shellsim-0.1.2 → shellsim-0.1.4}/src/descriptors.rs +121 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/exec.rs +205 -32
- {shellsim-0.1.2 → shellsim-0.1.4}/src/expand.rs +64 -7
- {shellsim-0.1.2 → shellsim-0.1.4}/src/harness.rs +3 -3
- {shellsim-0.1.2 → shellsim-0.1.4}/src/interp.rs +228 -9
- shellsim-0.1.4/src/jqcmd.rs +1497 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/main.rs +3 -3
- shellsim-0.1.4/src/net.rs +550 -0
- shellsim-0.1.4/src/netcmd.rs +357 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/pseudo_fs.rs +20 -2
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/ast.rs +16 -3
- shellsim-0.1.4/src/python/bytecode.rs +511 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/compiler.rs +284 -75
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/filesystem.rs +81 -32
- shellsim-0.1.4/src/python/heap.rs +1795 -0
- shellsim-0.1.4/src/python/http.rs +135 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/lexer.rs +48 -3
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/mod.rs +302 -46
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/native.rs +260 -39
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/number.rs +224 -80
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/object_model.rs +294 -65
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/parser.rs +324 -69
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/protocol.rs +179 -14
- shellsim-0.1.4/src/python/slice.rs +133 -0
- shellsim-0.1.4/src/python/stdlib/argparse.rs +674 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/core.rs +596 -25
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/frozen.rs +10 -0
- shellsim-0.1.4/src/python/stdlib/http.rs +63 -0
- shellsim-0.1.4/src/python/stdlib/importlib.rs +43 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/json.rs +36 -5
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/math.rs +36 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/mod.rs +12 -1
- shellsim-0.1.4/src/python/stdlib/numpy.rs +4730 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/os.rs +15 -6
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/csv.py +4 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/datetime.py +15 -0
- shellsim-0.1.4/src/python/stdlib/source/http.py +3 -0
- shellsim-0.1.4/src/python/stdlib/source/http_client.py +271 -0
- shellsim-0.1.4/src/python/stdlib/source/importlib.py +47 -0
- shellsim-0.1.4/src/python/stdlib/source/json.py +25 -0
- shellsim-0.1.4/src/python/stdlib/source/numpy_random.py +99 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/os.py +81 -8
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/pathlib.py +36 -0
- shellsim-0.1.4/src/python/stdlib/source/random.py +97 -0
- shellsim-0.1.4/src/python/stdlib/source/statistics.py +127 -0
- shellsim-0.1.4/src/python/stdlib/source/urllib.py +4 -0
- shellsim-0.1.4/src/python/stdlib/source/urllib_error.py +50 -0
- shellsim-0.1.4/src/python/stdlib/source/urllib_request.py +155 -0
- shellsim-0.1.4/src/python/stdlib/source/zipfile.py +234 -0
- shellsim-0.1.4/src/python/stdlib/sys.rs +183 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/vfs.rs +46 -0
- shellsim-0.1.4/src/python/string.rs +170 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/token.rs +5 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/vm.rs +2720 -761
- {shellsim-0.1.2 → shellsim-0.1.4}/src/resources.rs +10 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/scenario.rs +5 -5
- {shellsim-0.1.2 → shellsim-0.1.4}/src/shell.rs +142 -12
- {shellsim-0.1.2 → shellsim-0.1.4}/src/telemetry.rs +2 -2
- shellsim-0.1.2/PKG-INFO +0 -331
- shellsim-0.1.2/README.md +0 -307
- shellsim-0.1.2/src/commands/awk.rs +0 -674
- shellsim-0.1.2/src/commands/git.rs +0 -1858
- shellsim-0.1.2/src/commands/pkg.rs +0 -223
- shellsim-0.1.2/src/commands/sort.rs +0 -55
- shellsim-0.1.2/src/commands/text.rs +0 -1148
- shellsim-0.1.2/src/jqcmd.rs +0 -352
- shellsim-0.1.2/src/net.rs +0 -218
- shellsim-0.1.2/src/netcmd.rs +0 -135
- shellsim-0.1.2/src/python/bytecode.rs +0 -107
- shellsim-0.1.2/src/python/heap.rs +0 -569
- shellsim-0.1.2/src/python/stdlib/argparse.rs +0 -265
- shellsim-0.1.2/src/python/stdlib/source/json.py +0 -15
- shellsim-0.1.2/src/python/stdlib/sys.rs +0 -89
- {shellsim-0.1.2 → shellsim-0.1.4}/LICENSE +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/python/shellsim/py.typed +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/rust-toolchain.toml +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/bin/shellsim-python.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/clock.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/archives.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/echo.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/makecmd.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/rgcmd.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/commands/tarcmd.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/harness_manager.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/hashes.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/host_ingest.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/lib.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/mcp.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/process.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/process.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/source.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/base64.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/bisect.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/collections.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/dataclasses.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/enum.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/functools.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/hashlib.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/heapq.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/itertools.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/pytest.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/re.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/abc.py +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/base64.py +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/codecs.py +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/collections.py +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/glob.py +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/hashlib.py +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/io.py +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/logging.py +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/struct.py +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/subprocess.py +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/tempfile.py +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/uuid.py +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/source/zlib.py +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/string.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/struct.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/subprocess.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/time.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/typing.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/unittest.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/python/stdlib/zlib.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/sandbox.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/scheduler.rs +0 -0
- {shellsim-0.1.2 → shellsim-0.1.4}/src/vfs.rs +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "shellsim"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.4"
|
|
4
4
|
edition = "2021"
|
|
5
|
-
description = "
|
|
5
|
+
description = "In-process BusyBox-like environment for RL rollouts and agent tests"
|
|
6
6
|
license = "Apache-2.0"
|
|
7
7
|
readme = "README.md"
|
|
8
8
|
repository = "https://github.com/rjpower/shellsim"
|
|
@@ -58,5 +58,6 @@ python = []
|
|
|
58
58
|
opt-level = 1
|
|
59
59
|
|
|
60
60
|
[profile.release]
|
|
61
|
-
opt-level = "
|
|
62
|
-
lto =
|
|
61
|
+
opt-level = "z"
|
|
62
|
+
lto = "fat"
|
|
63
|
+
codegen-units = 1
|
shellsim-0.1.4/PKG-INFO
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: shellsim
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
6
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
7
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
8
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
11
|
+
Classifier: Programming Language :: Rust
|
|
12
|
+
Classifier: Topic :: Software Development :: Testing
|
|
13
|
+
Classifier: Typing :: Typed
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Summary: In-process BusyBox-like environment for RL rollouts and agent tests
|
|
16
|
+
Keywords: agents,containers,reinforcement-learning,sandbox,simulation,testing
|
|
17
|
+
Author: The shellsim authors
|
|
18
|
+
Requires-Python: >=3.9
|
|
19
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
20
|
+
Project-URL: Homepage, https://github.com/rjpower/shellsim
|
|
21
|
+
Project-URL: Issues, https://github.com/rjpower/shellsim/issues
|
|
22
|
+
Project-URL: Repository, https://github.com/rjpower/shellsim
|
|
23
|
+
|
|
24
|
+
# shellsim
|
|
25
|
+
|
|
26
|
+
Shellsim is a BusyBox for containers: one small, deterministic process that provides a useful
|
|
27
|
+
Unix-shaped environment without starting a VM, container runtime, or host subprocess. It is built
|
|
28
|
+
for experimentation and testing with reinforcement-learning rollouts and agentic environments,
|
|
29
|
+
where fast startup, reproducibility, isolation, and explicit resource limits matter more than
|
|
30
|
+
cycle-accurate emulation.
|
|
31
|
+
|
|
32
|
+
Shell programs, common command-line tools, logical processes, and Python run in-process against an
|
|
33
|
+
in-memory filesystem. Simulated code cannot access the host filesystem, processes, network,
|
|
34
|
+
environment, or clock. A trusted harness may copy a selected project into the virtual filesystem
|
|
35
|
+
before execution; changes never write back to the host.
|
|
36
|
+
|
|
37
|
+
## Compatibility
|
|
38
|
+
|
|
39
|
+
Shellsim aims for broad compatibility inside clear boundaries. A supported facility should handle
|
|
40
|
+
almost all ordinary uses, even when obscure flags or legacy behavior remain out of scope. A module
|
|
41
|
+
or command with no coherent useful subset is omitted instead of being exposed as a misleading
|
|
42
|
+
stub. Unsupported syntax, options, executable formats, and capabilities fail visibly and are
|
|
43
|
+
included in structured results.
|
|
44
|
+
|
|
45
|
+
The current environment includes:
|
|
46
|
+
|
|
47
|
+
- a Bash-like shell with pipelines, redirections, functions, common expansions, control flow,
|
|
48
|
+
background jobs, signals, and job control;
|
|
49
|
+
- common filesystem, text, archive, Git, Make, process, and system commands;
|
|
50
|
+
- deterministic virtual time, network fixtures, `/proc`, `/dev`, processes, descriptors, and
|
|
51
|
+
bounded pipes;
|
|
52
|
+
- a mostly complete Python language runtime with a deliberately selected standard-library and
|
|
53
|
+
third-party module surface.
|
|
54
|
+
|
|
55
|
+
Python is source-compatible where supported, not ABI-compatible with CPython. Native extensions,
|
|
56
|
+
network package installation, compilers, and arbitrary machine code are outside the simulation
|
|
57
|
+
boundary. The simulated `pip` and `uv` paths can activate packages already bundled with
|
|
58
|
+
shellsim; they reject other packages instead of fetching them. See
|
|
59
|
+
[Python in shellsim](docs/python.md) for the current contract.
|
|
60
|
+
|
|
61
|
+
`git` provides a porcelain subset backed by the virtual filesystem: staging, commits, history,
|
|
62
|
+
diffs, branches, tags, merges, stashes, and search, with output that matches real Git where an
|
|
63
|
+
agent is likely to parse it. Networked subcommands and content conflicts are refused rather than
|
|
64
|
+
approximated. See [Git in shellsim](docs/git.md) for the supported surface and its boundaries.
|
|
65
|
+
|
|
66
|
+
Common utilities accept clustered short options, long options, option values, and `--` through a
|
|
67
|
+
shared parser. Each utility declares its supported options. For example, `grep` supports ordinary
|
|
68
|
+
basic and extended regular expressions, recursive search, fixed strings, word and whole-line
|
|
69
|
+
matching, pattern files, include and exclude filters, context, counts, line numbers, match limits,
|
|
70
|
+
and common output controls. `sed` covers addresses and ranges plus the common substitution,
|
|
71
|
+
selection, text, transliteration, and early-exit commands. `awk` parses a typed language subset
|
|
72
|
+
with record rules, control flow, fields, associative arrays, arithmetic, regular expressions, and
|
|
73
|
+
the usual scalar functions. Unsupported syntax and options exit nonzero with a direct diagnostic;
|
|
74
|
+
text processing is UTF-8-only unless a command documents a byte-oriented mode.
|
|
75
|
+
|
|
76
|
+
## Install and run
|
|
77
|
+
|
|
78
|
+
Install the Python package and console command:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
python -m pip install shellsim
|
|
82
|
+
shellsim -c 'printf "b\na\n" | sort'
|
|
83
|
+
shellsim --root ./project -c 'python3.14 test.py'
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`--root` copies the selected host tree into a disposable `/work` snapshot. With no `-c` and a
|
|
87
|
+
terminal attached, `shellsim` starts a persistent interactive session.
|
|
88
|
+
|
|
89
|
+
To build the Rust binaries from source:
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
cargo build --release
|
|
93
|
+
./target/release/shellsim -c 'echo hello'
|
|
94
|
+
./target/release/shellsim eval --cpu 100k --memory 8m -c 'make test'
|
|
95
|
+
./target/release/shellsim-python ./project/main.py -- arg1
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Limits accept `k`, `m`, and `g` binary suffixes. `eval` emits a structured result containing the
|
|
99
|
+
exit status, stdout and stderr, resource use, command trace, and unsupported behavior.
|
|
100
|
+
`unsupported_commands` lists recognized or attempted commands that crossed the capability
|
|
101
|
+
boundary; invocation records include trust, status, and the unsupported reason.
|
|
102
|
+
|
|
103
|
+
The Python API exposes fresh and persistent environments:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
import shellsim
|
|
107
|
+
|
|
108
|
+
environment = shellsim.Environment(cpu=100_000)
|
|
109
|
+
environment.write_file("/work/main.py", "print(6 * 7)\n")
|
|
110
|
+
result = environment.run("python3.14 /work/main.py")
|
|
111
|
+
assert result.returncode == 0
|
|
112
|
+
assert result.stdout == b"42\n"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Static HTTP fixtures use the same isolated environment. They do not enable sockets, DNS, TLS, or
|
|
116
|
+
host-network access:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
environment = shellsim.Environment(http={
|
|
120
|
+
"https://api.test/items/*": shellsim.HttpResponse(
|
|
121
|
+
status=200,
|
|
122
|
+
headers={"Content-Type": "application/json"},
|
|
123
|
+
body='{"items": []}',
|
|
124
|
+
),
|
|
125
|
+
})
|
|
126
|
+
result = environment.run("curl -s https://api.test/items/1")
|
|
127
|
+
|
|
128
|
+
result = environment.run_python("""
|
|
129
|
+
from urllib.request import urlopen
|
|
130
|
+
print(urlopen('https://api.test/items/1').read())
|
|
131
|
+
""")
|
|
132
|
+
assert result.network_requests[0].matched
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Python source can bypass shell parsing and quoting while using the same isolated runtime:
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
result = shellsim.python.run("print(sum(range(10)))", argv=["example"])
|
|
139
|
+
result.check_returncode()
|
|
140
|
+
|
|
141
|
+
environment = shellsim.Environment()
|
|
142
|
+
result = environment.run_python("print('persistent VFS, fresh Python interpreter')")
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Agent harness
|
|
146
|
+
|
|
147
|
+
`shellsim serve --root ./project` runs a persistent newline-delimited JSON session. It supports
|
|
148
|
+
bounded execution, streaming actions, VFS operations, checkpoints, workspace diffs, process and
|
|
149
|
+
resource inspection, and deterministic session forks. `shellsim mcp` exposes the same environment
|
|
150
|
+
as a stdio MCP server. `shellsim replay scenario.ndjson` reruns checked action transcripts.
|
|
151
|
+
|
|
152
|
+
```sh
|
|
153
|
+
printf '%s\n' \
|
|
154
|
+
'{"id":1,"op":"execute","source":"printf hello > result"}' \
|
|
155
|
+
'{"id":2,"op":"workspace_diff"}' \
|
|
156
|
+
| shellsim serve --root ./project
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Resource model
|
|
160
|
+
|
|
161
|
+
CPU is deterministic fuel, memory is modeled working set, disk is current virtual-filesystem
|
|
162
|
+
usage, and output bounds materialized stdout and stderr. The defaults are 10,000,000 CPU units,
|
|
163
|
+
64 MiB memory, 64 MiB disk, and 4 MiB output. Costs are stable and intentionally approximate.
|
|
164
|
+
Exhaustion is observable and never falls back to an ambient host implementation.
|
|
165
|
+
|
|
166
|
+
For internals and contribution workflow, see [implementation](docs/implementation.md),
|
|
167
|
+
[Python](docs/python.md), and [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
168
|
+
|
shellsim-0.1.4/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# shellsim
|
|
2
|
+
|
|
3
|
+
Shellsim is a BusyBox for containers: one small, deterministic process that provides a useful
|
|
4
|
+
Unix-shaped environment without starting a VM, container runtime, or host subprocess. It is built
|
|
5
|
+
for experimentation and testing with reinforcement-learning rollouts and agentic environments,
|
|
6
|
+
where fast startup, reproducibility, isolation, and explicit resource limits matter more than
|
|
7
|
+
cycle-accurate emulation.
|
|
8
|
+
|
|
9
|
+
Shell programs, common command-line tools, logical processes, and Python run in-process against an
|
|
10
|
+
in-memory filesystem. Simulated code cannot access the host filesystem, processes, network,
|
|
11
|
+
environment, or clock. A trusted harness may copy a selected project into the virtual filesystem
|
|
12
|
+
before execution; changes never write back to the host.
|
|
13
|
+
|
|
14
|
+
## Compatibility
|
|
15
|
+
|
|
16
|
+
Shellsim aims for broad compatibility inside clear boundaries. A supported facility should handle
|
|
17
|
+
almost all ordinary uses, even when obscure flags or legacy behavior remain out of scope. A module
|
|
18
|
+
or command with no coherent useful subset is omitted instead of being exposed as a misleading
|
|
19
|
+
stub. Unsupported syntax, options, executable formats, and capabilities fail visibly and are
|
|
20
|
+
included in structured results.
|
|
21
|
+
|
|
22
|
+
The current environment includes:
|
|
23
|
+
|
|
24
|
+
- a Bash-like shell with pipelines, redirections, functions, common expansions, control flow,
|
|
25
|
+
background jobs, signals, and job control;
|
|
26
|
+
- common filesystem, text, archive, Git, Make, process, and system commands;
|
|
27
|
+
- deterministic virtual time, network fixtures, `/proc`, `/dev`, processes, descriptors, and
|
|
28
|
+
bounded pipes;
|
|
29
|
+
- a mostly complete Python language runtime with a deliberately selected standard-library and
|
|
30
|
+
third-party module surface.
|
|
31
|
+
|
|
32
|
+
Python is source-compatible where supported, not ABI-compatible with CPython. Native extensions,
|
|
33
|
+
network package installation, compilers, and arbitrary machine code are outside the simulation
|
|
34
|
+
boundary. The simulated `pip` and `uv` paths can activate packages already bundled with
|
|
35
|
+
shellsim; they reject other packages instead of fetching them. See
|
|
36
|
+
[Python in shellsim](docs/python.md) for the current contract.
|
|
37
|
+
|
|
38
|
+
`git` provides a porcelain subset backed by the virtual filesystem: staging, commits, history,
|
|
39
|
+
diffs, branches, tags, merges, stashes, and search, with output that matches real Git where an
|
|
40
|
+
agent is likely to parse it. Networked subcommands and content conflicts are refused rather than
|
|
41
|
+
approximated. See [Git in shellsim](docs/git.md) for the supported surface and its boundaries.
|
|
42
|
+
|
|
43
|
+
Common utilities accept clustered short options, long options, option values, and `--` through a
|
|
44
|
+
shared parser. Each utility declares its supported options. For example, `grep` supports ordinary
|
|
45
|
+
basic and extended regular expressions, recursive search, fixed strings, word and whole-line
|
|
46
|
+
matching, pattern files, include and exclude filters, context, counts, line numbers, match limits,
|
|
47
|
+
and common output controls. `sed` covers addresses and ranges plus the common substitution,
|
|
48
|
+
selection, text, transliteration, and early-exit commands. `awk` parses a typed language subset
|
|
49
|
+
with record rules, control flow, fields, associative arrays, arithmetic, regular expressions, and
|
|
50
|
+
the usual scalar functions. Unsupported syntax and options exit nonzero with a direct diagnostic;
|
|
51
|
+
text processing is UTF-8-only unless a command documents a byte-oriented mode.
|
|
52
|
+
|
|
53
|
+
## Install and run
|
|
54
|
+
|
|
55
|
+
Install the Python package and console command:
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
python -m pip install shellsim
|
|
59
|
+
shellsim -c 'printf "b\na\n" | sort'
|
|
60
|
+
shellsim --root ./project -c 'python3.14 test.py'
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`--root` copies the selected host tree into a disposable `/work` snapshot. With no `-c` and a
|
|
64
|
+
terminal attached, `shellsim` starts a persistent interactive session.
|
|
65
|
+
|
|
66
|
+
To build the Rust binaries from source:
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
cargo build --release
|
|
70
|
+
./target/release/shellsim -c 'echo hello'
|
|
71
|
+
./target/release/shellsim eval --cpu 100k --memory 8m -c 'make test'
|
|
72
|
+
./target/release/shellsim-python ./project/main.py -- arg1
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Limits accept `k`, `m`, and `g` binary suffixes. `eval` emits a structured result containing the
|
|
76
|
+
exit status, stdout and stderr, resource use, command trace, and unsupported behavior.
|
|
77
|
+
`unsupported_commands` lists recognized or attempted commands that crossed the capability
|
|
78
|
+
boundary; invocation records include trust, status, and the unsupported reason.
|
|
79
|
+
|
|
80
|
+
The Python API exposes fresh and persistent environments:
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
import shellsim
|
|
84
|
+
|
|
85
|
+
environment = shellsim.Environment(cpu=100_000)
|
|
86
|
+
environment.write_file("/work/main.py", "print(6 * 7)\n")
|
|
87
|
+
result = environment.run("python3.14 /work/main.py")
|
|
88
|
+
assert result.returncode == 0
|
|
89
|
+
assert result.stdout == b"42\n"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Static HTTP fixtures use the same isolated environment. They do not enable sockets, DNS, TLS, or
|
|
93
|
+
host-network access:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
environment = shellsim.Environment(http={
|
|
97
|
+
"https://api.test/items/*": shellsim.HttpResponse(
|
|
98
|
+
status=200,
|
|
99
|
+
headers={"Content-Type": "application/json"},
|
|
100
|
+
body='{"items": []}',
|
|
101
|
+
),
|
|
102
|
+
})
|
|
103
|
+
result = environment.run("curl -s https://api.test/items/1")
|
|
104
|
+
|
|
105
|
+
result = environment.run_python("""
|
|
106
|
+
from urllib.request import urlopen
|
|
107
|
+
print(urlopen('https://api.test/items/1').read())
|
|
108
|
+
""")
|
|
109
|
+
assert result.network_requests[0].matched
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Python source can bypass shell parsing and quoting while using the same isolated runtime:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
result = shellsim.python.run("print(sum(range(10)))", argv=["example"])
|
|
116
|
+
result.check_returncode()
|
|
117
|
+
|
|
118
|
+
environment = shellsim.Environment()
|
|
119
|
+
result = environment.run_python("print('persistent VFS, fresh Python interpreter')")
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Agent harness
|
|
123
|
+
|
|
124
|
+
`shellsim serve --root ./project` runs a persistent newline-delimited JSON session. It supports
|
|
125
|
+
bounded execution, streaming actions, VFS operations, checkpoints, workspace diffs, process and
|
|
126
|
+
resource inspection, and deterministic session forks. `shellsim mcp` exposes the same environment
|
|
127
|
+
as a stdio MCP server. `shellsim replay scenario.ndjson` reruns checked action transcripts.
|
|
128
|
+
|
|
129
|
+
```sh
|
|
130
|
+
printf '%s\n' \
|
|
131
|
+
'{"id":1,"op":"execute","source":"printf hello > result"}' \
|
|
132
|
+
'{"id":2,"op":"workspace_diff"}' \
|
|
133
|
+
| shellsim serve --root ./project
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Resource model
|
|
137
|
+
|
|
138
|
+
CPU is deterministic fuel, memory is modeled working set, disk is current virtual-filesystem
|
|
139
|
+
usage, and output bounds materialized stdout and stderr. The defaults are 10,000,000 CPU units,
|
|
140
|
+
64 MiB memory, 64 MiB disk, and 4 MiB output. Costs are stable and intentionally approximate.
|
|
141
|
+
Exhaustion is observable and never falls back to an ambient host implementation.
|
|
142
|
+
|
|
143
|
+
For internals and contribution workflow, see [implementation](docs/implementation.md),
|
|
144
|
+
[Python](docs/python.md), and [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
@@ -5,7 +5,7 @@ build-backend = "maturin"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "shellsim"
|
|
7
7
|
dynamic = ["version"]
|
|
8
|
-
description = "
|
|
8
|
+
description = "In-process BusyBox-like environment for RL rollouts and agent tests"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
11
11
|
license = { file = "LICENSE" }
|
|
@@ -22,7 +22,7 @@ classifiers = [
|
|
|
22
22
|
"Topic :: Software Development :: Testing",
|
|
23
23
|
"Typing :: Typed",
|
|
24
24
|
]
|
|
25
|
-
keywords = ["
|
|
25
|
+
keywords = ["agents", "containers", "reinforcement-learning", "sandbox", "simulation", "testing"]
|
|
26
26
|
|
|
27
27
|
[project.urls]
|
|
28
28
|
Homepage = "https://github.com/rjpower/shellsim"
|
|
@@ -44,4 +44,27 @@ locked = true
|
|
|
44
44
|
strip = true
|
|
45
45
|
|
|
46
46
|
[tool.pytest.ini_options]
|
|
47
|
-
testpaths = ["
|
|
47
|
+
testpaths = ["tests/python_package", "tests/tooling"]
|
|
48
|
+
|
|
49
|
+
[tool.marin-style]
|
|
50
|
+
checks = ["ruff-check", "ruff-format"]
|
|
51
|
+
include = [
|
|
52
|
+
"infra/*.py",
|
|
53
|
+
"infra/**/*.py",
|
|
54
|
+
"python/**/*.py",
|
|
55
|
+
"tests/python/test_*.py",
|
|
56
|
+
"tests/python_package/**/*.py",
|
|
57
|
+
"tests/tooling/**/*.py",
|
|
58
|
+
"tools/*.py",
|
|
59
|
+
"tools/**/*.py",
|
|
60
|
+
]
|
|
61
|
+
main_branch = "main"
|
|
62
|
+
ruff_version = "0.14.3"
|
|
63
|
+
|
|
64
|
+
[tool.ruff]
|
|
65
|
+
line-length = 120
|
|
66
|
+
target-version = "py39"
|
|
67
|
+
|
|
68
|
+
[tool.ruff.lint]
|
|
69
|
+
select = ["E", "F", "I", "B", "C4"]
|
|
70
|
+
ignore = ["E501"]
|
|
@@ -406,7 +406,7 @@ dependencies = [
|
|
|
406
406
|
|
|
407
407
|
[[package]]
|
|
408
408
|
name = "shellsim"
|
|
409
|
-
version = "0.1.
|
|
409
|
+
version = "0.1.4"
|
|
410
410
|
dependencies = [
|
|
411
411
|
"base64",
|
|
412
412
|
"crc32fast",
|
|
@@ -427,7 +427,7 @@ dependencies = [
|
|
|
427
427
|
|
|
428
428
|
[[package]]
|
|
429
429
|
name = "shellsim-python-bindings"
|
|
430
|
-
version = "0.1.
|
|
430
|
+
version = "0.1.4"
|
|
431
431
|
dependencies = [
|
|
432
432
|
"pyo3",
|
|
433
433
|
"serde",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[package]
|
|
4
4
|
name = "shellsim-python-bindings"
|
|
5
|
-
version = "0.1.
|
|
5
|
+
version = "0.1.4"
|
|
6
6
|
edition = "2021"
|
|
7
7
|
description = "Python bindings for shellsim"
|
|
8
8
|
license = "Apache-2.0"
|
|
@@ -20,5 +20,6 @@ serde_json = "1"
|
|
|
20
20
|
shellsim = { path = "../.." }
|
|
21
21
|
|
|
22
22
|
[profile.release]
|
|
23
|
-
opt-level = "
|
|
24
|
-
lto =
|
|
23
|
+
opt-level = "z"
|
|
24
|
+
lto = "fat"
|
|
25
|
+
codegen-units = 1
|
|
@@ -17,6 +17,7 @@ use pyo3::exceptions::PyException;
|
|
|
17
17
|
use pyo3::prelude::*;
|
|
18
18
|
use pyo3::types::PyBytes;
|
|
19
19
|
use serde::Serialize;
|
|
20
|
+
use shellsim::net::NetworkRequest;
|
|
20
21
|
use shellsim::{CommandTrust, InvocationEvent, Limits, RunOutcome};
|
|
21
22
|
|
|
22
23
|
const ACTION_STACK_BYTES: usize = 8 * 1024 * 1024;
|
|
@@ -35,10 +36,12 @@ struct RunMetadata {
|
|
|
35
36
|
dropped_unsupported: u64,
|
|
36
37
|
commands: Vec<String>,
|
|
37
38
|
dropped_commands: u64,
|
|
38
|
-
|
|
39
|
+
unsupported_commands: Vec<String>,
|
|
39
40
|
partial_commands: Vec<String>,
|
|
40
41
|
invocations: Vec<InvocationEvent>,
|
|
41
42
|
dropped_invocations: u64,
|
|
43
|
+
network_requests: Vec<NetworkRequest>,
|
|
44
|
+
dropped_network_requests: u64,
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
#[derive(Serialize)]
|
|
@@ -47,6 +50,17 @@ struct MountMetadata {
|
|
|
47
50
|
skipped_directories: Vec<String>,
|
|
48
51
|
}
|
|
49
52
|
|
|
53
|
+
struct MetadataStart {
|
|
54
|
+
command: usize,
|
|
55
|
+
dropped_commands: u64,
|
|
56
|
+
unsupported: usize,
|
|
57
|
+
dropped_unsupported: u64,
|
|
58
|
+
invocation: u64,
|
|
59
|
+
dropped_invocations: u64,
|
|
60
|
+
network: usize,
|
|
61
|
+
dropped_network: u64,
|
|
62
|
+
}
|
|
63
|
+
|
|
50
64
|
/// One persistent simulated machine owned by Python.
|
|
51
65
|
#[pyclass(module = "shellsim._native")]
|
|
52
66
|
struct NativeEnvironment {
|
|
@@ -91,6 +105,31 @@ impl NativeEnvironment {
|
|
|
91
105
|
))
|
|
92
106
|
}
|
|
93
107
|
|
|
108
|
+
/// Execute Python source directly without passing it through the shell parser.
|
|
109
|
+
fn run_python(
|
|
110
|
+
&self,
|
|
111
|
+
py: Python<'_>,
|
|
112
|
+
source: String,
|
|
113
|
+
argv: Vec<String>,
|
|
114
|
+
stdin: Vec<u8>,
|
|
115
|
+
) -> PyResult<(String, Py<PyBytes>, Py<PyBytes>)> {
|
|
116
|
+
let (metadata, stdout, stderr) = py
|
|
117
|
+
.detach(|| {
|
|
118
|
+
let mut environment = self.lock_environment()?;
|
|
119
|
+
on_worker(&mut environment, move |environment| {
|
|
120
|
+
Ok(run_python_action(environment, source, argv, stdin))
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
.map_err(SimulationError::new_err)?;
|
|
124
|
+
let metadata = serde_json::to_string(&metadata)
|
|
125
|
+
.map_err(|error| SimulationError::new_err(error.to_string()))?;
|
|
126
|
+
Ok((
|
|
127
|
+
metadata,
|
|
128
|
+
PyBytes::new(py, &stdout).unbind(),
|
|
129
|
+
PyBytes::new(py, &stderr).unbind(),
|
|
130
|
+
))
|
|
131
|
+
}
|
|
132
|
+
|
|
94
133
|
/// Write one byte string into the simulated filesystem.
|
|
95
134
|
fn write_file(&self, py: Python<'_>, path: String, data: Vec<u8>, mode: u32) -> PyResult<()> {
|
|
96
135
|
py.detach(|| {
|
|
@@ -139,6 +178,36 @@ impl NativeEnvironment {
|
|
|
139
178
|
.map_err(SimulationError::new_err)
|
|
140
179
|
}
|
|
141
180
|
|
|
181
|
+
/// Register one static response in the simulated HTTP broker.
|
|
182
|
+
fn route_http(
|
|
183
|
+
&self,
|
|
184
|
+
py: Python<'_>,
|
|
185
|
+
pattern: String,
|
|
186
|
+
method: Option<String>,
|
|
187
|
+
status: u16,
|
|
188
|
+
headers: Vec<(String, String)>,
|
|
189
|
+
body: Vec<u8>,
|
|
190
|
+
) -> PyResult<()> {
|
|
191
|
+
py.detach(|| {
|
|
192
|
+
let mut environment = self.lock_environment()?;
|
|
193
|
+
on_worker(&mut environment, move |environment| {
|
|
194
|
+
environment
|
|
195
|
+
.net
|
|
196
|
+
.route(
|
|
197
|
+
&pattern,
|
|
198
|
+
method.as_deref(),
|
|
199
|
+
shellsim::net::HttpResponse {
|
|
200
|
+
status,
|
|
201
|
+
headers,
|
|
202
|
+
body,
|
|
203
|
+
},
|
|
204
|
+
)
|
|
205
|
+
.map_err(|error| error.to_string())
|
|
206
|
+
})
|
|
207
|
+
})
|
|
208
|
+
.map_err(SimulationError::new_err)
|
|
209
|
+
}
|
|
210
|
+
|
|
142
211
|
/// Import one explicitly selected trusted host tree into the simulated filesystem.
|
|
143
212
|
fn mount(
|
|
144
213
|
&self,
|
|
@@ -188,35 +257,77 @@ fn run_action(
|
|
|
188
257
|
source: &str,
|
|
189
258
|
stdin: &[u8],
|
|
190
259
|
) -> (RunMetadata, Vec<u8>, Vec<u8>) {
|
|
191
|
-
let
|
|
192
|
-
let dropped_commands_start = environment.cmd_trace.dropped();
|
|
193
|
-
let unsupported_start = environment.unsupported.len();
|
|
194
|
-
let dropped_unsupported_start = environment.unsupported.dropped();
|
|
195
|
-
let invocation_start = environment.invocations.next_sequence();
|
|
196
|
-
let dropped_invocations_start = environment.invocations.dropped();
|
|
260
|
+
let start = metadata_start(environment);
|
|
197
261
|
let (outcome, stdout, stderr) = environment.run_script_capture_with_stdin(source, stdin);
|
|
198
|
-
|
|
199
|
-
|
|
262
|
+
(metadata_finish(environment, outcome, start), stdout, stderr)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
fn run_python_action(
|
|
266
|
+
environment: &mut shellsim::Environment,
|
|
267
|
+
source: String,
|
|
268
|
+
arguments: Vec<String>,
|
|
269
|
+
stdin: Vec<u8>,
|
|
270
|
+
) -> (RunMetadata, Vec<u8>, Vec<u8>) {
|
|
271
|
+
let start = metadata_start(environment);
|
|
272
|
+
let mut argv = vec!["python3.14".to_string(), "-c".to_string(), source];
|
|
273
|
+
argv.extend(arguments);
|
|
274
|
+
let mut stdout = Vec::new();
|
|
275
|
+
let mut stderr = Vec::new();
|
|
276
|
+
let status = shellsim::exec::exec(
|
|
277
|
+
environment,
|
|
278
|
+
&shellsim::shell::Node::ArgvCommand(argv),
|
|
279
|
+
stdin,
|
|
280
|
+
&mut stdout,
|
|
281
|
+
&mut stderr,
|
|
282
|
+
);
|
|
283
|
+
let outcome = environment.outcome(status);
|
|
284
|
+
(metadata_finish(environment, outcome, start), stdout, stderr)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
fn metadata_start(environment: &shellsim::Environment) -> MetadataStart {
|
|
288
|
+
MetadataStart {
|
|
289
|
+
command: environment.cmd_trace.len(),
|
|
290
|
+
dropped_commands: environment.cmd_trace.dropped(),
|
|
291
|
+
unsupported: environment.unsupported.len(),
|
|
292
|
+
dropped_unsupported: environment.unsupported.dropped(),
|
|
293
|
+
invocation: environment.invocations.next_sequence(),
|
|
294
|
+
dropped_invocations: environment.invocations.dropped(),
|
|
295
|
+
network: environment.net.log.len(),
|
|
296
|
+
dropped_network: environment.net.dropped_requests,
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
fn metadata_finish(
|
|
301
|
+
environment: &shellsim::Environment,
|
|
302
|
+
outcome: RunOutcome,
|
|
303
|
+
start: MetadataStart,
|
|
304
|
+
) -> RunMetadata {
|
|
305
|
+
let invocations = environment.invocations.events_since(start.invocation);
|
|
306
|
+
RunMetadata {
|
|
200
307
|
outcome,
|
|
201
|
-
unsupported: environment.unsupported.values_since(
|
|
308
|
+
unsupported: environment.unsupported.values_since(start.unsupported),
|
|
202
309
|
dropped_unsupported: environment
|
|
203
310
|
.unsupported
|
|
204
311
|
.dropped()
|
|
205
|
-
.saturating_sub(
|
|
206
|
-
commands: environment.cmd_trace.values_since(
|
|
312
|
+
.saturating_sub(start.dropped_unsupported),
|
|
313
|
+
commands: environment.cmd_trace.values_since(start.command),
|
|
207
314
|
dropped_commands: environment
|
|
208
315
|
.cmd_trace
|
|
209
316
|
.dropped()
|
|
210
|
-
.saturating_sub(
|
|
211
|
-
|
|
317
|
+
.saturating_sub(start.dropped_commands),
|
|
318
|
+
unsupported_commands: invocation_names(&invocations, CommandTrust::Unsupported),
|
|
212
319
|
partial_commands: invocation_names(&invocations, CommandTrust::Partial),
|
|
213
320
|
invocations,
|
|
214
321
|
dropped_invocations: environment
|
|
215
322
|
.invocations
|
|
216
323
|
.dropped()
|
|
217
|
-
.saturating_sub(
|
|
218
|
-
|
|
219
|
-
|
|
324
|
+
.saturating_sub(start.dropped_invocations),
|
|
325
|
+
network_requests: environment.net.log[start.network..].to_vec(),
|
|
326
|
+
dropped_network_requests: environment
|
|
327
|
+
.net
|
|
328
|
+
.dropped_requests
|
|
329
|
+
.saturating_sub(start.dropped_network),
|
|
330
|
+
}
|
|
220
331
|
}
|
|
221
332
|
|
|
222
333
|
fn invocation_names(events: &[InvocationEvent], trust: CommandTrust) -> Vec<String> {
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"""Typed Python interface to shellsim's deterministic execution environment."""
|
|
2
2
|
|
|
3
|
+
from . import python as python
|
|
3
4
|
from ._api import (
|
|
4
5
|
CommandUsage,
|
|
5
6
|
Environment,
|
|
7
|
+
HttpRequest,
|
|
8
|
+
HttpResponse,
|
|
6
9
|
Invocation,
|
|
7
10
|
Limits,
|
|
8
11
|
MountResult,
|
|
@@ -15,6 +18,8 @@ from ._api import (
|
|
|
15
18
|
__all__ = [
|
|
16
19
|
"CommandUsage",
|
|
17
20
|
"Environment",
|
|
21
|
+
"HttpRequest",
|
|
22
|
+
"HttpResponse",
|
|
18
23
|
"Invocation",
|
|
19
24
|
"Limits",
|
|
20
25
|
"MountResult",
|
|
@@ -22,4 +27,5 @@ __all__ = [
|
|
|
22
27
|
"SimulationError",
|
|
23
28
|
"Usage",
|
|
24
29
|
"run",
|
|
30
|
+
"python",
|
|
25
31
|
]
|