1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! Permission enforcement shared by the path-touching hostlib builtins.
//!
//! Two complementary layers live here:
//!
//! * The per-thread "enabled features" registry plus [`gated_handler`] —
//! the coarse "is this session allowed to touch the filesystem at all?"
//! gate (see the module body below).
//! * [`enforce_path_scope`] — the granular "is this *specific path* inside
//! the session's workspace roots?" check, delegating to the VM-native
//! sandbox so the hostlib surface and `harness.fs.*` agree.
//!
//! `harn-hostlib` exposes the deterministic tool builtins on every VM that
//! `install_default` runs against, but pipelines must explicitly opt in to
//! their use by calling the `hostlib_enable("tools:deterministic")` builtin
//! before any of the tool methods will execute. This keeps the surface
//! sandbox-friendly: a script that doesn't ask for the tools cannot poke
//! the host filesystem or shell out to `git` even though the contract is
//! registered.
//!
//! State is held in a thread-local so that:
//!
//! * Independent VM runs stay isolated when the embedder executes them on
//! separate threads.
//! * Cargo test isolation works without extra ceremony.
//!
//! Embedders can also call [`enable_for_test`] / [`reset`] from Rust if
//! they need to bypass the builtin (for example, tests that don't drive
//! a live VM).
use RefCell;
use BTreeSet;
use Path;
use Arc;
use ;
use VmValue;
use crateHostlibError;
use crateSyncHandler;
/// Feature key for the deterministic-tools surface.
///
/// Kept here as a constant so [`tools::register_builtins`](super::register_builtins)
/// and the integration tests share the exact same string.
pub const FEATURE_TOOLS_DETERMINISTIC: &str = "tools:deterministic";
thread_local!
/// Mark `feature` as enabled on the current thread. Returns `true` if the
/// feature was newly enabled, `false` if it was already on.
/// Mark `feature` as disabled on the current thread. Returns `true` if the
/// feature was previously enabled. Mostly useful in tests that want to
/// assert the gate works.
/// Bulk-clear every enabled feature on the current thread. Tests use this
/// to start from a known state.
/// Report whether `feature` is enabled on the current thread.
/// Convenience wrapper for tests: enable the deterministic tools in the
/// current thread without needing to reach for the builtin.
/// Wrap a builtin runner so it executes only when the deterministic-tools
/// feature has been enabled on the current thread, returning a descriptive
/// error otherwise.
///
/// This is the single gating policy shared by every hostlib builtin that
/// reads or writes arbitrary host filesystem paths — the `tools::*` file
/// I/O surface plus the `fs::*` and `ast::*` edit helpers — so a script
/// denied `tools:deterministic` cannot mutate the working tree through any
/// of them.
/// Reject `path` when it resolves outside the active execution policy's
/// workspace roots, under a restricted sandbox profile.
///
/// This is the single path-scope policy shared by every hostlib builtin
/// that resolves a host filesystem path — the `tools::*`, `fs::*`, and
/// `ast::*` surfaces — so the granular workspace-root check stays
/// consistent across all of them (the path-level complement to the coarse
/// [`gated_handler`] feature gate). It delegates to
/// [`harn_vm::process_sandbox::check_fs_path_scope`] so a path the
/// `harness.fs.*` VM-native builtins would refuse is refused here too, with
/// the same message. A no-op when no policy is active or the profile is
/// unrestricted.