upstream-radar 0.40.0 → 0.41.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.
Files changed (48) hide show
  1. package/README.md +123 -225
  2. package/dist/src/cli.js +11 -2
  3. package/dist/src/cli.js.map +1 -1
  4. package/dist/src/dsh-compatibility-ir.d.ts +98 -0
  5. package/dist/src/dsh-compatibility-ir.d.ts.map +1 -0
  6. package/dist/src/dsh-compatibility-ir.js +389 -0
  7. package/dist/src/dsh-compatibility-ir.js.map +1 -0
  8. package/dist/src/dsh-compatibility-issues.d.ts +44 -0
  9. package/dist/src/dsh-compatibility-issues.d.ts.map +1 -0
  10. package/dist/src/dsh-compatibility-issues.js +185 -0
  11. package/dist/src/dsh-compatibility-issues.js.map +1 -0
  12. package/dist/src/dsh-compatibility-ledger.d.ts +150 -0
  13. package/dist/src/dsh-compatibility-ledger.d.ts.map +1 -0
  14. package/dist/src/dsh-compatibility-ledger.js +645 -0
  15. package/dist/src/dsh-compatibility-ledger.js.map +1 -0
  16. package/dist/src/dsh-install-observation.d.ts +88 -1
  17. package/dist/src/dsh-install-observation.d.ts.map +1 -1
  18. package/dist/src/dsh-install-observation.js +579 -6
  19. package/dist/src/dsh-install-observation.js.map +1 -1
  20. package/dist/src/dsh-install-plan.d.ts +16 -6
  21. package/dist/src/dsh-install-plan.d.ts.map +1 -1
  22. package/dist/src/dsh-install-plan.js +272 -46
  23. package/dist/src/dsh-install-plan.js.map +1 -1
  24. package/dist/src/dsh-plugin.d.ts.map +1 -1
  25. package/dist/src/dsh-plugin.js +6 -2
  26. package/dist/src/dsh-plugin.js.map +1 -1
  27. package/dist/src/dsh-runtime.d.ts +6 -0
  28. package/dist/src/dsh-runtime.d.ts.map +1 -1
  29. package/dist/src/dsh-runtime.js +38 -0
  30. package/dist/src/dsh-runtime.js.map +1 -1
  31. package/dist/src/index.d.ts +7 -4
  32. package/dist/src/index.d.ts.map +1 -1
  33. package/dist/src/index.js +4 -1
  34. package/dist/src/index.js.map +1 -1
  35. package/dist/src/installed-graph.d.ts.map +1 -1
  36. package/dist/src/installed-graph.js +105 -26
  37. package/dist/src/installed-graph.js.map +1 -1
  38. package/dist/src/radar-types.d.ts +15 -0
  39. package/dist/src/radar-types.d.ts.map +1 -1
  40. package/dist/src/semver.d.ts.map +1 -1
  41. package/dist/src/semver.js +7 -1
  42. package/dist/src/semver.js.map +1 -1
  43. package/dist/src/version.d.ts +1 -1
  44. package/dist/src/version.js +1 -1
  45. package/docs/README.zh-CN.md +25 -23
  46. package/package.json +1 -1
  47. package/schemas/dsh-compatibility-ir.schema.json +89 -0
  48. package/schemas/dsh-install-observation.schema.json +135 -2
package/README.md CHANGED
@@ -2,258 +2,155 @@
2
2
 
