dsh-plugin-wsl-env 0.7.5 → 0.9.0
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.
- package/CHANGELOG.md +345 -8
- package/CONTRIBUTING.md +221 -68
- package/README.md +50 -35
- package/SECURITY.md +18 -2
- package/SUPPORT.md +23 -7
- package/cordis.patch.yml +9 -0
- package/docs/ARCHITECTURE.md +200 -57
- package/docs/CONFIGURATION.md +180 -16
- package/docs/LIMITATIONS.md +91 -33
- package/docs/PARITY.md +66 -38
- package/docs/PEER-PARITY.md +95 -32
- package/docs/README.zh.md +49 -31
- package/docs/UPSTREAM-FSIO-EXPORT.md +159 -50
- package/docs/UPSTREAM-TERMINAL-TITLE.md +49 -14
- package/lib/agent-confined.d.ts +42 -0
- package/lib/agent-confined.js +25 -41
- package/lib/agent-errors.d.ts +31 -0
- package/lib/agent-errors.js +19 -16
- package/lib/agent-exec.d.ts +159 -0
- package/lib/agent-exec.js +151 -165
- package/lib/agent-protocol.d.ts +192 -0
- package/lib/agent-protocol.js +76 -100
- package/lib/agent-shared.d.ts +27 -0
- package/lib/agent-shared.js +12 -12
- package/lib/agent.d.ts +353 -0
- package/lib/agent.js +536 -552
- package/lib/auto-preset.d.ts +110 -0
- package/lib/auto-preset.js +157 -141
- package/lib/bwrap.d.ts +90 -0
- package/lib/bwrap.js +18 -18
- package/lib/file-reference-wsl.d.ts +160 -0
- package/lib/file-reference-wsl.js +192 -173
- package/lib/fs-decisions.d.ts +107 -0
- package/lib/fs-decisions.js +64 -60
- package/lib/fs-routing.d.ts +182 -0
- package/lib/fs-routing.js +173 -116
- package/lib/fs-substrate.d.ts +258 -0
- package/lib/fs-substrate.js +248 -248
- package/lib/fs.d.ts +10 -0
- package/lib/fs.js +5 -0
- package/lib/fsio-agent.d.ts +307 -0
- package/lib/fsio-agent.js +414 -410
- package/lib/fsio-text.d.ts +115 -0
- package/lib/fsio-text.js +104 -84
- package/lib/git-route.d.ts +100 -0
- package/lib/git-route.js +46 -47
- package/lib/index.d.ts +1003 -0
- package/lib/index.js +1106 -1003
- package/lib/listing.d.ts +114 -0
- package/lib/listing.js +68 -55
- package/lib/paths.d.ts +182 -0
- package/lib/paths.js +134 -109
- package/lib/picker.d.ts +266 -0
- package/lib/picker.js +371 -351
- package/lib/ports.d.ts +44 -0
- package/lib/ports.js +39 -29
- package/lib/preflight.d.ts +91 -0
- package/lib/preflight.js +94 -0
- package/lib/preset-choice.d.ts +33 -0
- package/lib/preset-choice.js +15 -7
- package/lib/probe-cache.d.ts +51 -0
- package/lib/probe-cache.js +43 -29
- package/lib/sandbox-core.d.ts +149 -0
- package/lib/sandbox-core.js +239 -87
- package/lib/sandbox.d.ts +48 -0
- package/lib/sandbox.js +4 -4
- package/lib/search-exec.d.ts +96 -0
- package/lib/search-exec.js +52 -79
- package/lib/search-route.d.ts +75 -0
- package/lib/search-route.js +30 -31
- package/lib/shell-env.d.ts +88 -0
- package/lib/shell-env.js +78 -74
- package/lib/shell.d.ts +10 -0
- package/lib/shell.js +5 -0
- package/lib/subprocess.d.ts +313 -0
- package/lib/subprocess.js +267 -262
- package/lib/terminal-activity.d.ts +98 -0
- package/lib/terminal-activity.js +29 -39
- package/lib/terminal-route.d.ts +27 -0
- package/lib/terminal-route.js +16 -8
- package/lib/watcher.d.ts +77 -0
- package/lib/watcher.js +120 -126
- package/lib/workspace-files-route.d.ts +132 -0
- package/lib/workspace-files-route.js +73 -81
- package/lib/workspace-files-wsl.d.ts +257 -0
- package/lib/workspace-files-wsl.js +311 -251
- package/lib/wsl.d.ts +266 -0
- package/lib/wsl.js +150 -155
- package/locale/preflight/en.json +6 -0
- package/locale/preflight/zh.json +6 -0
- package/package.json +78 -22
- package/scripts/diagnose.sh +92 -0
package/CONTRIBUTING.md
CHANGED
|
@@ -10,35 +10,145 @@ the conventions this repository uses.
|
|
|
10
10
|
| Windows 10 or 11 | the plugin targets Windows only |
|
|
11
11
|
| WSL2 with at least one distro | `wsl.exe -l -v` lists the installed distros |
|
|
12
12
|
| `bubblewrap` in the distro | `sudo apt install bubblewrap`. The sandbox fails closed without it. |
|
|
13
|
-
| Node
|
|
13
|
+
| Node 22.19+, or 24 | the versions CI runs. `engines` requires `^22.19.0 \|\| >=24.0.0`, the harness host's own floor. |
|
|
14
14
|
|
|
15
15
|
## Toolchain
|
|
16
16
|
|
|
17
|
-
The package
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
17
|
+
The runtime package ships no `dependencies` field at all, on purpose: it is
|
|
18
|
+
loaded into the DSH process and everything it needs arrives as a peer package.
|
|
19
|
+
Running the plugin from a checkout has no install step.
|
|
20
|
+
|
|
21
|
+
Developing and running the gates do have dependencies. The tests import pinned
|
|
22
|
+
`@deepseek-ai/*` packages — the composition test runs the loader's real patch
|
|
23
|
+
algorithm, and the boot test starts a row through the real Loader — so a fresh
|
|
24
|
+
checkout needs one `pnpm install` before the gates pass.
|
|
25
|
+
|
|
26
|
+
Those pins are deliberate, and they move with the harness rather than on their
|
|
27
|
+
own: the `@deepseek-ai/dsh-*` peers sit at `0.2.0-rc.2`, `@deepseek-ai/cordis`
|
|
28
|
+
at `~4.0.4` and `@deepseek-ai/schemastery` at `~3.18.4`. The plugin subclasses
|
|
29
|
+
peer classes and mirrors peer protocol, so raising one pin alone is how the
|
|
30
|
+
seams drift: bump them in the commit that matches a harness release, re-run the
|
|
31
|
+
comparison `docs/PEER-PARITY.md` describes, and let the gate chain and the
|
|
32
|
+
probes confirm the result.
|
|
33
|
+
|
|
34
|
+
pnpm runs the scripts in this repository, pinned through the `packageManager`
|
|
35
|
+
field (corepack resolves it). Treat `pnpm run <script>` as the reference
|
|
36
|
+
toolchain.
|
|
37
|
+
|
|
38
|
+
Do not add a runtime dependency — see above. Style tooling is kept out for the
|
|
39
|
+
same reason: there is no ESLint and no Prettier. The checks that would normally
|
|
40
|
+
need them are built from Node builtins instead. `test/style.mjs` verifies the
|
|
41
|
+
rules `.editorconfig` states, and it checks that every `files` entry still
|
|
42
|
+
matches tracked content and every `exports` target still exists. The syntax pass
|
|
43
|
+
inside `pnpm test` uses Node's own parser.
|
|
44
|
+
|
|
45
|
+
Exactly three dependencies run install scripts (`@deepseek-ai/dsh-subprocess-local`,
|
|
46
|
+
`koffi`, `node-pty` — the native pieces); they are allow-listed in
|
|
47
|
+
`pnpm-workspace.yaml` and everything else builds nothing.
|
|
48
|
+
|
|
49
|
+
## The type gate
|
|
50
|
+
|
|
51
|
+
`lint:types` runs `tsc --noEmit` under `strict` with `checkJs` over what is NOT
|
|
52
|
+
generated — `test/**` and the ambient types — and the types come from the peer
|
|
53
|
+
packages' own `.d.ts`: nothing is invented twice. `types/dsh-services.d.ts`
|
|
54
|
+
pulls in the `declare module '@deepseek-ai/cordis'` augmentations the service
|
|
55
|
+
packages ship, so `ctx.fs`, `ctx.shell`, `ctx.sandboxPolicy` and friends are
|
|
56
|
+
typed; it declares nothing itself and ships nowhere.
|
|
57
|
+
|
|
58
|
+
The probe scripts under `test/probe/` are inside the gate as well. The sources
|
|
59
|
+
under `src/` are checked by the build program itself (`strict`,
|
|
60
|
+
`noEmitOnError`), which is strictly stronger than checking their emitted
|
|
61
|
+
JavaScript. The shipped artifact was checked first because it is where protocol
|
|
62
|
+
drift with the pinned peers hurts; the tests and probes came next, and the
|
|
63
|
+
errors they surfaced were real — a test that pinned a raw number into an argv,
|
|
64
|
+
a couple of hand-written JSDoc contracts wider than the code (`wslErrorCode`,
|
|
65
|
+
`gitSpawnRewrite`) and narrower than their seams, and one
|
|
66
|
+
accepted-but-never-enforced byte-window cap in the distro-routed file service,
|
|
67
|
+
found because a fake hands the confinement seam an `"full"` enforcement the core
|
|
68
|
+
itself never reports.
|
|
69
|
+
|
|
70
|
+
Three patterns keep the check honest:
|
|
71
|
+
|
|
72
|
+
- A subclass's own config keys are declared as a type mirroring its
|
|
73
|
+
`static Config` schema and read through one explicit cast — the schema and
|
|
74
|
+
the type can then only drift apart visibly.
|
|
75
|
+
- A test double is typed as the slice of the seam it scripts (a duck
|
|
76
|
+
`@typedef`) and reaches the seam's declared type through one documented cast
|
|
77
|
+
at the injection point — the cast states which contract the double stands in
|
|
78
|
+
for, instead of silencing the mismatch with `any`.
|
|
79
|
+
- `@ts-expect-error` is allowed exactly when the suppressed error names a real
|
|
80
|
+
upstream seam gap, carries the reason inline, and the gap is written up — in a
|
|
81
|
+
`docs/UPSTREAM-*.md` tracking doc when the fix is an upstream ask (the
|
|
82
|
+
`LocalBashExecutor.spawnSpec` seam has one), or in the source comment itself
|
|
83
|
+
when the honest fix needs a protocol decision this package owns (the exit-4
|
|
84
|
+
relay's unknown entry kind is the other site, deliberately left visible). It
|
|
85
|
+
is a published finding, not a silencer.
|
|
86
|
+
|
|
87
|
+
## The build
|
|
88
|
+
|
|
89
|
+
The plugin must be loadable from a bare checkout: the harness has no
|
|
90
|
+
transpilation layer, the Windows runtime mirror is a copy of the tree, and the
|
|
91
|
+
tests exercise `lib/*.js` — the published artifact — rather than the sources.
|
|
92
|
+
Sources live in `src/`, built JavaScript and declarations in `lib/`, and the
|
|
93
|
+
artifacts stay COMMITTED. `pnpm run build` (`scripts/build.mjs`) runs one pass —
|
|
94
|
+
`tsc -p tsconfig.build.json` — emitting every `src/*.ts` as JavaScript plus its
|
|
95
|
+
declaration under the same export paths as the hand-written modules it
|
|
96
|
+
replaced. Imports name the artifact (`./x.js`); `nodenext` resolves that
|
|
97
|
+
through the TypeScript source. The build then prunes declarations no source
|
|
98
|
+
owns (a rename leftover), so `lib/` is exactly the artifacts of `src/`.
|
|
99
|
+
|
|
100
|
+
Rules that keep this honest:
|
|
101
|
+
|
|
102
|
+
- Never edit a generated file under `lib/` — its module doc names the source
|
|
103
|
+
to edit and `lint:build` fails the moment the two drift. Generated artifacts
|
|
104
|
+
keep tsc's canonical formatting (four-space, compacted); review `src/` for
|
|
105
|
+
every module.
|
|
106
|
+
- `lint:build` (`test/build-freshness.mjs`) enforces that the corpus is closed
|
|
107
|
+
— every `lib/*.js` has its `src/<name>.ts`, every source has both artifacts —
|
|
108
|
+
then snapshots every generated file, runs the real build, byte-compares and
|
|
109
|
+
RESTORES the snapshot: a check, not a rebuild; the remedy for drift is
|
|
110
|
+
`pnpm run build` plus a commit. It is part of the gate chain after
|
|
111
|
+
`test:syntax`.
|
|
112
|
+
- Generated files are not in the `checkJs` gate at all (`tsconfig.json` covers
|
|
113
|
+
`test/**` and the ambient types); their sources are type-checked by the build
|
|
114
|
+
program with `noEmitOnError`, so a broken build never overwrites `lib/`.
|
|
115
|
+
- Every JavaScript export carries its `types` condition (enforced by
|
|
116
|
+
`lint:style`), so downstream resolves these declarations; there is no
|
|
117
|
+
second, hand-written type surface.
|
|
118
|
+
- The protocol message union and friends are the single home now: consumers
|
|
119
|
+
import them (`@typedef {import("./agent-protocol.js").AgentMessage}
|
|
120
|
+
AgentMessage`) instead of restating them, which is how `lib/agent.js` and
|
|
121
|
+
the script-driven tests read them.
|
|
122
|
+
|
|
123
|
+
### Adding a module
|
|
124
|
+
|
|
125
|
+
1. Write `src/<name>.ts`; imports name the artifact (`./x.js`), which
|
|
126
|
+
`nodenext` resolves through the TypeScript source. Move every type into the
|
|
127
|
+
signature, keep the prose, and keep every exported NAME — types included,
|
|
128
|
+
since consumers import them (`import("./paths.js").DistroPath`). Close the
|
|
129
|
+
module doc with the note that names the generated artifact.
|
|
130
|
+
2. `pnpm run build`, then `pnpm test`. There is no exclude list to maintain and
|
|
131
|
+
no registration step: the build and `lint:build` derive everything from
|
|
132
|
+
`src/`, and `lib/` is generated output — never edit it by hand.
|
|
133
|
+
3. If the module gets a row of its own on the Plugins page, add its display
|
|
134
|
+
metadata as `locale/<name>/en.json` and `locale/<name>/zh.json` — a
|
|
135
|
+
`meta.title` / `meta.description` pair each — and expose both through
|
|
136
|
+
`exports` (`./<name>/locale/en.json`, `./<name>/locale/zh.json`), which is
|
|
137
|
+
what that page reads before falling back to the package `description`. The
|
|
138
|
+
bundle's own pair is `locale/en.json` / `locale/zh.json`, and `subprocess`,
|
|
139
|
+
`picker`, `shell-env` and `auto-preset` carry theirs; `files` already ships
|
|
140
|
+
`locale/**/*.json`, and `lint:style` fails an `exports` target that does not
|
|
141
|
+
exist.
|
|
33
142
|
|
|
34
143
|
## The development loop
|
|
35
144
|
|
|
36
145
|
1. Clone the repository inside the distro. Most contributors develop there.
|
|
37
146
|
2. Make the change.
|
|
38
147
|
3. Run the gates below.
|
|
39
|
-
4.
|
|
40
|
-
|
|
41
|
-
|
|
148
|
+
4. If you changed anything under `lib/`, run `pnpm run sync:windows` first and
|
|
149
|
+
then restart the DSH app. The app loads the Windows mirror (see below), so a
|
|
150
|
+
restart without the sync just reloads the old code; a running process also
|
|
151
|
+
caches ES modules.
|
|
42
152
|
|
|
43
153
|
### The runtime mirror
|
|
44
154
|
|
|
@@ -50,7 +160,7 @@ The Windows copy under `default-workspace/dsh-plugin-wsl` is a runtime mirror. S
|
|
|
50
160
|
it before launching the app:
|
|
51
161
|
|
|
52
162
|
```bash
|
|
53
|
-
|
|
163
|
+
pnpm run sync:windows
|
|
54
164
|
```
|
|
55
165
|
|
|
56
166
|
The mirror destination sits outside a session workspace. An agent that runs the
|
|
@@ -62,28 +172,31 @@ terminal if you would rather not see the prompt.
|
|
|
62
172
|
|
|
63
173
|
| Command | Covers | Needs a harness |
|
|
64
174
|
|---|---|---|
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
74
|
-
| `
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
79
|
-
| `
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
175
|
+
| `pnpm test` | style checks, syntax pass, build consistency, type check, and unit tests | no |
|
|
176
|
+
| `pnpm run test:coverage` | unit tests with coverage | no |
|
|
177
|
+
| `pnpm run lint:style` | style and lint rules | no |
|
|
178
|
+
| `pnpm run lint:build` | the build-freshness check: every source has its artifacts and the committed bytes match a real build | no |
|
|
179
|
+
| `pnpm run lint:types` | the TypeScript check over `test/**` and the ambient types (`tsc --noEmit`) | no |
|
|
180
|
+
| `pnpm run probe` | filesystem behaviour against a real distro | yes |
|
|
181
|
+
| `pnpm run probe:sandbox` | what bubblewrap confines and what it does not | no |
|
|
182
|
+
| `pnpm run probe:sandbox-shell` | the confined executor through a real boot | yes |
|
|
183
|
+
| `pnpm run probe:terminal` | the terminal provider | yes |
|
|
184
|
+
| `pnpm run probe:substrate` | the agent filesystem substrate over a real `wsl.exe` transport | no; inside the distro |
|
|
185
|
+
| `pnpm run probe:watch` | the in-distro watcher over a real directory | no; inside the distro |
|
|
186
|
+
| `pnpm run probe:agent` | the resident-vs-one-shot fallback parity legs | no; inside the distro |
|
|
187
|
+
| `pnpm run probe:exec` | the agent-backed execution handle: timeout, kill, cwd failure | no; inside the distro |
|
|
188
|
+
| `pnpm run probe:missing-wsl` | how a `wslPath` that cannot start is reported | yes |
|
|
189
|
+
| `pnpm run probe:picker` | the picker's root level, its refusals and its cap | yes |
|
|
190
|
+
| `pnpm run probe:mode` | which POSIX-mode facts survive the share | no; Windows Node |
|
|
191
|
+
| `pnpm run probe:sandbox-off` | the documented opt-out on both providers | yes |
|
|
192
|
+
|
|
193
|
+
Every script above is wired in `package.json`. `pnpm test` runs `lint:style`,
|
|
194
|
+
`test:syntax`, `lint:build`, `lint:types` and `test:unit` in that order.
|
|
195
|
+
`prepublishOnly` runs `pnpm test` again at publish time, so a broken gate stops a
|
|
196
|
+
release before the upload.
|
|
197
|
+
|
|
198
|
+
CI runs `pnpm test` on Node 22 and 24, on both `ubuntu-latest` and
|
|
199
|
+
`windows-latest`, and `pnpm run test:coverage` on Node 24. The Windows runners are
|
|
87
200
|
there because the plugin targets Windows; the coverage thresholds need Node 22.8 or
|
|
88
201
|
newer, which is why that job runs on one version.
|
|
89
202
|
|
|
@@ -91,6 +204,19 @@ The probes marked "yes" need Windows, WSL2, a mounted harness profile and a link
|
|
|
91
204
|
checkout, which a hosted runner does not have. Run them on your own machine and
|
|
92
205
|
paste the output into the pull request.
|
|
93
206
|
|
|
207
|
+
The rows marked "no; inside the distro" (`substrate`, `watch`, `agent`, `exec`)
|
|
208
|
+
still need Windows and WSL2, but no harness boot and no profile: run them from a
|
|
209
|
+
distro terminal with Node available, and they reach `wsl.exe` through interop.
|
|
210
|
+
|
|
211
|
+
Two conveniences for the real-machine set. `test/probe/run-all-when-closed.sh
|
|
212
|
+
--include-fs` runs all twelve probes once the app has exited. And `ci.yml` has a
|
|
213
|
+
`probes` job you dispatch by hand: `sandbox` runs whenever WSL is present, then
|
|
214
|
+
`mode`, `terminal`, `picker` and `missing-wsl` where the harness app is
|
|
215
|
+
installed. It is named for a self-hosted Windows runner although its `runs-on`
|
|
216
|
+
carries the hosted `windows-latest` label, and it is not a green no-op on a
|
|
217
|
+
hosted runner — the `sandbox` leg fails, not skips, where the default distro has
|
|
218
|
+
no bubblewrap.
|
|
219
|
+
|
|
94
220
|
## Adding a test
|
|
95
221
|
|
|
96
222
|
Choose the layer by what the test needs.
|
|
@@ -100,44 +226,70 @@ Choose the layer by what the test needs.
|
|
|
100
226
|
| Unit test | `test/*.test.mjs` | pure logic: path translation, listing, shell argument building, terminal helpers |
|
|
101
227
|
| Probe | `test/probe/` | behaviour that needs a real distro, a real profile, or bubblewrap |
|
|
102
228
|
|
|
103
|
-
Unit tests run under `node --test`.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
`test
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
229
|
+
Unit tests run under `node --test`. The `test:unit` and the `test:coverage` lists
|
|
230
|
+
in `package.json` name their files explicitly; a test that only touches this
|
|
231
|
+
repository belongs in both. Two lags in those lists today are hygiene to fix in
|
|
232
|
+
passing, not a pattern to copy: each names one file twice
|
|
233
|
+
(`test/fsio-text.test.mjs` in `test:unit`, `test/fs.boot.test.mjs` in
|
|
234
|
+
`test:coverage`), and `test/fs-routing.test.mjs` is in neither
|
|
235
|
+
(`docs/REQUIREMENTS.zh.md` tracks that as OI-7).
|
|
236
|
+
|
|
237
|
+
A test that imports a pinned `@deepseek-ai/*` package goes in the same lists and
|
|
238
|
+
needs no guarding — CI runs `pnpm install --frozen-lockfile` over the locked tree
|
|
239
|
+
before `pnpm test`. Five files import such packages at runtime today —
|
|
240
|
+
`test/provider.test.mjs` is what covers the assembled service rows, and
|
|
241
|
+
`test/composition.test.mjs` runs the loader's real patch algorithm — and a sixth
|
|
242
|
+
(`test/terminal-activity.test.mjs`) reaches a peer only through a JSDoc type
|
|
243
|
+
import, which `checkJs` still resolves.
|
|
244
|
+
|
|
245
|
+
Where a peer-free seam exists, prefer it. `test/sandbox.test.mjs` runs against
|
|
246
|
+
`lib/sandbox-core.js`, with a stand-in for the peer's `SandboxUnavailableError`
|
|
247
|
+
contract, which leaves only the one-line peer binding in `lib/sandbox.js`. That
|
|
248
|
+
line is covered by the harness probes, which boot the plugin and so reach
|
|
249
|
+
`WslSandbox` through `lib/index.js` — not by `probe:sandbox`, which reads only
|
|
250
|
+
the argument builder out of `lib/bwrap.js`. A test that cannot run everywhere
|
|
251
|
+
must skip itself — print a `SKIP` line and exit 0 — the way that file does on
|
|
252
|
+
`win32`, where its fake `wsl.exe` (a POSIX script) cannot execute.
|
|
253
|
+
|
|
254
|
+
Probes are shell scripts, plus the small plugin files they load: the `*-probe.mjs`
|
|
255
|
+
and `*-probe.yml` files in the same directory. Two shapes. The harness probes
|
|
256
|
+
(`run.sh`, `terminal.sh`, `sandbox-shell.sh`, `picker.sh`, `missing-wsl.sh`,
|
|
257
|
+
`sandbox-off.sh`) boot a throwaway profile whose setup steps are in the header of
|
|
258
|
+
`test/probe/run.sh`; the five others reuse the profile `run.sh` creates rather
|
|
259
|
+
than making their own. The distro probes (`substrate.sh`, `watch.sh`, `agent.sh`,
|
|
260
|
+
`exec.sh`) boot nothing: they run from a distro terminal and drive the resident
|
|
261
|
+
agent through the `wsl.exe` interop transport. `sandbox.sh` and `mode.sh` sit
|
|
262
|
+
outside both groups — no harness boot, no profile.
|
|
114
263
|
|
|
115
264
|
Keep probe output idempotent. Several probes delete their scratch files at the
|
|
116
265
|
start, because a leftover file from an earlier run changes the result.
|
|
117
266
|
|
|
118
267
|
## What has been verified
|
|
119
268
|
|
|
120
|
-
`
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
269
|
+
`pnpm test` runs the whole unit suite once the one `pnpm install` above has
|
|
270
|
+
fetched the pinned packages: the files that import them statically exercise the
|
|
271
|
+
services through the loader and their declared types, and `test:syntax` keeps a
|
|
272
|
+
`node --check` pass over every shipped module. What no test on a Linux leg can
|
|
273
|
+
reach is the Windows-plus-WSL2 topology itself: a real `wsl.exe`, a real distro,
|
|
274
|
+
a real harness boot. That is the gap the probes close; the archived record's
|
|
275
|
+
§15.4 documents the five rounds of misdiagnosis it once caused.
|
|
125
276
|
|
|
126
277
|
`test/probe/sandbox.sh` needs no harness: it uses the same arguments
|
|
127
278
|
`lib/sandbox.js` builds and asserts what bubblewrap does and does not confine,
|
|
128
279
|
recording the interop escape as `INFO` because a Linux sandbox cannot govern a
|
|
129
|
-
Windows process. The
|
|
280
|
+
Windows process. The harness probes boot a throwaway profile bound to the distro:
|
|
130
281
|
|
|
131
282
|
- the filesystem probe asserts the write path and the write checks — a write outside
|
|
132
283
|
the policy root and a write in `read-only` mode both return `FS_SANDBOX_DENIED`,
|
|
133
|
-
while `danger-full-access` is
|
|
284
|
+
while `danger-full-access` is the approved escalation and its write is asserted
|
|
285
|
+
to land;
|
|
134
286
|
- the shell probe drives all three modes through `ctx.shell` and checks the refusal
|
|
135
287
|
classification the tool layer returns;
|
|
136
288
|
- the terminal probe asserts the distro, the starting directory, and the `DSH_*`
|
|
137
289
|
variables forwarded through `WSLENV`.
|
|
138
290
|
|
|
139
|
-
The setup steps for
|
|
140
|
-
`
|
|
291
|
+
The setup steps for that throwaway profile are in the header of
|
|
292
|
+
`test/probe/run.sh`; the harness probes share the one profile it creates.
|
|
141
293
|
|
|
142
294
|
On Windows 11 + WSL2 (Ubuntu 26.04) the following has been verified:
|
|
143
295
|
|
|
@@ -152,11 +304,12 @@ On Windows 11 + WSL2 (Ubuntu 26.04) the following has been verified:
|
|
|
152
304
|
outside the session workspace is refused inside the distro and the following
|
|
153
305
|
wider-permission request succeeds.
|
|
154
306
|
|
|
155
|
-
Counts:
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
307
|
+
Counts: 28 unit test files under `test/` — 27 of them registered in the
|
|
308
|
+
`test:unit` list, see the OI-7 note above — which need the pinned packages
|
|
309
|
+
installed, and over 1000 `assert` call sites across them; 19 filesystem-probe
|
|
310
|
+
assertions; 15 shell-probe checks; 9 picker checks; 6 missing-executable checks;
|
|
311
|
+
5 mode checks; 5 opt-out checks and 10 sandbox expectations plus the recorded
|
|
312
|
+
escape; and 3 terminal assertions.
|
|
160
313
|
|
|
161
314
|
## Commit and pull request conventions
|
|
162
315
|
|
package/README.md
CHANGED
|
@@ -26,25 +26,31 @@ dsh --profile wsl # 4. run
|
|
|
26
26
|
|
|
27
27
|
Step 3 should print a layer named `# == dsh-plugin-wsl-env`, and `- id: terminal-controller` should now carry `shell: { path: wsl.exe, name: WSL }`. The package is a DSH bundle, so step 2 applies [`cordis.patch.yml`](cordis.patch.yml) as a configuration layer; nothing is merged by hand.
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
**Before the first command, give the distro bubblewrap.** Every command runs confined by [bubblewrap](#sandbox), which most distros do not preinstall, and without it every command fails closed — by design, never unconfined:
|
|
30
|
+
|
|
31
|
+
```powershell
|
|
32
|
+
wsl.exe -d <distro> -u root -- apt-get install -y bubblewrap # Debian/Ubuntu
|
|
33
|
+
```
|
|
30
34
|
|
|
31
|
-
|
|
35
|
+
From a checkout of this plugin, `pnpm run bootstrap -- <distro>` checks all four tools the plugin uses (bubblewrap, ripgrep, git, inotify-tools) and prints the install command for the distro's own package family; add `--install` to run it. A skipped step announces itself: when a distro session opens, the plugin probes bubblewrap and warns with the exact remedy — the first command never has to be the discovery moment.
|
|
36
|
+
|
|
37
|
+
Then open a folder under `\\wsl.localhost\<distro>\...` in the GUI. The picker lists every installed distro at its root level, and **New terminal** opens a shell in the distro.
|
|
32
38
|
|
|
33
39
|
Uninstall: `dsh plugin --profile wsl remove dsh-plugin-wsl-env`. Upgrade: run the same `add` command again.
|
|
34
40
|
|
|
35
|
-
> **Changed anything under `lib/`?
|
|
41
|
+
> **Changed anything under `lib/`? Sync the mirror, then restart the app.** The app loads the Windows-side runtime mirror, so run `pnpm run sync:windows` first — a restart without the sync just reloads the old code; a running process also caches ES modules. See [Development](#development).
|
|
36
42
|
|
|
37
43
|
## Using it
|
|
38
44
|
|
|
39
45
|
Open `\\wsl.localhost\ubuntu\home\you\project` as the workspace, then ask the model "what kernel am I on, and what is in `/etc/os-release`?". It runs `uname -r` and reads that file inside the distro. Nothing goes through `/mnt/c`, and no files are copied.
|
|
40
46
|
|
|
41
47
|
- **A distro folder gets the distro environment automatically.** The `wsl` preset is bound while the session is created, so the first tool call is already correct.
|
|
42
|
-
- **Commands** run
|
|
48
|
+
- **Commands** run inside the distro in your login shell, so your `PATH`, `nvm`, `cargo`, `pyenv` and rc files apply; the shell is not hardcoded to bash. The default is the resident in-distro agent — one long-lived process per distro; while it is out (or with `agent: false`) the same command falls back to one `wsl.exe -d <distro> --cd <linux dir> --exec <your login shell> -lc <command>` process.
|
|
43
49
|
- **Files are the distro's real files.** `/home/you/x` and `\\wsl.localhost\ubuntu\home\you\x` are the same file, and `/mnt/c/...` reaches the Windows disk.
|
|
44
50
|
- **The terminal** (right sidebar, then *New terminal*) opens a shell inside the distro, in the session's folder.
|
|
45
51
|
- **Port visibility.** The model sees which ports have a listener inside the distro (`DSH_WSL_PORTS`, refreshed about every 10 s), so it can hand you the exact URL of a dev server it just started; WSL2's localhost forwarding makes it reachable from Windows directly.
|
|
46
|
-
- **The model sees its shell environment.** The plugin registers `DSH_WSL_DISTRO`, `DSH_WSL_SHELL` and `
|
|
47
|
-
- **Permissions work as on a Linux host.** The Permissions selector switches between `read-only`, `workspace-write` (the default) and `danger-full-access`. A refused command or write comes back with an offer to
|
|
52
|
+
- **The model sees its shell environment.** The plugin registers `DSH_WSL_DISTRO`, `DSH_WSL_SHELL`, `DSH_WSL_HOME` and the port snapshot `DSH_WSL_PORTS` in the managed `DSH_*` namespace.
|
|
53
|
+
- **Permissions work as on a Linux host.** The Permissions selector switches between `read-only`, `workspace-write` (the default) and `danger-full-access`. A refused command or write comes back with an offer to retry it once with the narrowest wider mode that suffices; if you approve, that one call runs in the approved mode — from `read-only` that is usually `workspace-write`, still inside the sandbox, and only an escalation to `danger-full-access` runs without one.
|
|
48
54
|
|
|
49
55
|
## Configure
|
|
50
56
|
|
|
@@ -61,19 +67,19 @@ Override a row by id in `$DSH_HOME/profiles/<name>/cordis.patch.yml`. The keys w
|
|
|
61
67
|
| `directory-picker-wsl` | `includeHostHome` | `true` | also list the Windows home directory |
|
|
62
68
|
| `subprocess-wsl` | `distro` | `''` | which distro the GUI terminal opens in |
|
|
63
69
|
|
|
70
|
+
`wsl-shell` and `wsl-fs` are the two rows a by-id patch **cannot** reach: they are plugins of the `wsl` agent preset, nested inside the `preset-wsl` row's `config.plugins`, so `- id: wsl-shell` in your layer changes nothing — the loader only warns `patch: entry "wsl-shell" not found` and the shipped value stays in force. Override the `preset-wsl` row as a whole instead; [docs/CONFIGURATION.md](docs/CONFIGURATION.md#overriding-the-rows-inside-preset-wsl) has the recipe.
|
|
71
|
+
|
|
64
72
|
[`cordis.patch.yml`](cordis.patch.yml) is the commented reference for every shipped value. [docs/CONFIGURATION.md](docs/CONFIGURATION.md) lists the rest, including `shell`, `loginShell`, `cwd`, `timeoutMs`, `preferredDistro` and `maxEntries`; [examples/profile.cordis.patch.yml](examples/profile.cordis.patch.yml) is a machine-local layer to copy from.
|
|
65
73
|
|
|
66
74
|
## Recipes
|
|
67
75
|
|
|
68
76
|
- **Git credential sharing**: let git inside the distro use the Windows-side Git
|
|
69
77
|
Credential Manager — `git config --global credential.helper "/mnt/c/Program\ Files/Git/mingw64/bin/git-credential-manager.exe"`
|
|
70
|
-
(adjust the path to your Windows Git install
|
|
71
|
-
platform behaviour, so ports a dev server listens on inside the distro are
|
|
72
|
-
reachable from Windows directly).
|
|
78
|
+
(adjust the path to your Windows Git install).
|
|
73
79
|
- **Paths and performance**: the model sees and operates on Linux paths
|
|
74
80
|
(`/home/...`) on the distro's own ext4. `/mnt/c` reaches the Windows disk over
|
|
75
81
|
9p — noticeably slow for many small files; keep heavy-IO projects on the
|
|
76
|
-
distro filesystem. `
|
|
82
|
+
distro filesystem. `pnpm run bootstrap -- <distro>` also reports whether
|
|
77
83
|
ripgrep, git and inotifywait (the search, snapshot and watch backends) are in place.
|
|
78
84
|
- **WSLENV passthrough**: WSL imports only the variables listed in `WSLENV`.
|
|
79
85
|
This plugin admits the managed `DSH_*` namespace by prefix, translating the
|
|
@@ -90,17 +96,20 @@ composition (app level, one per process)
|
|
|
90
96
|
│ WSL-folder session → the distro shell, in the session's Linux directory
|
|
91
97
|
│ Windows-folder session → powershell.exe, in the session's Windows directory
|
|
92
98
|
├─ directory-picker-wsl installed distros listed beside the Windows home
|
|
99
|
+
├─ workspace-files-wsl the GUI file tree and previews of a distro workspace, served from inside it
|
|
100
|
+
├─ fs-routing the root filesystem, routed by coordinate
|
|
101
|
+
│ distro UNC → the resident agent; a drive path → the host backend
|
|
93
102
|
├─ wsl-shell-env the DSH_WSL_DISTRO / _SHELL / _HOME / _PORTS facts the model sees
|
|
94
103
|
└─ auto-preset binds the wsl preset when a session opens a distro folder
|
|
95
104
|
|
|
96
105
|
preset-wsl (the wsl agent preset; its services run in isolate realms)
|
|
97
106
|
├─ wsl-shell ctx.shell — wsl.exe --exec <login shell>, confined by bubblewrap inside the distro
|
|
98
|
-
└─ wsl-fs ctx.fs — real distro files
|
|
107
|
+
└─ wsl-fs ctx.fs — real distro files on the resident agent substrate (ext4)
|
|
99
108
|
```
|
|
100
109
|
|
|
101
|
-
**Why two levels.** `wsl-shell` and `wsl-fs` live inside the `wsl` agent preset, which `auto-preset` binds whenever a session's workspace is inside the distro: a Windows-folder session keeps the stock providers, a distro session gets the WSL ones — the environment is a property of the session, not of the process. The terminal controller is the exception: it resolves its execution world through the root context, which never sees a preset's isolate realms, so `subprocess-wsl` sits at the composition level instead.
|
|
110
|
+
**Why two levels.** `wsl-shell` and `wsl-fs` live inside the `wsl` agent preset, which `auto-preset` binds whenever a session's workspace is inside the distro: a Windows-folder session keeps the stock providers, a distro session gets the WSL ones — the environment is a property of the session, not of the process. The terminal controller is the exception: it resolves its execution world through the root context, which never sees a preset's isolate realms, so `subprocess-wsl` sits at the composition level instead. `workspace-files-wsl` and `fs-routing` are composition-level for the mirror-image reason: the GUI file tree and the root `ctx.fs` are session-less, so they cannot be served from a preset. They replace the shipped `workspace-files` and root `fs-sandbox` rows outright; [docs/root-fs-routing.md](docs/root-fs-routing.md) is the design of the root-plane routing.
|
|
102
111
|
|
|
103
|
-
**Commands and files.**
|
|
112
|
+
**Commands and files.** By default a command runs over the resident in-distro agent — one long-lived process per distro, which carries the cwd as part of the request instead of a per-command `--cd`. What it runs is the same `<login shell> -lc <cmd>` inside a distro-side bubblewrap profile assembled with the same arguments as DSH's own Linux runner, so confinement semantics and error messages match a Linux host; while the agent is out, or with `agent: false`, the command falls back to one `wsl.exe -d <distro> --cd <linux dir> --exec <login shell> -lc <cmd>` process. The file tools read and write real distro files on the resident in-distro agent — reads, writes and identities run on ext4 with native symlinks and mode bits — and the file-search spawn is rewritten the same way: a search over a distro workspace runs the distro's own `rg` (`wsl.exe --exec`), never the Windows binary over the 9p share. Writes are checked against the same policy the command sandbox enforces.
|
|
104
113
|
|
|
105
114
|
## Sandbox
|
|
106
115
|
|
|
@@ -112,9 +121,9 @@ Commands are confined by `bubblewrap` inside the distro, and file writes are che
|
|
|
112
121
|
| `workspace-write` | the above, plus the session workspace is writable and `/tmp` is a temporary mount |
|
|
113
122
|
| `danger-full-access` | no sandbox; used for an approved wider-permission request |
|
|
114
123
|
|
|
115
|
-
**`bubblewrap` is required, and it fails closed.** Without it every confined command reports `SANDBOX_UNAVAILABLE` instead of running unconfined.
|
|
124
|
+
**`bubblewrap` is required, and it fails closed.** Without it every confined command reports `SANDBOX_UNAVAILABLE` instead of running unconfined. To opt out, set `sandbox: false` on the row that owns the operation — `wsl-shell` for commands, `wsl-fs` for the write fence, and the top-level `fs-routing` row for its own copy. Note that the two preset rows are reached through `preset-wsl`, not by id (see [Configure](#configure)). The tool layer then tells the model these operations have no sandbox.
|
|
116
125
|
|
|
117
|
-
**The reported enforcement is `partial`, not `full`.** A process inside the distro can still run a Windows program through WSL interop, for example `/mnt/c/.../*.exe`, and bubblewrap does not govern it. `
|
|
126
|
+
**The reported enforcement is `partial`, not `full`.** A process inside the distro can still run a Windows program through WSL interop, for example `/mnt/c/.../*.exe`, and bubblewrap does not govern it. `pnpm run probe:sandbox` demonstrates the boundary on your machine. `maskWindowsDrive: true` on the `wsl-shell`, `wsl-fs` and `fs-routing` rows narrows it — the confined profile shadows `/mnt` with an empty tmpfs, so the drive's files cannot be read or exfiltrated and its executables cannot be launched — but does not close it: a command can still write an executable into the workspace and run it, so enforcement stays `partial`. The complete closure is distro-level, `[interop] enabled=false` in `wsl.conf` (see [docs/CONFIGURATION.md](docs/CONFIGURATION.md)).
|
|
118
127
|
|
|
119
128
|
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#sandbox) for the design, and [docs/LIMITATIONS.md](docs/LIMITATIONS.md) for everything the plugin does not do.
|
|
120
129
|
|
|
@@ -122,39 +131,45 @@ See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#sandbox) for the design, and [do
|
|
|
122
131
|
|
|
123
132
|
| Symptom | Cause | Fix |
|
|
124
133
|
|---|---|---|
|
|
125
|
-
| every command reports `SANDBOX_UNAVAILABLE` | `bubblewrap` is
|
|
134
|
+
| every command reports `SANDBOX_UNAVAILABLE` | `bubblewrap` is missing from the distro, or present but unusable — the error text distinguishes the two and carries the matching remedy | follow the remedy in the error, or set `sandbox: false` on `wsl-shell` (commands) and `wsl-fs` (writes) — see [Configure](#configure) for how to reach those rows |
|
|
126
135
|
| a command or write is refused outside the session folder | expected behaviour of `workspace-write` | accept the wider-permission offer, or open a session on the folder you need |
|
|
127
136
|
| writes are refused even inside the workspace | the session is in `read-only` mode | switch the Permissions selector |
|
|
128
|
-
| `dsh plugin add`
|
|
137
|
+
| `dsh plugin add` prints no confirmation that a layer was added | the dependency is already installed and the bundle list is unchanged, so `add` reconciles to the same manifest without reporting anything — that is the success path, not a failure | nothing to do; the layer is already in place, and `dsh --profile wsl --dump-config` still shows `# == dsh-plugin-wsl-env` |
|
|
129
138
|
| the terminal still opens `cmd.exe` | the `terminal-controller` row from the layer did not apply | check that `dsh --profile wsl --dump-config` shows `shell: { path: wsl.exe, name: WSL }` |
|
|
130
|
-
| changes to `lib/` have no effect | ES
|
|
139
|
+
| changes to `lib/` have no effect | the app loads the Windows-side runtime mirror, and a running process also caches ES modules | run `pnpm run sync:windows` to bring the mirror up to date, then restart the app |
|
|
131
140
|
| `link:\\wsl.localhost\...` leaves a broken symlink | pnpm cannot link a UNC path | link a Windows path instead; developing inside the distro needs the runtime mirror, see [Development](#development) |
|
|
132
|
-
| `glob` and `grep` are slow | a distro search without rg inside the distro falls back to rg's own "command not found"; a Windows-folder search is native and unaffected | run `
|
|
141
|
+
| `glob` and `grep` are slow | a distro search without rg inside the distro falls back to rg's own "command not found"; a Windows-folder search is native and unaffected | run `pnpm run bootstrap -- <distro> --install` (installs ripgrep); distro searches always run the distro's rg — they never walk the 9p share |
|
|
133
142
|
| the terminal reports `unknown` activity | only while the resident agent is out — distro terminals are observed from inside the distro (a `DSH_TERMINAL_ID` marker scanned in `/proc`: a shell alone is `idle`, a shell running anything is `busy`) | check the distro is running; idle terminals are reclaimed automatically after the controller's unattended timeout (2 h by default), and `terminalIdleReclaim: false` restores the close-by-hand posture |
|
|
134
143
|
| a result names an `FS_*` code | the code says what refused it, and what clears it | see the error-code table in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#error-codes) |
|
|
135
144
|
|
|
136
145
|
## Development
|
|
137
146
|
|
|
138
147
|
```bash
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
pnpm run build # compile src/ into lib/ (the artifact is committed; rebuild after editing src/)
|
|
149
|
+
pnpm test # style checks, syntax pass, build consistency, type check, and unit tests
|
|
150
|
+
pnpm run sync:windows # mirror the checkout onto the Windows-side copy the app loads (after any lib/ change, then restart the app)
|
|
151
|
+
pnpm run test:coverage # the unit tests with coverage thresholds (Node 22.8+)
|
|
152
|
+
pnpm run diagnose # read-only diagnostic report for a bug issue: versions, tools, bwrap probe
|
|
153
|
+
pnpm run bootstrap -- <distro> # check the four distro tools; add --install to install what is missing
|
|
154
|
+
pnpm run probe:sandbox # measure inside the distro what bubblewrap does and does not confine
|
|
155
|
+
pnpm run probe # filesystem probe against a real distro (Windows + WSL only)
|
|
156
|
+
pnpm run probe:sandbox-shell # boot a real harness and drive the confined executor
|
|
157
|
+
pnpm run probe:terminal # open a PTY through the terminal provider
|
|
158
|
+
pnpm run probe:substrate # drive the agent filesystem substrate over a real wsl.exe transport (from inside the distro)
|
|
159
|
+
pnpm run probe:watch # arm the in-distro watcher over a real directory (from inside the distro)
|
|
160
|
+
pnpm run probe:agent # the resident-vs-one-shot fallback parity legs (from inside the distro)
|
|
161
|
+
pnpm run probe:exec # the agent-backed execution handle: timeout, kill, cwd failure (from inside the distro)
|
|
162
|
+
pnpm run probe:missing-wsl # boot a profile whose wslPath cannot start (Windows + WSL only)
|
|
163
|
+
pnpm run probe:picker # list the picker's root level, refusals and its cap (Windows + WSL only)
|
|
164
|
+
pnpm run probe:mode # which POSIX-mode facts survive the share (needs a Windows node and an installed harness; opens no profile)
|
|
165
|
+
pnpm run probe:sandbox-off # prove sandbox: false unconfines both providers (Windows + WSL only)
|
|
153
166
|
```
|
|
154
167
|
|
|
155
|
-
|
|
168
|
+
The app loads the Windows-side runtime mirror, not the repository checkout: after changing anything under `lib/`, run `pnpm run sync:windows` before restarting the app — otherwise the restart just reloads the old code. `pnpm run build` regenerates `lib/` from `src/`; the artifact is committed, and the build-freshness check inside `pnpm test` verifies it.
|
|
169
|
+
|
|
170
|
+
One `pnpm install` reproduces the pinned development dependencies before the first run: the tests import pinned `@deepseek-ai/*` packages (the composition and boot tests exercise the loader's real patch algorithm), while the runtime package itself still ships zero dependencies. pnpm is resolved through the `packageManager` field, so any corepack-enabled Node works. CI runs `pnpm test` on Node 22 and 24, on Linux and Windows, and `pnpm run test:coverage` on Node 24; `engines` matches the harness host's own floor (`^22.19.0 || >=24.0.0`).
|
|
156
171
|
|
|
157
|
-
[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) has the file layout, the mounting, and the sandbox design. [CONTRIBUTING.md](CONTRIBUTING.md) has the development loop, the full gate list, and what has been verified.
|
|
172
|
+
[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) has the file layout, the mounting, and the sandbox design. [CONTRIBUTING.md](CONTRIBUTING.md) has the development loop, the runtime mirror, the full gate list, and what has been verified.
|
|
158
173
|
|
|
159
174
|
## Documentation
|
|
160
175
|
|
package/SECURITY.md
CHANGED
|
@@ -45,6 +45,21 @@ These are targets, not a contract.
|
|
|
45
45
|
|
|
46
46
|
If a report is out of scope, we will say so and explain why.
|
|
47
47
|
|
|
48
|
+
## Disclosure
|
|
49
|
+
|
|
50
|
+
A confirmed vulnerability is fixed and disclosed through the ordinary release
|
|
51
|
+
process, not through a separate security track.
|
|
52
|
+
|
|
53
|
+
- The fix ships in the next release of the package, which is the only version the
|
|
54
|
+
Supported versions table above covers.
|
|
55
|
+
- That release records the fix in [`CHANGELOG.md`](CHANGELOG.md), and the GitHub
|
|
56
|
+
Release notes are taken from that section.
|
|
57
|
+
- The advisory is published on this repository's Security tab, where the private
|
|
58
|
+
report was filed, once the release that carries the fix is out.
|
|
59
|
+
|
|
60
|
+
A report that is out of scope, or that we cannot confirm as a vulnerability, is
|
|
61
|
+
closed without a published advisory.
|
|
62
|
+
|
|
48
63
|
## Scope
|
|
49
64
|
|
|
50
65
|
In scope:
|
|
@@ -69,8 +84,9 @@ process inside the distro can still start a Windows program through WSL interop,
|
|
|
69
84
|
for example `/mnt/c/.../*.exe`. That program runs outside the Linux sandbox.
|
|
70
85
|
|
|
71
86
|
This is a documented design boundary, not a vulnerability by itself. The command
|
|
72
|
-
`npm run probe:sandbox` demonstrates it on your machine
|
|
73
|
-
|
|
87
|
+
`npm run probe:sandbox` demonstrates it on your machine when run from inside the
|
|
88
|
+
distro, where `bubblewrap` and `node` must be installed; the README states it in
|
|
89
|
+
its Sandbox section.
|
|
74
90
|
|
|
75
91
|
A report is still welcome if you find an escape that does not depend on interop,
|
|
76
92
|
or if the plugin ever reports `full` while interop is reachable.
|