@twinsearth/w2m-dsh-plugin 0.43.0 → 0.45.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 +104 -0
- package/README.md +4 -4
- package/package.json +3 -3
- package/src/plugin/tools.mjs +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,110 @@ All notable changes to this project are documented here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
5
5
|
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.45.0] — 2026-10-15
|
|
8
|
+
|
|
9
|
+
**The test plan's security cases, made executable — and the one case that had never been watched run.**
|
|
10
|
+
|
|
11
|
+
### A coverage gap with an error code and no test
|
|
12
|
+
|
|
13
|
+
`COMMAND_EXECUTABLE_RELATIVE_PATH` is declared in `allowed-commands.mjs` with a written rationale — *"it names
|
|
14
|
+
a different file in every working directory"*. **A grep across all 81 suites returned zero hits.** The refusal
|
|
15
|
+
path existed and **no test had ever watched it fire.**
|
|
16
|
+
|
|
17
|
+
That is the same class of defect as the three uncalled modules this project shipped: **present, documented, and
|
|
18
|
+
unobserved.** The difference is that a module has a suite and an error code does not. It now has one, and it
|
|
19
|
+
distinguishes the two refusals that are easy to confuse — **an entry that itself names a relative path is
|
|
20
|
+
refused as `EXECUTABLE_RELATIVE_PATH`, while a relative `argv[0]` against an absolute entry is merely
|
|
21
|
+
`NOT_ALLOWED`.**
|
|
22
|
+
|
|
23
|
+
### The plan asserted something the code does, and reading alone would not have settled it
|
|
24
|
+
|
|
25
|
+
The test plan claims `node --test --test-reporter=tap` is **allowed when an entry names it explicitly**, while
|
|
26
|
+
`node --test-reporter=tap` (no `--test`) is refused. The suite says the opposite of half of that —
|
|
27
|
+
`agent.test.mjs` is titled *"refuses --test-reporter and every other argument that makes node load code"*.
|
|
28
|
+
|
|
29
|
+
**Both are right, and the mechanism is the one the refusal's own message names:** the reparse refusal fires on
|
|
30
|
+
**trailing** arguments of a matched entry, and its remedy is *"an entry of its own"*. So:
|
|
31
|
+
|
|
32
|
+
* `['node','--test']` **refuses** `--test-reporter=tap` — verified;
|
|
33
|
+
* `['node','--test'], ['node','--test','--test-reporter=tap']` **allows** exactly that flag — verified;
|
|
34
|
+
* **and still refuses** `--test-reporter=file:///tmp/evil.mjs`, because the second entry pins one value rather
|
|
35
|
+
than opening the flag — verified.
|
|
36
|
+
|
|
37
|
+
**The line between "a named flag" and "a flag" is the whole security property**, so all three are now asserted
|
|
38
|
+
rather than inferred from the refusal's wording.
|
|
39
|
+
|
|
40
|
+
### The plan's `environmental` state does not exist
|
|
41
|
+
|
|
42
|
+
`AGG-003` and the plan's nine-state table name **`environmental`**. The project implements
|
|
43
|
+
**`divergent-platform`** (`tools.mjs`, `report.mjs`, `fleet.mjs`). **A test asserting `environmental` would fail
|
|
44
|
+
against correct code** — the kind of error that gets a real check disabled, because the runner looks broken
|
|
45
|
+
rather than the expectation.
|
|
46
|
+
|
|
47
|
+
### My own error, and it was two errors in one run
|
|
48
|
+
|
|
49
|
+
Running every suite in **one process** with `--experimental-test-isolation=none` produced **41 failures**;
|
|
50
|
+
the project's own entry (`node --test --test-force-exit`, each suite isolated) produced **1**. The other 38 were
|
|
51
|
+
**global state from `mdns-discover`'s fetch stub leaking into `outbound-only`** — my harness, not the code.
|
|
52
|
+
|
|
53
|
+
The 1 real failure was also mine: I bumped the version to `0.45.0` and did not write the CHANGELOG entry, so
|
|
54
|
+
`claims` and `CHANGELOG shape` correctly went red. **Both are recorded because the first is the trap worth
|
|
55
|
+
naming: a test harness that is not the project's harness measures the harness.**
|
|
56
|
+
|
|
57
|
+
**10 new tests, 0 failures** by the project's own entry point.
|
|
58
|
+
|
|
59
|
+
## [0.44.0] — 2026-10-15
|
|
60
|
+
|
|
61
|
+
**A real dispatch proved the parameter does not yet travel — and the tests that make that checkable.**
|
|
62
|
+
|
|
63
|
+
### What the end-to-end attempt showed
|
|
64
|
+
|
|
65
|
+
`cwd_outside_project: true` was dispatched to MacMini with a `cwd_rel` pointing outside its project root.
|
|
66
|
+
**The answer was `refusal_reason: CWD_OUTSIDE_PROJECT`** — the guard firing exactly as if the escape had never
|
|
67
|
+
been asked for.
|
|
68
|
+
|
|
69
|
+
**That is the honest result, and it is not a bug in the change.** The relay serving the fleet started
|
|
70
|
+
`2026-10-14T13:53:14Z`, and MacMini was restarted *before* 0.43.0 was installed there:
|
|
71
|
+
|
|
72
|
+
| Component | On disk | In memory |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| the shared relay | 0.43.0 | **the code from before this change** |
|
|
75
|
+
| MacMini's agent | 0.43.0 | **the code from before this change** |
|
|
76
|
+
|
|
77
|
+
**So the new field had nowhere to travel through.** Neither process knew the name, so the relay dropped it on
|
|
78
|
+
the way in and the agent never saw it. **The refusal is what the old code correctly produces** — and it is also
|
|
79
|
+
the second time in two releases that a real dispatch was more informative than reading the code.
|
|
80
|
+
|
|
81
|
+
### Which is why this release is the tests rather than the feature
|
|
82
|
+
|
|
83
|
+
The parameter is copied by hand in **four** places, and each is a place it can be dropped:
|
|
84
|
+
|
|
85
|
+
1. the plugin's payload
|
|
86
|
+
2. `createTask`'s explicit task object
|
|
87
|
+
3. the `task.created` ledger row — **so a relay restart cannot forget a granted permission**
|
|
88
|
+
4. the offer handed to a machine
|
|
89
|
+
|
|
90
|
+
**This is the shape of the defect that produced the parameter in the first place:** `cwd_rel` was accepted,
|
|
91
|
+
normalized, hashed and stored, and then the guard's own refusal was **discarded** — it travelled most of the
|
|
92
|
+
way and stopped short, with nothing saying so. **The risk in adding a new field is that it travels the same
|
|
93
|
+
distance and stops at the same place.**
|
|
94
|
+
|
|
95
|
+
So the copies are now asserted against the real relay, and both directions are pinned, **including the
|
|
96
|
+
omission**: `false` writes `false` rather than vanishing, so **absence is never ambiguous**, and the check is
|
|
97
|
+
`=== true` rather than truthy, because the value arrives over the wire.
|
|
98
|
+
|
|
99
|
+
The ledger assertion is the one worth naming. A dispatch that runs, a relay that restarts, and a permission
|
|
100
|
+
that is **silently gone** would be the worst available failure — the same dispatch refused afterwards with
|
|
101
|
+
nothing visibly changed.
|
|
102
|
+
|
|
103
|
+
### Containment, re-asserted rather than assumed
|
|
104
|
+
|
|
105
|
+
`resolveProjectCwd`'s guarantee is unchanged: an escape is refused unless asked for, an absolute path is
|
|
106
|
+
refused however it is spelled, a sibling sharing a path prefix is refused, and **the escape is reported** as
|
|
107
|
+
`outside_project` so a result says where a command ran instead of leaving a reader to assume.
|
|
108
|
+
|
|
109
|
+
**12 new tests, 0 failures.**
|
|
110
|
+
|
|
7
111
|
## [0.43.0] — 2026-10-15
|
|
8
112
|
|
|
9
113
|
**A machine stuck in its own state directory — and the parameter that was accepted, hashed, and ignored.**
|
package/README.md
CHANGED
|
@@ -16,8 +16,8 @@ English | [中文](#中文说明)
|
|
|
16
16
|
|
|
17
17
|
## Progress — where this actually is
|
|
18
18
|
|
|
19
|
-
**Current: `0.
|
|
20
|
-
**11 tools,
|
|
19
|
+
**Current: `0.45.0`.** 66 versions since `0.8.0`. The number that matters more than the version:
|
|
20
|
+
**11 tools, 82 suites, 2228 tests, 12 pre-flight checks, 0 failures.**
|
|
21
21
|
|
|
22
22
|
### The three properties this project set out to have
|
|
23
23
|
|
|
@@ -866,8 +866,8 @@ When something does not work, start from the symptom: [TROUBLESHOOTING.md](TROUB
|
|
|
866
866
|
|
|
867
867
|
### 进度 —— 它现在到底到哪一步了
|
|
868
868
|
|
|
869
|
-
**当前版本:`0.
|
|
870
|
-
**11 个工具、
|
|
869
|
+
**当前版本:`0.45.0`**。自 `0.8.0` 以来共 **66 个版本**。比版本号更重要的数字是:
|
|
870
|
+
**11 个工具、82 个测试套件、2228 个用例、12 项预检、0 失败。**
|
|
871
871
|
|
|
872
872
|
#### 三项目标本来的属性
|
|
873
873
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twinsearth/w2m-dsh-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.45.0",
|
|
4
4
|
"description": "DSH: Windows2MacOS — drive the same project on online Windows and macOS machines from one DeepSeek account, across networks and regions. P2P hole punching is the default path (relay + shared server as rendezvous, ledger and fallback), with a bundled STUN responder, Tailscale/public-VPS/tunnel shapes, Rabbit relay + per-machine Localside + eight DSH tools (replicate / split), nine aggregate verdicts and signed requests.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -113,13 +113,13 @@
|
|
|
113
113
|
}
|
|
114
114
|
},
|
|
115
115
|
"scripts": {
|
|
116
|
-
"test": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.test.mjs test/health.test.mjs test/storage.test.mjs test/exit-channel.test.mjs test/council.test.mjs test/council-session.test.mjs test/log-bounds.test.mjs test/test-report.test.mjs test/fleet-scale.test.mjs test/fleet-state.test.mjs test/crypto-blake2s.test.mjs test/installed-version.test.mjs test/permission.test.mjs test/machine-test-packet.test.mjs test/field-authority.test.mjs test/approval-gate.test.mjs test/authority-choice.test.mjs test/reachability-check.test.mjs test/reachability-classify.test.mjs test/accepted-orphans.test.mjs test/acceptance-doc.test.mjs test/layer-model.test.mjs test/cwd-containment.test.mjs test/memory.test.mjs test/tools.test.mjs test/claims.test.mjs test/fleet-target.test.mjs test/client-bundle.test.mjs test/schedule.test.mjs test/auto-update.test.mjs test/update-source.test.mjs test/update-install.test.mjs test/update-wiring.test.mjs test/signing.test.mjs test/stress.test.mjs test/shared-config.test.mjs test/metrics.test.mjs test/metrics-route.test.mjs test/tool-cards.test.mjs test/p2p-stun.test.mjs test/p2p-transport.test.mjs test/p2p-signaling.test.mjs test/p2p-node.test.mjs test/p2p-transport-fields.test.mjs test/p2p-plugin.test.mjs test/p2p-crypto.test.mjs test/stun-server.test.mjs test/loader-entry.test.mjs test/mdns-wire.test.mjs test/mdns-discover.test.mjs test/chatops-approval.test.mjs test/chatops-policy.test.mjs test/chatops-file-safety.test.mjs test/chatops-outbound-queue.test.mjs test/chatops-commands.test.mjs test/chatops-bridge.test.mjs test/chatops-config-route.test.mjs test/chatops-apply.test.mjs test/chatops-ilink-contract.test.mjs test/chatops-fleet.test.mjs test/chatops-account.test.mjs test/chatops-auth.test.mjs test/chatops-fleet-scope.test.mjs test/chatops-handoff.test.mjs test/chatops-fleet-wiring.test.mjs test/chatops-fleet-live.test.mjs test/chatops-takeover.test.mjs test/chatops-device-signing.test.mjs test/chatops-relay-verify.test.mjs test/chatops-durability.test.mjs test/chatops-run-command.test.mjs test/secrets-guard.test.mjs test/chatops-ilink-fleet-bridge.test.mjs test/chatops-fleet-join.test.mjs",
|
|
116
|
+
"test": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/plan-sec-cmd.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.test.mjs test/health.test.mjs test/storage.test.mjs test/exit-channel.test.mjs test/council.test.mjs test/council-session.test.mjs test/log-bounds.test.mjs test/test-report.test.mjs test/fleet-scale.test.mjs test/fleet-state.test.mjs test/crypto-blake2s.test.mjs test/installed-version.test.mjs test/permission.test.mjs test/machine-test-packet.test.mjs test/field-authority.test.mjs test/approval-gate.test.mjs test/authority-choice.test.mjs test/reachability-check.test.mjs test/reachability-classify.test.mjs test/accepted-orphans.test.mjs test/acceptance-doc.test.mjs test/layer-model.test.mjs test/cwd-containment.test.mjs test/cwd-outside-project.test.mjs test/memory.test.mjs test/tools.test.mjs test/claims.test.mjs test/fleet-target.test.mjs test/client-bundle.test.mjs test/schedule.test.mjs test/auto-update.test.mjs test/update-source.test.mjs test/update-install.test.mjs test/update-wiring.test.mjs test/signing.test.mjs test/stress.test.mjs test/shared-config.test.mjs test/metrics.test.mjs test/metrics-route.test.mjs test/tool-cards.test.mjs test/p2p-stun.test.mjs test/p2p-transport.test.mjs test/p2p-signaling.test.mjs test/p2p-node.test.mjs test/p2p-transport-fields.test.mjs test/p2p-plugin.test.mjs test/p2p-crypto.test.mjs test/stun-server.test.mjs test/loader-entry.test.mjs test/mdns-wire.test.mjs test/mdns-discover.test.mjs test/chatops-approval.test.mjs test/chatops-policy.test.mjs test/chatops-file-safety.test.mjs test/chatops-outbound-queue.test.mjs test/chatops-commands.test.mjs test/chatops-bridge.test.mjs test/chatops-config-route.test.mjs test/chatops-apply.test.mjs test/chatops-ilink-contract.test.mjs test/chatops-fleet.test.mjs test/chatops-account.test.mjs test/chatops-auth.test.mjs test/chatops-fleet-scope.test.mjs test/chatops-handoff.test.mjs test/chatops-fleet-wiring.test.mjs test/chatops-fleet-live.test.mjs test/chatops-takeover.test.mjs test/chatops-device-signing.test.mjs test/chatops-relay-verify.test.mjs test/chatops-durability.test.mjs test/chatops-run-command.test.mjs test/secrets-guard.test.mjs test/chatops-ilink-fleet-bridge.test.mjs test/chatops-fleet-join.test.mjs",
|
|
117
117
|
"test:e2e": "node --test --test-force-exit test/e2e.test.mjs test/crossnetwork.test.mjs test/signing-e2e.test.mjs test/outbound-only.test.mjs test/recovery.test.mjs test/pipeline-e2e.test.mjs test/p2p-agent.test.mjs",
|
|
118
118
|
"test:relay": "node --test --test-force-exit test/relay.test.mjs",
|
|
119
119
|
"test:agent": "node --test --test-force-exit test/agent.test.mjs test/memory.test.mjs",
|
|
120
120
|
"test:tools": "node --test --test-force-exit test/tools.test.mjs",
|
|
121
121
|
"test:crossnetwork": "node --test --test-force-exit test/crossnetwork.test.mjs",
|
|
122
|
-
"test:all": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.test.mjs test/health.test.mjs test/storage.test.mjs test/exit-channel.test.mjs test/council.test.mjs test/council-session.test.mjs test/log-bounds.test.mjs test/test-report.test.mjs test/fleet-scale.test.mjs test/fleet-state.test.mjs test/crypto-blake2s.test.mjs test/installed-version.test.mjs test/permission.test.mjs test/machine-test-packet.test.mjs test/field-authority.test.mjs test/approval-gate.test.mjs test/authority-choice.test.mjs test/reachability-check.test.mjs test/reachability-classify.test.mjs test/accepted-orphans.test.mjs test/acceptance-doc.test.mjs test/layer-model.test.mjs test/cwd-containment.test.mjs test/memory.test.mjs test/tools.test.mjs test/claims.test.mjs test/fleet-target.test.mjs test/client-bundle.test.mjs test/schedule.test.mjs test/auto-update.test.mjs test/update-source.test.mjs test/update-install.test.mjs test/update-wiring.test.mjs test/signing.test.mjs test/stress.test.mjs test/e2e.test.mjs test/crossnetwork.test.mjs test/signing-e2e.test.mjs test/outbound-only.test.mjs test/recovery.test.mjs test/pipeline-e2e.test.mjs test/shared-config.test.mjs test/metrics.test.mjs test/metrics-route.test.mjs test/tool-cards.test.mjs test/p2p-stun.test.mjs test/p2p-transport.test.mjs test/p2p-signaling.test.mjs test/p2p-node.test.mjs test/p2p-transport-fields.test.mjs test/p2p-plugin.test.mjs test/p2p-agent.test.mjs test/stun-server.test.mjs test/loader-entry.test.mjs test/mdns-wire.test.mjs test/mdns-discover.test.mjs test/p2p-crypto.test.mjs test/chatops-approval.test.mjs test/chatops-policy.test.mjs test/chatops-file-safety.test.mjs test/chatops-outbound-queue.test.mjs test/chatops-commands.test.mjs test/chatops-bridge.test.mjs test/chatops-config-route.test.mjs test/chatops-apply.test.mjs test/chatops-ilink-contract.test.mjs test/chatops-fleet.test.mjs test/chatops-account.test.mjs test/chatops-auth.test.mjs test/chatops-fleet-scope.test.mjs test/chatops-handoff.test.mjs test/chatops-fleet-wiring.test.mjs test/chatops-fleet-live.test.mjs test/chatops-takeover.test.mjs test/chatops-device-signing.test.mjs test/chatops-relay-verify.test.mjs test/chatops-durability.test.mjs test/chatops-run-command.test.mjs test/secrets-guard.test.mjs test/chatops-ilink-fleet-bridge.test.mjs test/chatops-fleet-join.test.mjs",
|
|
122
|
+
"test:all": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/plan-sec-cmd.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.test.mjs test/health.test.mjs test/storage.test.mjs test/exit-channel.test.mjs test/council.test.mjs test/council-session.test.mjs test/log-bounds.test.mjs test/test-report.test.mjs test/fleet-scale.test.mjs test/fleet-state.test.mjs test/crypto-blake2s.test.mjs test/installed-version.test.mjs test/permission.test.mjs test/machine-test-packet.test.mjs test/field-authority.test.mjs test/approval-gate.test.mjs test/authority-choice.test.mjs test/reachability-check.test.mjs test/reachability-classify.test.mjs test/accepted-orphans.test.mjs test/acceptance-doc.test.mjs test/layer-model.test.mjs test/cwd-containment.test.mjs test/cwd-outside-project.test.mjs test/memory.test.mjs test/tools.test.mjs test/claims.test.mjs test/fleet-target.test.mjs test/client-bundle.test.mjs test/schedule.test.mjs test/auto-update.test.mjs test/update-source.test.mjs test/update-install.test.mjs test/update-wiring.test.mjs test/signing.test.mjs test/stress.test.mjs test/e2e.test.mjs test/crossnetwork.test.mjs test/signing-e2e.test.mjs test/outbound-only.test.mjs test/recovery.test.mjs test/pipeline-e2e.test.mjs test/shared-config.test.mjs test/metrics.test.mjs test/metrics-route.test.mjs test/tool-cards.test.mjs test/p2p-stun.test.mjs test/p2p-transport.test.mjs test/p2p-signaling.test.mjs test/p2p-node.test.mjs test/p2p-transport-fields.test.mjs test/p2p-plugin.test.mjs test/p2p-agent.test.mjs test/stun-server.test.mjs test/loader-entry.test.mjs test/mdns-wire.test.mjs test/mdns-discover.test.mjs test/p2p-crypto.test.mjs test/chatops-approval.test.mjs test/chatops-policy.test.mjs test/chatops-file-safety.test.mjs test/chatops-outbound-queue.test.mjs test/chatops-commands.test.mjs test/chatops-bridge.test.mjs test/chatops-config-route.test.mjs test/chatops-apply.test.mjs test/chatops-ilink-contract.test.mjs test/chatops-fleet.test.mjs test/chatops-account.test.mjs test/chatops-auth.test.mjs test/chatops-fleet-scope.test.mjs test/chatops-handoff.test.mjs test/chatops-fleet-wiring.test.mjs test/chatops-fleet-live.test.mjs test/chatops-takeover.test.mjs test/chatops-device-signing.test.mjs test/chatops-relay-verify.test.mjs test/chatops-durability.test.mjs test/chatops-run-command.test.mjs test/secrets-guard.test.mjs test/chatops-ilink-fleet-bridge.test.mjs test/chatops-fleet-join.test.mjs",
|
|
123
123
|
"pack": "node scripts/pack.mjs",
|
|
124
124
|
"verify:join": "node scripts/verify-join.mjs",
|
|
125
125
|
"lint": "eslint .",
|
package/src/plugin/tools.mjs
CHANGED
|
@@ -208,7 +208,7 @@ const MAX_STAGES = 16;
|
|
|
208
208
|
* `package.json` during `scripts/pack.mjs` rather than hand-maintained, and `W2M_PLUGIN_VERSION`
|
|
209
209
|
* overrides it at runtime for tests and packagers.
|
|
210
210
|
*/
|
|
211
|
-
const PLUGIN_VERSION = '0.
|
|
211
|
+
const PLUGIN_VERSION = '0.45.0';
|
|
212
212
|
|
|
213
213
|
/** How long any single HTTP call may take before it is aborted, in milliseconds. */
|
|
214
214
|
const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
|