3
3
  [![CI](https://github.com/MicroMilo/upstream-radar/actions/workflows/ci.yml/badge.svg)](https://github.com/MicroMilo/upstream-radar/actions)
4
4
  [![npm](https://img.shields.io/npm/v/upstream-radar)](https://www.npmjs.com/package/upstream-radar)
5
+ [![GitHub stars](https://img.shields.io/github/stars/MicroMilo/upstream-radar)](https://github.com/MicroMilo/upstream-radar/stargazers)
5
6
  [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
6
7
 
7
- **The upstream dependency radar built into [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) plugins.**
8
+ **Compatibility evidence for the [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) plugin ecosystem.**
8
9
 
9
- Upstream Radar is not another package-name vulnerability scanner. It follows one DSH plugin from admission to maintenance:
10
+ A plugin repository can look healthy while its published artifact has drifted
11
+ from the DSH host it actually runs in. Upstream Radar joins what a plugin
12
+ declares with what an isolated DSH profile really resolves, then keeps that
13
+ relationship current as DSH and plugins change.
10
14
 
11
- | Product job | What Radar establishes |
12
- | --- | --- |
13
- | **DSH compatibility / admission** | Whether the exact published bundle can be installed, registered, and loaded by the DSH releases you care about, with an isolated execution lane for behavior evidence. |
14
- | **Real dependency graph** | Which exact package versions and physical paths the plugin brings into the DSH profile, including unresolved edges. |
15
- | **Continuous upstream monitoring** | Whether an advisory, npm release, DSH/Cordis change, or breaking signal changes the old → new situation. |
16
- | **Author-facing repair** | Which plugin, dependency path, version, lockfile, or DSH declaration gives the author a concrete next fix. |
17
-
18
- The deterministic scanner establishes package, graph, advisory, and compatibility facts. Only a meaningful affected change is handed to the DSH Agent for read-only, project-specific analysis; the model does not guess version matches or replace the evidence.
15
+ The core object is an exact environment, not a package name or a diff:
19
16
 
20
- ## The product loop
21
-
22
- ```mermaid
23
- flowchart TD
24
- A["DSH plugin source or exact npm artifact"] --> B["Static review + DSH compatibility check"]
25
- B --> C["Build the real plugin → dependency graph"]
26
- C --> D["Monitor advisories, npm, DSH and Cordis changes"]
27
- D --> E{"Meaningful affected change?"}
28
- E -- "No" --> F["Update observation point and stay quiet"]
29
- E -- "Yes" --> G["Calculate exact old → new impact paths"]
30
- G --> H["Send bounded evidence to the DSH Agent"]
31
- H --> I["Return a repairable action to the plugin author"]
17
+ ```text
18
+ plugin tarball SHA-256 × DSH version × Node/pnpm baseline × approved dependency builds
32
19
  ```
33
20
 
34
- This is the boundary: Radar decides **what changed and which exact path is involved**; DSH decides **what that means for the project**. A later website can visualize the saved graph, but the evidence and impact index are already useful without one.
35
-
36
- ## The upstream/downstream alignment IR
37
-
38
- Every observer snapshot now carries a small, machine-readable alignment record:
21
+ ## How the system fits together
39
22
 
40
- ```text
41
- upstream: Git commit + package.json coordinate
42
- downstream: npm coordinate + lockfile graph root + graph coverage
43
- result: aligned | mismatch | unknown
23
+ ```mermaid
24
+ flowchart TB
25
+ Artifact["Exact plugin tarball"] --> Static["Static: peer declaration + literal import evidence"]
26
+ DSH["Exact DSH + Node runtime"] --> Runtime["Fresh VM + restricted container"]
27
+ Static --> Runtime
28
+ Runtime --> Resolve["Dynamic: install → register → profile resolver → import → headless boot"]
29
+ Resolve --> IR["Compatibility IR: declared range ↔ resolved host version"]
30
+ IR --> Ledger["Current-cell ledger"]
31
+ IR --> Impact["Reverse impact index + author-facing repair"]
32
+ Ledger --> Incident["Managed compatibility incident"]
33
+ Incident --> Repair["Plugin or DSH repair"]
34
+ Repair --> Artifact
44
35
  ```
45
36
 
46
- This catches a class of problems that a vulnerability scanner cannot: the source
47
- package, published package, and dependency graph may no longer describe the
48
- same thing. For example, the public DSH/Feishu target currently reports:
37
+ Radar establishes deterministic facts; an optional Agent may explain project
38
+ impact afterward. A model never decides whether versions match or turns missing
39
+ evidence into a green result.
49
40
 
50
- ```text
51
- source: dsh-lark-bot@0.15.8
52
- published: dsh-feishu-bot@0.15.8
53
- graph root: dsh-lark-bot@0.15.8
54
- result: mismatch
55
- ```
41
+ ## What it answers
56
42
 
57
- That is not a claim of malware or runtime incompatibility. It is an evidence
58
- gap: Radar cannot safely say that the source it watched produced the artifact
59
- users install. The IR is stored in `observations.json`, rendered in the first
60
- baseline report, and defined in [`schemas/upstream-downstream-ir.schema.json`](schemas/upstream-downstream-ir.schema.json).
43
+ | Question | Evidence returned |
44
+ | --- | --- |
45
+ | Does the declared plugin contract align with this DSH release? | Exact tarball, Node contract, install/registration/load evidence, and every direct peer's resolved host version. |
46
+ | Is it a runtime break or a declaration drift? | Static literal-import classification beside the dynamic resolver result. |
47
+ | What enters the DSH profile? | Exact npm/pnpm nodes, host-plane joins, duplicate versions, paths, and unresolved edges. |
48
+ | Which plugins are exposed to an upstream dependency change? | A materialized reverse index from host package to exact plugin cells. |
49
+ | What can the author repair? | One package/range/API boundary with the evidence needed to reproduce it. |
50
+ | What happens after a break is found? | One managed issue is created, updated on repeat failures, reopened on regression, and closed only after a clean retest. |
51
+
52
+ ## Proven on real DSH plugins
53
+
54
+ - Imported a commit-pinned cohort of **8 repositories** from
55
+ [`awesome-dsh-plugin`](examples/dsh/awesome-observer/README.md); 6 independently
56
+ matched npm artifacts enter the isolated matrix and 2 remain correctly
57
+ GitHub-only.
58
+ - In a fresh VM, tested `@zseven-w/dsh-openpencil@0.1.0-rc.1` against current
59
+ DSH `0.1.1-rc.1` on Node 24. Install, registration, direct import, and
60
+ headless boot passed; the exact host-contract check found **12/14** peers
61
+ aligned, one type-only peer declaration missing, and one runtime `react-dom`
62
+ range drift. [Read the reproducible case.](examples/dsh/install-observer/reports/2026-08-22-openpencil-node24.md)
63
+ - Proved `dsh-better-sidebar@0.14.0` succeeds only after the documented
64
+ `node-pty` build is explicitly approved and the native toolchain is present.
65
+ - Found that `@sanqi-normal/dsh-webui-market-plugin@0.5.4` could not form a
66
+ clean DSH dependency graph, gave the author an exact repair path, and added
67
+ the published `0.5.5` repair to the maintained isolated matrix.
68
+ [See the author-confirmed case.](https://github.com/Sanqi-normal/dsh-webui-market-plugin/issues/5)
69
+ - Built a reverse index from **37 real plugin graphs and 1,025 dependency
70
+ coordinates**, while preserving 13 missing-graph targets as evidence gaps.
71
+
72
+ Read the [live isolated matrix and negative controls](examples/dsh/install-observer/reports/2026-08-21-dsh-0.1.1-rc.1.md)
73
+ or inspect the [first 50-plugin corpus](examples/dsh/first-batch/README.md).
61
74
 
62
75
  ## Try it in 60 seconds
63
76
 
64
77
  ```bash
65
- # No DSH profile, API key, or network state required
66
- npx --yes upstream-radar@0.40.0 demo
78
+ # Network-free product walkthrough
79
+ npx --yes upstream-radar@0.41.0 demo
67
80
 
68
- # Scan a public DSH plugin repository without installing it
69
- npx --yes upstream-radar@0.40.0 scan \
81
+ # Static review of a public DSH plugin; no install or plugin execution
82
+ npx --yes upstream-radar@0.41.0 scan \
70
83
  https://github.com/PlutoKeating/dsh-lark-bot \
71
84
  --fail-on never
72
85
 
73
- # Review a real browser plugin users would install, then check two DSH releases
74
- npx --yes upstream-radar@0.40.0 review dsh-plugin dsh-cloudflare-browser-run@0.1.1 \
75
- --dsh-version 0.1.0-rc.6,0.1.0-rc.7
76
- ```
77
-
78
- The important output is evidence, not a green badge: exact package identity, dependency paths, unresolved edges, install-time scripts, npm integrity/signature/provenance, advisory matches, and DSH load results.
79
-
80
- ## The isolated execution lane
81
-
82
- Static metadata tells us that a lifecycle script exists; it cannot tell us what
83
- actually ran. The new [`dsh-install` workflow](.github/workflows/observe-dsh-plugin-install.yml)
84
- therefore uses a separate, deliberately untrusted lane:
85
-
86
- ```text
87
- fresh GitHub-hosted VM (no secrets, read-only repository token)
88
- → restricted container (no host workspace or Docker socket)
89
- → npm pack exact package@version with scripts disabled
90
- → enforce the artifact's declared Node range before plugin code can run
91
- → record the exact Node and pnpm runtime used by the check
92
- → DSH installs that same tarball with only the declared dependency-build approvals
93
- → strace records child processes, network destinations and file writes
94
- → DSH loads the registered bundle under the same exact release
95
- → bounded JSON report survives and a non-compatible pair fails the check
96
- → the container and VM are discarded
97
- ```
98
-
99
- Use **Actions → Observe one DSH plugin install** and supply one exact plugin and
100
- one exact DSH version. The CLI also exposes `probe dsh-install`, but it refuses
101
- to run unless both `--execute` and `UPSTREAM_RADAR_ISOLATED_RUNNER=1` are present;
102
- it is not intended as a normal laptop command.
103
-
104
- This lane is wired into the always-on observer. Radar now watches the official
105
- `@deepseek-ai/dsh` `next` release channel (current DSH releases are prereleases
106
- rather than npm `latest`). A new exact DSH publication fans out the
107
- [nine-plugin maintained corpus](examples/dsh/install-observer/targets.json), one
108
- fresh VM per plugin. Six of those targets come from an identity-checked,
109
- [commit-pinned `awesome-dsh-plugin` cohort](examples/dsh/awesome-observer/README.md);
110
- two additional catalog targets are source-only because their real distribution
111
- is GitHub rather than npm. A mapped plugin publication retests only that plugin. Unchanged
112
- evidence keeps `observations.json` byte-stable, persistent source/publish drift
113
- does not wake the Agent again, and the DSH Agent/API key never enters the execution job.
114
- Build-script approvals are exact package names stored in the maintained target
115
- and copied into every report; an absent list approves nothing.
116
-
117
- The first implementation is intentionally honest about its limit: a container
118
- shares the hosted VM's kernel, and same-container `strace` evidence is not
119
- tamper-proof against determined malicious code. The outer VM is disposable and
120
- secret-free; a Firecracker collector is the later high-assurance backend, not a
121
- claim made by this report. See the [execution boundary and result semantics](examples/dsh/install-observer/README.md)
122
- and [`dsh-install-observation.schema.json`](schemas/dsh-install-observation.schema.json).
123
-
124
- ## What we have already found
125
-
126
- These are real, reproducible cases in this repository—not synthetic “vulnerable package” demos.
127
-
128
- | Case | Finding | Why it matters |
129
- | --- | --- | --- |
130
- | [Live DSH `0.1.1-rc.1` isolated matrix](examples/dsh/install-observer/reports/2026-08-21-dsh-0.1.1-rc.1.md) | Eight exact artifacts install/register/load under their recorded contracts; OpenPencil is stopped before execution because it requires Node ≥24.11 while the isolated runner is Node 22.23; Better Sidebar passes only with its documented `node-pty` build approval and a real native toolchain | The imported awesome cohort found both a genuine runtime-pair incompatibility and a test-environment defect, while preserving the evidence that distinguishes them. |
131
- | [`dsh-cloudflare-browser-run@0.1.1`](examples/reports/dsh-cloudflare-browser-run-0.1.1.txt) | 18 resolved packages, 2 unresolved optional Cordis edges, 0 known vulnerabilities, and DSH rc.6/rc.7 both loaded the bundle | A real browser plugin demonstrates the DSH admission boundary and why incomplete edges stay visible. |
132
- | [50-plugin batch](examples/dsh/reports/dsh-batch-50-2026-08-17.md) / [real graph corpus](examples/dsh/first-batch/README.md) | 50 source scans, 30 exact npm reviews, 37 real plugin graphs indexed; 13 targets kept as missing evidence | The reverse index is now built from real DSH plugins, and missing graphs are not treated as clean. |
133
- | [`dsh-feishu-bot@0.15.8`](examples/dsh/reports/dsh-feishu-bot-0.15.8-review-2026-08-18.md) | 89-package graph, 12 unresolved optional edges, reachable `protobufjs` `postinstall`, DSH rc.6/rc.7 compatible | “No known CVE” is not the same as “no installation trust boundary.” |
134
- | [DSH-TUI source vs npm](examples/dsh/reports/dsh-tui-source-vs-npm-2026-08-18.md) | Source has `prepare`; published artifact does not | Source-only and artifact-only reviews answer different questions. |
135
- | [dsh-composer-expand](examples/dsh/reports/dsh-composer-expand-lockfile-feedback.md) | Committed lockfile root says `0.1.0` while source says `0.1.2` | A small author-fix can restore the identity of the monitored graph. |
136
-
137
- We report a confirmed vulnerability only when the affected exact version and runtime path are supported by the available evidence. Development-only hits, missing data, and advisory-source outages remain visibly different states.
138
-
139
- ## Monitor the findings we already found
140
-
141
- The repository now has a focused watch for seven real DSH plugins from the first
142
- batch. It re-runs the source scan and the exact npm artifact review, then stores
143
- only trusted observations in [`state.json`](examples/dsh/finding-watch/state.json)
144
- and writes the current author-facing result to
145
- [`report.md`](examples/dsh/finding-watch/report.md).
146
-
147
- ```bash
148
- pnpm run monitor:dsh-findings
149
- ```
150
-
151
- The watch distinguishes `persisting`, `added`, `resolved`, `changed`, and
152
- `unknown`. A failed registry request never becomes “resolved”; a source fix also
153
- does not erase a finding that remains in the published npm artifact. The same
154
- loop runs daily in [the dedicated GitHub Actions workflow](.github/workflows/dsh-finding-watch.yml)
155
- and commits the state only when a trusted observation changes. It does not install
156
- plugins, execute lifecycle scripts, load DSH, or call an LLM.
157
-
158
- The current run is already useful: `dsh-msg-hub@0.1.8` has removed the old source
159
- lockfile findings, but its npm artifact still reaches `protobufjs@7.6.5` with a
160
- `postinstall`; `dsh-wsl-workspace` now resolves `koffi@3.1.6`, while the native
161
- install step remains. The other reviewed install/lifecycle findings persist.
162
-
163
- ## The dependency graph behind every alert
164
-
165
- ```text
166
- plugin@1.0.0
167
- ├── framework@2.4.7
168
- │ ├── parser@3.2.1
169
- │ └── archive@1.8.0
170
- └── logger@4.0.2
171
- └── parser@2.9.0 ← the affected physical node
86
+ # Exact artifact review plus a DSH load matrix
87
+ npx --yes upstream-radar@0.41.0 review dsh-plugin \
88
+ dsh-cloudflare-browser-run@0.1.3 \
89
+ --dsh-version 0.1.0-rc.8,0.1.1-rc.1
172
90
  ```
173
91
 
174
- Two copies of `parser` are different nodes. An alert names the exact version and path that entered the DSH profile; it does not page every plugin that happens to use the same package name.
175
-
176
- For a collection of saved reports, build the reverse index that turns an upstream package update into affected plugins:
177
-
178
- ```bash
179
- npx --yes upstream-radar@0.40.0 graph reverse ./reports \
180
- --output reverse-dependency-index.json
181
-
182
- # Ask: which plugins currently depend on this exact package?
183
- npx --yes upstream-radar@0.40.0 graph reverse ./reports \
184
- --package parser@2.9.0
185
-
186
- # Rebuild the checked-in index from the real first 50 DSH plugin reports
187
- pnpm run refresh:dsh-batch
188
- ```
189
-
190
- The generated JSON preserves exact paths such as:
191
-
192
- ```text
193
- plugin@1.0.0 logger@4.0.2 parser@2.9.0
194
- ```
195
-
196
- It also preserves whether the graph is complete or has unresolved optional/peer edges. A later website can visualize this index; the index and evidence remain the product foundation.
197
-
198
- To route an upstream old new change to that index, pass it to the always-on
199
- observer:
200
-
201
- ```bash
202
- npx --yes upstream-radar@0.40.0 observe ./targets.yml \
203
- --reverse-index ./reverse-dependency-index.json \
204
- --state ./observations.json \
205
- --report ./upstream-radar-observer.md
206
- ```
207
-
208
- The observer matches by package name, not only by the new exact version. If
209
- `parser@1.0.0` becomes `parser@2.0.0` upstream while a downstream plugin still
210
- uses `parser@1.0.0`, the report names that plugin and its path as a possible
211
- impact. `complete` or `incomplete` coverage stays attached to the result; this
212
- is an evidence-based routing signal, not a claim that the plugin is already
213
- broken. See the persisted index definition in
214
- [`schemas/reverse-dependency-index.schema.json`](schemas/reverse-dependency-index.schema.json).
215
-
216
- The checked-in real-corpus replay makes this concrete: an observed
217
- `@deepseek-ai/cordis@4.0.1 → 4.0.2` change routes to 17 DSH plugins from the
218
- first 50-plugin batch. The route is marked `incomplete` because 26 of the 37
219
- reconstructed graphs contain unresolved edges; the other 13 targets are kept
220
- outside the index as missing evidence. Run `pnpm run showcase:observer` to
221
- replay baseline → one Agent task → quiet run without network access.
222
-
223
- ## GitHub Action
224
-
225
- The repository already contains a reusable, composite Action in [`action.yml`](action.yml). It runs the same frozen Radar check in CI and writes a short Job Summary.
226
-
227
- ```yaml
228
- - uses: MicroMilo/upstream-radar@v0.40.0
229
- with:
230
- config: upstream-radar.config.json
231
- fail-on: high
232
- ```
233
-
234
- See the [consumer workflow](examples/github-actions/consumer/README.md) for config and lockfile examples. The GitHub Marketplace prompt is a distribution opportunity, not a separate scanning engine: the Action listing should follow a reviewed stable release, while exact tags remain copyable and auditable.
235
-
236
- ## What it does—and does not do
237
-
238
- | It does | It does not claim |
92
+ The code-executing path is deliberately separate. Run **Actions Observe one
93
+ DSH plugin install** to give one exact pair its own secret-free GitHub-hosted VM
94
+ and restricted container.
95
+
96
+ ## Always-on now
97
+
98
+ The scheduled observer watches DSH, plugin source/npm/lockfile evidence every
99
+ day, then reconciles a checked-in **compatibility ledger** against the desired
100
+ current matrix. An isolated run is selected when its exact cell is missing,
101
+ older than seven days, or invalidated by a DSH/plugin coordinate, source graph,
102
+ runtime, or build-policy change. A package update therefore accelerates a
103
+ retest; it is no longer the only trigger.
104
+
105
+ Every report must prove its exact plugin × DSH × Node runtime × build-approval
106
+ cell before it can update the [ledger](compatibility-ledger.json). The Action
107
+ also materializes a bounded [compatibility IR](compatibility-ir.json) and
108
+ [reverse index](compatibility-reverse-index.json). The IR does not copy the
109
+ entire pnpm tree: it preserves the compatibility frontier—the plugin's declared
110
+ non-optional peer range, static use evidence, and concrete package version that
111
+ the final DSH profile resolves.
112
+
113
+ A Node-engine mismatch stops before plugin execution; a maintained target can
114
+ also select its required Node profile explicitly. The profile lockfile and
115
+ effective profile-plus-DSH-host graph are compared on every retest. An
116
+ install/load green result cannot close a cell while a required direct host peer
117
+ is missing, outside its declared range, or indeterminate.
118
+
119
+ When all cells are current, the runtime lane stays quiet. Missing or malformed
120
+ reports never turn green: they remain unsatisfied and are selected again.
121
+
122
+ Actionable incompatibilities become managed issues in the Radar repository.
123
+ The same stable cell owns the issue across plugin and DSH releases: repeated
124
+ failures update it, a regression reopens it, and a later compatible isolated
125
+ run comments with fresh evidence and closes it. `unknown` is deliberately not
126
+ an accusation against a plugin; it fails the observer lane and waits for a
127
+ trustworthy rerun instead of opening an incident.
128
+
129
+ ## Safety boundary
130
+
131
+ | Radar does | Radar does not claim |
239
132
  | --- | --- |
240
- | Reconstruct exact npm/pnpm dependency paths | An empty finding list is a safety certificate |
241
- | Query OSV and GitHub Advisory evidence for exact versions | A missing provenance statement proves maliciousness |
242
- | Compare source and published artifact evidence | Static review replaces runtime evidence |
243
- | Observe exact install/load behavior in a disposable VM and restricted container | One observed run proves adversarial code is safe |
244
- | Check DSH bundle/profile compatibility without business actions | “Compatible” means the plugin is secure |
245
- | Monitor old → new upstream observations | An LLM can repair evidence that was never collected |
133
+ | Static graph and artifact checks without importing plugin code | An empty finding list proves safety |
134
+ | Dynamic checks in a fresh VM and restricted, secret-free container | A shared-kernel container proves hostile code is harmless |
135
+ | Exact-version advisory matching and dependency paths | Every matched plugin is exploitable |
136
+ | Exact-pair compatibility results with explicit coverage | One successful load covers every plugin business action |
246
137
 
247
- ## Install and connect to DSH
138
+ An external symlink in a DSH profile never expands static read scope. Radar only
139
+ uses an outside host plane after it has been discovered from the verified DSH
140
+ process that is actually running the profile.
248
141
 
249
- ```bash
250
- pnpm add upstream-radar
142
+ ## Use it in DSH or CI
251
143
 
252
- # Generate a reviewable DSH profile inventory from the installed profile
253
- npx --yes upstream-radar@0.40.0 setup
144
+ ```bash
145
+ # Generate a reviewable DSH inventory and wiring
146
+ npx --yes upstream-radar@0.41.0 setup
254
147
  ```
255
148
 
256
- For Feishu/webhook routing, DSH Agent handoff, observer state, report schemas, and troubleshooting, use the [full Chinese guide](docs/README.zh-CN.md). The [architecture notes](docs/architecture.md) explain the boundaries and evidence model.
149
+ The repository also ships a [reusable GitHub Action](action.yml), maintained
150
+ [observer workflow](.github/workflows/upstream-observer.yml), and machine-readable
151
+ [schemas](schemas/). See the [Chinese guide](docs/README.zh-CN.md) for complete
152
+ configuration and [architecture notes](docs/architecture.md) for evidence and
153
+ trust boundaries.
257
154
 
258
155
  ## Development
259
156
 
@@ -263,4 +160,5 @@ pnpm test
263
160
  pnpm run release:check
264
161
  ```
265
162
 
266
- The project is Apache-2.0 licensed. Contributions that improve a real DSH plugin report, dependency resolution, advisory matching, or reproducible author feedback are especially welcome.
163
+ Apache-2.0 licensed. Contributions backed by a reproducible DSH plugin case are
164
+ especially welcome.
package/dist/src/cli.js CHANGED
@@ -477,7 +477,7 @@ Usage:
477
477
  upstream-radar profile-check [profile-directory] [--patch <path>] [--report <path>] [--summary] [--json]
478
478
  upstream-radar probe dsh-load <package.tgz> [--dsh-version <exact-version>] [--timeout <seconds>] [--keep-profile] [--json]
479
479
  upstream-radar probe dsh-matrix <package.tgz> --dsh-version <v1>[,<v2>,...] [--timeout <seconds>] [--keep-profile] [--json]
480
- upstream-radar probe dsh-install [npm:]<package>@<exact-version> --dsh-version <exact-version> --isolation-provider <github-actions-hosted-runner|firecracker|other> --execute [--allow-build <package>]... [--timeout <seconds>] [--report <report.json>] [--json]
480
+ upstream-radar probe dsh-install [npm:]<package>@<exact-version> --dsh-version <exact-version> [--case-id <stable-label>] --isolation-provider <github-actions-hosted-runner|firecracker|other> --execute [--allow-build <package>]... [--timeout <seconds>] [--report <report.json>] [--json]
481
481
  upstream-radar review dsh-plugin [npm:]<package>@<exact-version> --dsh-version <v1>,<v2>,... [--json]
482
482
  upstream-radar demo [--json]
483
483
  upstream-radar case dsh-web-ui [--json]
@@ -1284,6 +1284,7 @@ async function runDshInstallObservation(args) {
1284
1284
  throw new Error('probe dsh-install requires an exact npm package');
1285
1285
  }
1286
1286
  let dshVersion;
1287
+ let caseId;
1287
1288
  let isolationProvider;
1288
1289
  let timeoutSeconds = 180;
1289
1290
  let reportPath;
@@ -1298,7 +1299,7 @@ async function runDshInstallObservation(args) {
1298
1299
  else if (argument === '--json') {
1299
1300
  json = true;
1300
1301
  }
1301
- else if (argument === '--dsh-version' || argument === '--isolation-provider' || argument === '--allow-build' || argument === '--timeout' || argument === '--report') {
1302
+ else if (argument === '--dsh-version' || argument === '--case-id' || argument === '--isolation-provider' || argument === '--allow-build' || argument === '--timeout' || argument === '--report') {
1302
1303
  const value = args[index + 1];
1303
1304
  if (value === undefined || value.startsWith('-'))
1304
1305
  throw new Error(`${argument} requires a value`);
@@ -1307,6 +1308,13 @@ async function runDshInstallObservation(args) {
1307
1308
  throw new Error('probe dsh-install accepts only one --dsh-version');
1308
1309
  dshVersion = value;
1309
1310
  }
1311
+ else if (argument === '--case-id') {
1312
+ if (caseId !== undefined)
1313
+ throw new Error('probe dsh-install accepts only one --case-id');
1314
+ if (!/^[a-z0-9][a-z0-9._-]{0,63}$/.test(value))
1315
+ throw new Error('--case-id must be a short lowercase label');
1316
+ caseId = value;
1317
+ }
1310
1318
  else if (argument === '--isolation-provider') {
1311
1319
  if (value !== 'github-actions-hosted-runner' && value !== 'firecracker' && value !== 'other') {
1312
1320
  throw new Error('--isolation-provider must be github-actions-hosted-runner, firecracker or other');
@@ -1344,6 +1352,7 @@ async function runDshInstallObservation(args) {
1344
1352
  const report = await observeDshPluginInstall({
1345
1353
  packageSpec,
1346
1354
  dshVersion,
1355
+ ...(caseId === undefined ? {} : { caseId }),
1347
1356
  allowExecution: true,
1348
1357
  isolationProvider,
1349
1358
  allowedBuilds,