upstream-radar 0.32.0 → 0.33.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/README.md +396 -43
- package/cordis.patch.yml +1 -0
- package/dist/src/cli.js +950 -33
- package/dist/src/cli.js.map +1 -1
- package/dist/src/compatibility.d.ts +3 -1
- package/dist/src/compatibility.d.ts.map +1 -1
- package/dist/src/compatibility.js +146 -12
- package/dist/src/compatibility.js.map +1 -1
- package/dist/src/demo.d.ts +13 -0
- package/dist/src/demo.d.ts.map +1 -0
- package/dist/src/demo.js +85 -0
- package/dist/src/demo.js.map +1 -0
- package/dist/src/doctor.d.ts.map +1 -1
- package/dist/src/doctor.js +62 -0
- package/dist/src/doctor.js.map +1 -1
- package/dist/src/dsh-analysis.d.ts.map +1 -1
- package/dist/src/dsh-analysis.js +2 -1
- package/dist/src/dsh-analysis.js.map +1 -1
- package/dist/src/dsh-plugin.d.ts +9 -3
- package/dist/src/dsh-plugin.d.ts.map +1 -1
- package/dist/src/dsh-plugin.js +87 -11
- package/dist/src/dsh-plugin.js.map +1 -1
- package/dist/src/dsh-runtime.d.ts +7 -0
- package/dist/src/dsh-runtime.d.ts.map +1 -1
- package/dist/src/dsh-runtime.js +21 -0
- package/dist/src/dsh-runtime.js.map +1 -1
- package/dist/src/github-advisory.d.ts +25 -0
- package/dist/src/github-advisory.d.ts.map +1 -0
- package/dist/src/github-advisory.js +335 -0
- package/dist/src/github-advisory.js.map +1 -0
- package/dist/src/graph.d.ts +2 -0
- package/dist/src/graph.d.ts.map +1 -1
- package/dist/src/graph.js +600 -4
- package/dist/src/graph.js.map +1 -1
- package/dist/src/index.d.ts +14 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +13 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/init.d.ts +44 -2
- package/dist/src/init.d.ts.map +1 -1
- package/dist/src/init.js +62 -5
- package/dist/src/init.js.map +1 -1
- package/dist/src/installed-graph.d.ts +3 -1
- package/dist/src/installed-graph.d.ts.map +1 -1
- package/dist/src/installed-graph.js +101 -2
- package/dist/src/installed-graph.js.map +1 -1
- package/dist/src/inventory.d.ts.map +1 -1
- package/dist/src/inventory.js +76 -2
- package/dist/src/inventory.js.map +1 -1
- package/dist/src/notification-policy.d.ts +20 -0
- package/dist/src/notification-policy.d.ts.map +1 -0
- package/dist/src/notification-policy.js +87 -0
- package/dist/src/notification-policy.js.map +1 -0
- package/dist/src/npm-release.d.ts.map +1 -1
- package/dist/src/npm-release.js +18 -7
- package/dist/src/npm-release.js.map +1 -1
- package/dist/src/osv.d.ts.map +1 -1
- package/dist/src/osv.js +1 -0
- package/dist/src/osv.js.map +1 -1
- package/dist/src/quickstart.d.ts +31 -0
- package/dist/src/quickstart.d.ts.map +1 -0
- package/dist/src/quickstart.js +266 -0
- package/dist/src/quickstart.js.map +1 -0
- package/dist/src/radar-history.d.ts +22 -0
- package/dist/src/radar-history.d.ts.map +1 -0
- package/dist/src/radar-history.js +80 -0
- package/dist/src/radar-history.js.map +1 -0
- package/dist/src/radar-render.d.ts.map +1 -1
- package/dist/src/radar-render.js +106 -1
- package/dist/src/radar-render.js.map +1 -1
- package/dist/src/radar-state.d.ts.map +1 -1
- package/dist/src/radar-state.js +264 -6
- package/dist/src/radar-state.js.map +1 -1
- package/dist/src/radar-status.d.ts +36 -1
- package/dist/src/radar-status.d.ts.map +1 -1
- package/dist/src/radar-status.js +199 -16
- package/dist/src/radar-status.js.map +1 -1
- package/dist/src/radar-types.d.ts +128 -3
- package/dist/src/radar-types.d.ts.map +1 -1
- package/dist/src/radar-types.js +4 -0
- package/dist/src/radar-types.js.map +1 -1
- package/dist/src/radar.d.ts +7 -1
- package/dist/src/radar.d.ts.map +1 -1
- package/dist/src/radar.js +432 -70
- package/dist/src/radar.js.map +1 -1
- package/dist/src/render.d.ts.map +1 -1
- package/dist/src/render.js +10 -0
- package/dist/src/render.js.map +1 -1
- package/dist/src/threat-intel.d.ts +46 -0
- package/dist/src/threat-intel.d.ts.map +1 -0
- package/dist/src/threat-intel.js +243 -0
- package/dist/src/threat-intel.js.map +1 -0
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/vulnerability-priority.d.ts +16 -0
- package/dist/src/vulnerability-priority.d.ts.map +1 -0
- package/dist/src/vulnerability-priority.js +20 -0
- package/dist/src/vulnerability-priority.js.map +1 -0
- package/dist/src/webhook.d.ts +84 -0
- package/dist/src/webhook.d.ts.map +1 -0
- package/dist/src/webhook.js +432 -0
- package/dist/src/webhook.js.map +1 -0
- package/docs/README.zh-CN.md +394 -40
- package/package.json +22 -3
- package/schemas/quickstart.schema.json +56 -0
- package/schemas/webhook.schema.json +53 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<h1 align="center">Upstream Radar</h1>
|
|
2
2
|
|
|
3
|
-
<p align="center"><strong>Always-on dependency radar for DeepSeek Harness plugins: exact paths, breaking-change
|
|
3
|
+
<p align="center"><strong>Always-on dependency radar for DeepSeek Harness plugins: exact paths, CISA KEV/EPSS priority signals, breaking-change detection, and project-aware Agent follow-up.</strong></p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
6
|
English · <a href="docs/README.zh-CN.md">简体中文</a>
|
|
@@ -15,31 +15,109 @@
|
|
|
15
15
|
<a href="LICENSE"><img alt="Apache-2.0 license" src="https://img.shields.io/badge/license-Apache--2.0-0f766e?style=flat-square"></a>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
|
+
<p align="center">
|
|
19
|
+
<picture>
|
|
20
|
+
<source media="(max-width: 600px)" srcset="docs/assets/upstream-radar-hero-mobile.jpg">
|
|
21
|
+
<img src="docs/assets/upstream-radar-hero.jpg" alt="Upstream Radar watches a dependency graph, highlights one affected path, and routes one signal to a DSH Agent." width="100%">
|
|
22
|
+
</picture>
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
<p align="center"><em>Upstream signal → exact installed path → durable incident → project-specific DSH Agent analysis</em></p>
|
|
26
|
+
|
|
18
27
|
<p align="center">
|
|
19
28
|
<a href="#try-it-in-60-seconds">Try it in 60 seconds</a> ·
|
|
20
29
|
<a href="#see-one-incident">See one incident</a> ·
|
|
21
30
|
<a href="#install-in-dsh">Install in DSH</a> ·
|
|
31
|
+
<a href="#notify-feishu-or-an-https-endpoint">Notify Feishu</a> ·
|
|
22
32
|
<a href="#run-the-proof">Run the proof</a> ·
|
|
23
33
|
<a href="#run-it-in-github-actions">Run in GitHub Actions</a> ·
|
|
34
|
+
<a href="https://github.com/MicroMilo/upstream-radar/issues/new?template=trial.yml">Share feedback</a> ·
|
|
24
35
|
<a href="#how-the-loop-works">How it works</a> ·
|
|
25
36
|
<a href="ROADMAP.md">Roadmap</a>
|
|
26
37
|
</p>
|
|
27
38
|
|
|
39
|
+
## Start without guessing
|
|
40
|
+
|
|
41
|
+
If you are not sure whether this project should use a DSH profile, a lockfile, or the packaged demo, run the read-only guide first:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx --yes upstream-radar@latest quickstart
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
It looks only at the current directory and local DSH profile metadata. It recommends one of the real paths below, labels every suggested command as read-only, local-file creation, or install/start, and refuses to choose between two lockfiles or multiple DSH profiles. The guide itself never installs packages, starts DSH, queries vulnerability sources, or executes plugin code. Use `--json` to feed the result into a setup page or internal launcher.
|
|
48
|
+
|
|
49
|
+
## Choose the smallest path
|
|
50
|
+
|
|
51
|
+
| Your goal | Start here | What you get |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| Keep a live DSH Agent informed | [`setup`](#install-in-dsh) | A profile-aware monitor that refreshes the installed graph and routes only changed incidents to the matching Agent. |
|
|
54
|
+
| Respond to the first alert | [`radar next`](#install-in-dsh) | One read-only command selects the highest-priority incident and points to the DSH task, verified analysis, or next check. |
|
|
55
|
+
| Add a scheduled CI gate | [GitHub Actions example](examples/github-actions/upstream-radar.yml) | A frozen check from a reviewed config or one lockfile, with a concise Job Summary and a machine-readable JSON report. |
|
|
56
|
+
| Check a plugin before installing it | [`graph` / `init` for npm or pnpm lockfiles](#inspect-an-npm-or-pnpm-lockfile-before-installation) | Exact dependency paths and OSV/GitHub Advisory results without running the plugin or its lifecycle scripts. |
|
|
57
|
+
| Review one exact published artifact | `upstream-radar inspect npm:<package>@<exact-version> --deep` | Package, dependency, vulnerability, and provenance evidence for one release. |
|
|
58
|
+
| Publish and maintain a DSH plugin | [Plugin author path](#for-dsh-plugin-authors) | Start from a real DSH scaffold, review its locked graph, and add a two-step CI gate before users install it. |
|
|
59
|
+
| Send changed events to Feishu | [Feishu or HTTPS webhook](#notify-feishu-or-an-https-endpoint) | Native Feishu V2 text, environment-only secrets, durable acknowledgement, and retry. |
|
|
60
|
+
|
|
61
|
+
If you want project-specific reasoning from DSH, use the first path. If you only need an independent admission or regression gate, use the second or third; they do not require a running DSH profile.
|
|
62
|
+
|
|
28
63
|
## Try it in 60 seconds
|
|
29
64
|
|
|
30
|
-
|
|
65
|
+
Want to see the core value before touching DSH? Run the packaged, network-free demo:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npx --yes upstream-radar@latest demo
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
It prints one exact transitive path, independent advisory-source evidence (including an explicit source conflict), CISA KEV/EPSS prioritization evidence, the read-only DSH Agent handoff, and the next setup command. It uses a local fixture only; it does not inspect your repository, install a plugin, or claim that the demo advisory is real. Use `--json` when you want the same proof as a machine-readable artifact.
|
|
72
|
+
|
|
73
|
+
The core result looks like this (the demo uses a local fixture; fields are abbreviated):
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
[HIGH][NEW] Dependency vulnerability
|
|
77
|
+
Affected: parser@2.9.0
|
|
78
|
+
Paths:
|
|
79
|
+
demo-plugin@1.0.0 -> logger@4.0.2 -> parser@2.9.0
|
|
80
|
+
Threat signal: CISA KEV lists this CVE as exploited in the wild.
|
|
81
|
+
FIRST EPSS estimated exploitation probability: 97.2% (percentile 100.0%)
|
|
82
|
+
Next: Review the fixed version with the DSH Agent in this project.
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The useful part is the exact path and project-specific next step—not another generic list of vulnerable package names.
|
|
86
|
+
|
|
87
|
+
Tried the demo or a real DSH setup? [Share a short trial result](https://github.com/MicroMilo/upstream-radar/issues/new?template=trial.yml) with the versions, path, and redacted outcome. Never include source code, secrets, or private paths.
|
|
88
|
+
|
|
89
|
+
Every command has its own short guide: `npx --yes upstream-radar@latest setup --help`, `npx --yes upstream-radar@latest inspect --help`, and `npx --yes upstream-radar@latest radar status --help` are useful starting points when you are not sure which path to choose.
|
|
90
|
+
|
|
91
|
+
Use DSH with at least one third-party bundle. When it has exactly one such profile, `setup` selects it automatically; pass `--profile <name>` only when you have multiple profiles. The commands below are split between two terminals because DSH normally stays running:
|
|
92
|
+
|
|
93
|
+
Before running `setup`, confirm that DeepSeek Harness is installed and `dsh --help` works. If `setup` cannot find `dsh`, it prints this recovery step again.
|
|
94
|
+
|
|
95
|
+
If DSH has no third-party plugin profile yet, install the plugin you want to monitor first: `dsh plugin --profile <name> add <package>@<exact-version>`.
|
|
31
96
|
|
|
32
97
|
```bash
|
|
33
98
|
# Terminal 1
|
|
34
99
|
pnpm dlx --package=upstream-radar@latest upstream-radar setup \
|
|
35
|
-
--
|
|
36
|
-
|
|
37
|
-
--output ./upstream-radar.config.json \
|
|
38
|
-
--dsh-patch ./upstream-radar.dsh.yml
|
|
100
|
+
--project-name "My DSH project"
|
|
101
|
+
# Use the profile name printed by setup; `web` is only an example.
|
|
39
102
|
dsh --profile web --patch ./upstream-radar.dsh.yml
|
|
40
103
|
```
|
|
41
104
|
|
|
42
|
-
|
|
105
|
+
If you explicitly want setup to launch DSH in the same invocation after its local doctor check passes, add `--start`:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
pnpm dlx --package=upstream-radar@latest upstream-radar setup \
|
|
109
|
+
--project-name "My DSH project" --start
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Without `--start`, setup never launches DSH and gives you a pause to review the generated files. The explicit flag is the one-command path; doctor verifies local wiring, but it is not a human review or a package-safety certificate.
|
|
113
|
+
|
|
114
|
+
The one-command path is also covered by a network-free showcase: `pnpm run showcase:setup-start`.
|
|
115
|
+
|
|
116
|
+
If you use npm rather than pnpm, the equivalent launcher is `npx --yes upstream-radar@latest setup --project-name "My DSH project"`. For a reproducible team workflow, replace `latest` with the exact release you have reviewed.
|
|
117
|
+
|
|
118
|
+
`setup` explicitly installs the exact Radar version used by the command into the selected DSH profile, discovers the installed graph, writes `./upstream-radar.config.json` and `./upstream-radar.dsh.yml` by default, and runs the network-free wiring check. By default it does not start DSH or execute plugin business actions; `--start` opts into launching DSH only after the doctor check passes. Use `--output` or `--dsh-patch` for different paths; if Radar is already installed, add `--no-install`.
|
|
119
|
+
|
|
120
|
+
The printed doctor command uses `npx --yes` with the exact same Radar version, so the handoff also works when the first command was launched with npm rather than pnpm.
|
|
43
121
|
|
|
44
122
|
After DSH is running, use a second terminal for the read-only status check:
|
|
45
123
|
|
|
@@ -50,6 +128,14 @@ pnpm dlx --package=upstream-radar@latest upstream-radar radar status ./upstream-
|
|
|
50
128
|
|
|
51
129
|
The setup command writes a reviewable inventory and an explicit DSH overlay. Its local doctor check verifies the wiring before DSH starts; `radar status` confirms the first completed check without another network request. Read the [full DSH setup](#install-in-dsh) for the legacy environment-variable path, profile boundaries, and the real runtime proof.
|
|
52
130
|
|
|
131
|
+
The same state file keeps a bounded audit trail of real transitions. To answer “what changed and when?” without polling any source:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
pnpm dlx --package=upstream-radar@latest upstream-radar radar history ./upstream-radar.config.json
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
It shows `new`, `updated`, `resolved`, and source-health transitions, including the exact affected path. Use `--json` for a dashboard or relay; the ledger keeps the latest 1,000 transitions and deduplicates stable event ids.
|
|
138
|
+
|
|
53
139
|
If you want to try the monitoring loop without booting a DSH profile, run one cycle from a reviewed inventory:
|
|
54
140
|
|
|
55
141
|
```bash
|
|
@@ -58,19 +144,111 @@ pnpm dlx --package=upstream-radar@latest upstream-radar radar watch ./upstream-r
|
|
|
58
144
|
|
|
59
145
|
Remove `--once` to keep a local monitor alive. This is a lightweight CLI surface for demos, CI, and diagnosis; the native DSH bundle remains the recommended always-on path because it can deliver the task to a live Agent.
|
|
60
146
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
147
|
+
## Notify Feishu or an HTTPS endpoint
|
|
148
|
+
|
|
149
|
+
To also notify a team-owned HTTPS endpoint when an incident changes, keep the endpoint outside the reviewed config and state:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
export UPSTREAM_RADAR_WEBHOOK_URL='https://alerts.example.test/upstream-radar?token=replace-me'
|
|
153
|
+
|
|
154
|
+
# Native DSH path: the bundle reads the variable at runtime.
|
|
155
|
+
dsh --profile web --patch ./upstream-radar.dsh.yml
|
|
156
|
+
|
|
157
|
+
# Or use the CLI path for a persistent one-shot/continuous monitor.
|
|
158
|
+
pnpm dlx --package=upstream-radar@latest upstream-radar radar watch \
|
|
159
|
+
./upstream-radar.config.json --webhook "$UPSTREAM_RADAR_WEBHOOK_URL"
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
The webhook receives only `new`, `updated`, and `resolved` changes (including source-health changes) in the bounded `upstream-radar.webhook/v1alpha1` JSON format described by the [schema](schemas/webhook.schema.json). A successful HTTP 2xx response records the event id; a failed request remains retryable on the next cycle. The state stores only a SHA-256 endpoint fingerprint, delivery ids, and a bounded copy of events waiting for retry or a quiet window; it never stores the URL or its token. Vulnerability summaries include the same short priority evidence as `radar status`—CISA KEV, then EPSS, then severity—so a Feishu message does not require a second interpretation. For a normal endpoint, this provider-neutral JSON can be turned into a Feishu or Slack card by a relay. For a Feishu/Lark V2 custom bot, Radar recognizes the `/open-apis/bot/v2/hook/` URL and sends the native text body directly:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
export UPSTREAM_RADAR_WEBHOOK_URL='https://open.feishu.cn/open-apis/bot/v2/hook/replace-me'
|
|
166
|
+
# Only needed when the Feishu bot has signature validation enabled.
|
|
167
|
+
export UPSTREAM_RADAR_FEISHU_SECRET='replace-me'
|
|
168
|
+
|
|
169
|
+
dsh --profile web --patch ./upstream-radar.dsh.yml
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The Feishu secret is read only from the environment and is never written to the Radar config or state. Follow the [official Feishu custom-bot guide](https://open.feishu.cn/document/ukTMukTMukTM/ucTM5YjL3ETO24yNxkjN?lang=zh-CN) when creating the V2 bot. Use the V2 URL; the older `/open-apis/bot/hook/` form is rejected with an actionable error. Run `pnpm run showcase:webhook` to see deduplication and retry behavior without contacting a real endpoint.
|
|
173
|
+
|
|
174
|
+
For more than one monitored project, give each project its own environment-variable route. The config stores only the variable names, never the webhook URL or secret:
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
"project": {
|
|
179
|
+
"id": "payments-api",
|
|
180
|
+
"name": "Payments API",
|
|
181
|
+
"webhookUrlEnv": "UPSTREAM_RADAR_PAYMENTS_WEBHOOK_URL",
|
|
182
|
+
"webhookSecretEnv": "UPSTREAM_RADAR_PAYMENTS_FEISHU_SECRET"
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
export UPSTREAM_RADAR_PAYMENTS_WEBHOOK_URL='https://open.feishu.cn/open-apis/bot/v2/hook/replace-me'
|
|
189
|
+
export UPSTREAM_RADAR_PAYMENTS_FEISHU_SECRET='replace-me'
|
|
190
|
+
|
|
191
|
+
pnpm dlx --package=upstream-radar@latest upstream-radar setup \
|
|
192
|
+
--webhook-url-env UPSTREAM_RADAR_PAYMENTS_WEBHOOK_URL \
|
|
193
|
+
--webhook-secret-env UPSTREAM_RADAR_PAYMENTS_FEISHU_SECRET
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Each project's changed events go only to its configured endpoint. If two projects intentionally share one endpoint, Radar combines them into one delivery target; conflicting Feishu secrets fail the local `doctor` check instead of choosing one silently. The existing global `UPSTREAM_RADAR_WEBHOOK_URL` and CLI `--webhook` paths remain broadcast-compatible for a single team endpoint. Project webhook ledgers are kept separately under endpoint fingerprints, so a failed Payments delivery cannot acknowledge a Platform event.
|
|
197
|
+
|
|
198
|
+
## Control notification noise without losing evidence
|
|
199
|
+
|
|
200
|
+
The generated inventory can hold ordinary notices while keeping the full incident, dependency path, history, and DSH task intact. For a first setup, use flags so you do not need to edit JSON by hand:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
pnpm dlx --package=upstream-radar@latest upstream-radar setup \
|
|
204
|
+
--minimum-severity high \
|
|
205
|
+
--quiet-hours 'Asia/Shanghai,22:00-08:00'
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
`init --profile`, `init --pnpm-lock`, and `init --npm-lock` accept the same two flags. `--minimum-severity` accepts `info`, `low`, `medium`, `high`, or `critical`. `--quiet-hours` uses `<IANA timezone>,<HH:MM>-<HH:MM>`; the window may cross midnight. The equivalent generated block is:
|
|
209
|
+
|
|
210
|
+
```json
|
|
211
|
+
{
|
|
212
|
+
"notificationPolicy": {
|
|
213
|
+
"minimumSeverity": "high",
|
|
214
|
+
"quietHours": {
|
|
215
|
+
"timezone": "Asia/Shanghai",
|
|
216
|
+
"start": "22:00",
|
|
217
|
+
"end": "08:00"
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
`minimumSeverity` applies to vulnerability notices; `critical` vulnerabilities and malicious-package alerts always pass. `quietHours` uses the configured IANA timezone and also supports a window crossing midnight. Compatibility and source-health notices follow the quiet window but are not hidden by a vulnerability severity threshold. With a policy in effect, DSH tasks stay in the durable outbox until they can be delivered, and the webhook outbox keeps pending events for retry or a later policy change. `radar status` shows how many tasks are currently held. Omitting the block keeps the current behavior and delivers every notice. Run `pnpm run showcase:notifications` for a network-free proof of the hold, later delivery, and durable webhook outbox.
|
|
224
|
+
|
|
225
|
+
If one active incident is noisy, mute only that incident for a bounded period:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
upstream-radar radar next ./upstream-radar.config.json
|
|
229
|
+
upstream-radar mute './upstream-radar.config.json.state.json' '<incident-id>' \
|
|
230
|
+
--until '2026-08-17T12:00:00Z'
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
This pauses only DSH and webhook delivery. The active incident, exact dependency path, history, and status remain visible; the mute expires automatically, and `radar next` prints the matching `unmute` command. A later event version is delivered again, so muting an old fact cannot hide a new fact. Critical and malware incidents require an explicit `--force`.
|
|
234
|
+
|
|
235
|
+
Record the human handoff next to the same incident:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
upstream-radar triage './upstream-radar.config.json.state.json' '<incident-id>' \
|
|
239
|
+
--status in-progress --owner security-team \
|
|
240
|
+
--note 'Trace the parser input path' \
|
|
241
|
+
--due '2026-08-17T12:00:00Z'
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
The available states are `open`, `in-progress`, `blocked`, and `accepted-risk`. `blocked` and `accepted-risk` require a note. `--due` is an optional human deadline; `radar status` and `radar next` mark it as overdue when it passes. This is workflow context only: it never marks an active vulnerability resolved or suppresses its evidence. The record is bound to the exact event id, so an updated upstream fact requires a fresh review; `radar status` and `radar next` show the current owner, note, and deadline.
|
|
67
245
|
|
|
68
246
|
---
|
|
69
247
|
|
|
70
248
|
A vulnerability feed stops at “package X is affected.” Upstream Radar keeps going: it identifies the exact installed dependency path, maintains one durable incident, and wakes a [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) Agent with the project evidence needed for a useful investigation.
|
|
71
249
|
|
|
72
250
|
```text
|
|
73
|
-
OSV
|
|
251
|
+
OSV/GitHub Advisory or npm release
|
|
74
252
|
-> exact installed plugin path
|
|
75
253
|
-> new / updated / resolved incident
|
|
76
254
|
-> project-specific DSH Agent analysis task
|
|
@@ -78,6 +256,8 @@ OSV advisory or npm release
|
|
|
78
256
|
|
|
79
257
|
**No matching installed path means no Agent wake-up.** Version matching and compatibility facts are calculated by code; the model handles only repository-specific judgment.
|
|
80
258
|
|
|
259
|
+
Radar checks OSV and the GitHub Advisory Database as independent vulnerability sources. If both sources describe the same issue through a GHSA or CVE alias, Radar emits one incident and keeps the source identifiers, source list, and fix versions together; human-readable output says `Sources: OSV + GitHub Advisory Database` for this cross-confirmed case. If their severity or fixed-version claims differ, the event also says `Source conflict` and shows each claim instead of silently making the operator infer why multiple fixes are listed. If one source times out, the last confirmed vulnerability evidence and incident identity are retained; the source itself becomes a visible health incident after three consecutive failures instead of being treated as clean. The CLI and DSH adapter use the GitHub source by default, accept an optional `GITHUB_TOKEN` from the environment for API rate limits, and expose `--no-github-advisories` when an operator deliberately needs an OSV-only run. See the [GitHub Advisory Database API](https://docs.github.com/en/rest/security-advisories/global-advisories?apiVersion=2026-03-10) for the upstream query contract.
|
|
260
|
+
|
|
81
261
|
## The missing middle: candidate dependency graphs
|
|
82
262
|
|
|
83
263
|
An upgrade can look clean at the top level while introducing a vulnerable transitive package. Radar therefore does not stop at `plugin@1.3.0`'s manifest:
|
|
@@ -90,6 +270,88 @@ candidate plugin@1.1.0
|
|
|
90
270
|
|
|
91
271
|
For the earliest bounded set of newer versions, Radar resolves npm metadata into a temporary `package-lock.json` with lifecycle scripts disabled, queries every resolved node against OSV, and keeps the exact path in the compatibility event. A missing required edge, resolver failure, or OSV failure is shown as incomplete or unavailable; it is never presented as “no vulnerability found”. Later versions are marked as unchecked when the candidate list is larger than the bounded prefix. The result is still a starting point for DSH project analysis, not an upgrade certificate.
|
|
92
272
|
|
|
273
|
+
## Inspect an npm or pnpm lockfile before installation
|
|
274
|
+
|
|
275
|
+
If a DSH plugin is managed with pnpm, inspect the exact locked tree before putting it into a DSH profile:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
pnpm dlx --package=upstream-radar@latest upstream-radar graph pnpm-lock \
|
|
279
|
+
./pnpm-lock.yaml \
|
|
280
|
+
--json
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
This reads only the lockfile. It does not run `pnpm install`, lifecycle scripts, plugin code, or network requests. It understands pnpm v6/v9 package locators, peer-context variants, duplicate versions, and a project root declared through the `importers` section. An unresolved or ambiguous dependency remains visible instead of being guessed away. The JSON is the same canonical graph shape used by Radar's OSV path matching, so a CI job can review the graph before the plugin is admitted to DSH. Run `pnpm run showcase:pnpm-lock` for a real repository example.
|
|
284
|
+
|
|
285
|
+
To turn that graph into a monitorable inventory and run the first vulnerability check:
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
pnpm dlx --package=upstream-radar@latest upstream-radar init \
|
|
289
|
+
--pnpm-lock ./pnpm-lock.yaml \
|
|
290
|
+
--project-name "My DSH plugin"
|
|
291
|
+
|
|
292
|
+
pnpm dlx --package=upstream-radar@latest upstream-radar radar check \
|
|
293
|
+
./upstream-radar.config.json --frozen --fail-on high
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
`init --pnpm-lock` does not need a DSH profile and writes a normal Radar config; `radar check` then queries exact locked versions and emits the same DSH-ready event shape. Use the native DSH `setup` path when the plugin is installed and should receive follow-up analysis in a live Agent. Run `pnpm run showcase:pnpm-lock:monitor` to see the complete lockfile-to-OSV event locally.
|
|
297
|
+
|
|
298
|
+
When `package.json` sits beside `pnpm-lock.yaml`, `--root` can be omitted; Radar reads the exact package name and version from that manifest. Keep `--root` when the lockfile belongs to another workspace root or when you want the admission coordinate to be explicit.
|
|
299
|
+
|
|
300
|
+
The same path works for npm projects with a committed `package-lock.json`:
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
pnpm dlx --package=upstream-radar@latest upstream-radar graph npm-lock \
|
|
304
|
+
./package-lock.json --json
|
|
305
|
+
|
|
306
|
+
pnpm dlx --package=upstream-radar@latest upstream-radar init \
|
|
307
|
+
--npm-lock ./package-lock.json \
|
|
308
|
+
--project-name "My DSH plugin"
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
For an npm project root, Radar reads `packages[""]` from the lockfile and ignores the root package's development-only dependencies. The command still does not install packages, run lifecycle scripts, load plugin code, or make network requests until the subsequent `radar check` queries OSV.
|
|
312
|
+
|
|
313
|
+
Run `pnpm run showcase:npm-lock:monitor` for a deterministic local proof of this npm lockfile-to-OSV-to-DSH event path.
|
|
314
|
+
|
|
315
|
+
## For DSH plugin authors
|
|
316
|
+
|
|
317
|
+
If you start with the real [`create-dsh-plugin`](https://www.npmjs.com/package/create-dsh-plugin) scaffold, the shortest review-first path is:
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
npx create-dsh-plugin my-dsh-plugin -t tool --yes --skip-install
|
|
321
|
+
cd my-dsh-plugin
|
|
322
|
+
pnpm install --ignore-scripts
|
|
323
|
+
|
|
324
|
+
# Read the exact graph before adding the plugin to a DSH profile.
|
|
325
|
+
pnpm dlx --package=upstream-radar@0.33.0 upstream-radar graph pnpm-lock pnpm-lock.yaml --json
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
The graph includes the exact DSH package versions and keeps unresolved optional peers visible. It does not load the generated plugin or run lifecycle scripts. After reviewing it, copy this complete workflow into `.github/workflows/upstream-radar.yml`:
|
|
329
|
+
|
|
330
|
+
```yaml
|
|
331
|
+
name: Upstream Radar
|
|
332
|
+
|
|
333
|
+
on:
|
|
334
|
+
workflow_dispatch:
|
|
335
|
+
pull_request:
|
|
336
|
+
schedule:
|
|
337
|
+
- cron: '17 6 * * *'
|
|
338
|
+
|
|
339
|
+
permissions:
|
|
340
|
+
contents: read
|
|
341
|
+
|
|
342
|
+
jobs:
|
|
343
|
+
dependency-radar:
|
|
344
|
+
runs-on: ubuntu-latest
|
|
345
|
+
steps:
|
|
346
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
347
|
+
- uses: MicroMilo/upstream-radar@v0.33.0
|
|
348
|
+
with:
|
|
349
|
+
fail-on: high
|
|
350
|
+
fail-on-compatibility: breaking
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
The Action auto-detects the one `pnpm-lock.yaml`, checks the same exact graph, and writes the result to the Job Summary. This is a pre-install and CI gate; it does not install the plugin into DSH. After the graph is reviewed, use the normal `dsh plugin` flow to install it and `upstream-radar setup` to start project-aware monitoring.
|
|
354
|
+
|
|
93
355
|
## See one incident
|
|
94
356
|
|
|
95
357
|
If an advisory affects only one of two installed `parser` versions, Radar reports the path that actually matched:
|
|
@@ -101,13 +363,30 @@ Plugin: plugin@1.0.0
|
|
|
101
363
|
Affected: parser@2.9.0
|
|
102
364
|
Origin: plugin profile
|
|
103
365
|
Advisory: GHSA-demo-2026-parser / CVE-2026-1234
|
|
366
|
+
Sources: OSV + GitHub Advisory Database
|
|
367
|
+
Source conflict: fixed versions — OSV=3.0.0; GitHub Advisory Database=3.1.0
|
|
104
368
|
Paths:
|
|
105
369
|
plugin@1.0.0 -> logger@4.0.2 -> parser@2.9.0
|
|
106
|
-
Fixed versions: 3.0.0
|
|
370
|
+
Fixed versions: 3.0.0, 3.1.0
|
|
107
371
|
Route: payments-platform via feishu:payments-security
|
|
108
372
|
```
|
|
109
373
|
|
|
110
|
-
That incident becomes a plugin-originated DSH notice. It is not copied into a generic chatbot prompt.
|
|
374
|
+
That incident becomes a plugin-originated DSH notice. Radar keeps both source claims visible instead of silently picking one fixed version; the DSH Agent then decides which fix is appropriate for the project. It is not copied into a generic chatbot prompt.
|
|
375
|
+
|
|
376
|
+
For a CVE, native DSH also adds two prioritization signals:
|
|
377
|
+
|
|
378
|
+
```text
|
|
379
|
+
Threat signal: CISA KEV lists this CVE as exploited in the wild.
|
|
380
|
+
FIRST EPSS estimated exploitation probability: 97.2% (percentile 100.0%)
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
[CISA KEV](https://www.cisa.gov/known-exploited-vulnerabilities-catalog) answers “is this CVE known to be exploited in the wild?” [FIRST EPSS](https://www.first.org/epss/) gives a daily estimate of exploitation probability and relative percentile. They help the Agent and the team decide what to inspect first; they do not change the exact dependency match, and a missing signal is not a safety certificate.
|
|
384
|
+
|
|
385
|
+
To replay the two signals and a source outage without network access:
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
pnpm run showcase:threat-intel
|
|
389
|
+
```
|
|
111
390
|
|
|
112
391
|
| Upstream signal | Radar proves deterministically | DSH Agent investigates |
|
|
113
392
|
| --- | --- | --- |
|
|
@@ -120,13 +399,17 @@ Upstream Radar is an npm-published DSH bundle, so no install-time build permissi
|
|
|
120
399
|
|
|
121
400
|
```bash
|
|
122
401
|
pnpm dlx --package=upstream-radar@latest upstream-radar setup \
|
|
123
|
-
--
|
|
124
|
-
--project-name "My DSH project" \
|
|
125
|
-
--output ./upstream-radar.config.json \
|
|
126
|
-
--dsh-patch ./upstream-radar.dsh.yml
|
|
402
|
+
--project-name "My DSH project"
|
|
127
403
|
```
|
|
128
404
|
|
|
129
|
-
`setup` delegates the package installation to DSH using the exact Radar version currently being run. It then generates
|
|
405
|
+
When exactly one DSH profile contains third-party bundles, `setup` selects it automatically; pass `--profile <name>` when more than one profile is eligible. `setup` delegates the package installation to DSH using the exact Radar version currently being run. It then generates `upstream-radar.config.json` and `upstream-radar.dsh.yml` by default, and runs `doctor` locally without contacting OSV, npm, or GitHub. By default it does not start DSH. The explicit one-command path is:
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
pnpm dlx --package=upstream-radar@latest upstream-radar setup \
|
|
409
|
+
--project-name "My DSH project" --start
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
For the review-first path, start the generated overlay yourself:
|
|
130
413
|
|
|
131
414
|
```bash
|
|
132
415
|
dsh --profile web --patch ./upstream-radar.dsh.yml --dump-config
|
|
@@ -146,15 +429,23 @@ pnpm dlx --package=upstream-radar@latest upstream-radar doctor ./upstream-radar.
|
|
|
146
429
|
--patch ./upstream-radar.dsh.yml
|
|
147
430
|
```
|
|
148
431
|
|
|
149
|
-
`doctor` does not contact OSV, npm, GitHub, or execute plugin code. It checks that the config parses, the selected DSH profile actually registers `upstream-radar`, the overlay points to the same config and state files, the dependency coverage is complete, and the durable state can be read. It exits non-zero only for a blocked setup; a missing first-run state is shown as a warning with the next command to run. Add `--json` when another tool needs the result.
|
|
432
|
+
`doctor` does not contact OSV, npm, GitHub, or execute plugin code. It checks that the config parses, the selected DSH profile actually registers `upstream-radar`, the overlay points to the same config and state files, the dependency coverage is complete, and the durable state can be read. When `UPSTREAM_RADAR_WEBHOOK_URL` is set, it also checks the HTTPS route locally, recognizes the native Feishu/Lark V2 path, and blocks the retired V1 path before the first poll; it never prints the URL or `UPSTREAM_RADAR_FEISHU_SECRET`. It exits non-zero only for a blocked setup; a missing first-run state is shown as a warning with the next command to run. Add `--json` when another tool needs the result.
|
|
433
|
+
|
|
434
|
+
The generated overlay points DSH at the config and state files explicitly and records the selected profile. If `--registry <url>` was used during initialization, the same registry is carried into the running DSH monitor; otherwise release and candidate checks use the public npm registry. Before each native DSH polling cycle, and before each CLI `radar check` or `radar watch` cycle, it re-reads that profile's installed graph, so later plugin installs, upgrades, removals, and host-runtime changes are not silently missed. If the refresh fails, that cycle stops without replacing the last durable state. `radar status` remains read-only and reports whether a check has completed, which source is unhealthy, whether dependency coverage is complete, the most important active incidents with their exact path or candidate, a suggested next step, pending DSH tasks, and verified model conclusions. Its Attention list is ordered by CISA KEV evidence, then EPSS score, then advisory severity; each vulnerability line shows the evidence that was actually available. Missing signals are not treated as a safety claim. `radar history` is also read-only and shows the bounded transition ledger from the same state file, including resolved incidents that no longer appear in the active summary. You can inspect a stored conclusion with `upstream-radar analysis list <state.json>` or `analysis show <state.json>`. Radar accepts a conclusion only when the response is strict JSON from the matching DSH model session; it never treats arbitrary chat as an analysis result. `radar compare` remains a manual comparison of the files you provide. If you prefer environment variables or need to override the polling interval, omit `--dsh-patch` and use `UPSTREAM_RADAR_CONFIG`, `UPSTREAM_RADAR_STATE`, `UPSTREAM_RADAR_INTERVAL_SECONDS`, `UPSTREAM_RADAR_REGISTRY`, and `UPSTREAM_RADAR_DEEP_CANDIDATES` as before.
|
|
150
435
|
|
|
151
|
-
|
|
436
|
+
When you only want the next action after an alert, use the shorter read-only view:
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
pnpm dlx --package=upstream-radar@latest upstream-radar radar next ./upstream-radar.config.json
|
|
440
|
+
```
|
|
152
441
|
|
|
153
|
-
|
|
442
|
+
It selects the same first incident as `radar status`, then points to its queued DSH task, verified analysis, or the next check command. When a DSH conclusion is already verified, the output also prints its urgency, recommendation, and bounded evidence list so the operator can act without opening a second report. If a task is queued, it also prints the explicit `task ack` command; acknowledging removes only that delivery item, not the active incident or its evidence.
|
|
443
|
+
|
|
444
|
+
The generated graph is the actual installed profile graph. During a native DSH run, Radar also reads the exact DSH CLI entrypoint (`@deepseek-ai/dsh/lib/bin.js`) and discovers the `node_modules` plane that process is using. It does this with bounded, read-only manifest checks: it does not import DSH, load a plugin, or run an install hook. Packages resolved from that plane are marked as `dsh-host`, and their exact versions are checked for advisories. Radar also records the exact `@deepseek-ai/dsh` executable package that owns the plane, so the DSH core and its reachable host dependencies get OSV and npm release checks even when they are not declared plugin dependencies. The graph uses an explicit `host-runtime` boundary edge; a host finding is never presented as an ordinary plugin dependency. `radar status` says whether the host plane came from the running DSH process or the profile fallback. If a required dependency is declared but cannot be resolved from either place, it remains visible as incomplete coverage instead of being treated as absent. Missing optional platform packages are retained as evidence but do not make coverage incomplete. Passing `--registry <url>` explicitly selects the older public npm artifact graph path, which is useful for comparing a profile against registry resolution but is not the default.
|
|
154
445
|
|
|
155
446
|
For a hand-written or CI fixture, use [the example inventory](examples/radar/config.json). If neither a generated `--patch` overlay nor `UPSTREAM_RADAR_CONFIG` is provided, the bundle stays dormant and performs no polling.
|
|
156
447
|
|
|
157
|
-
Once running, Radar polls OSV, npm, and public GitHub Releases, persists incident state before delivery, and submits only changed incidents to the matching DSH project session. With one root Agent, delivery remains automatic; with multiple roots, Radar requires an exact match between `project.workspace` and `Agent.session.header.cwd`, and keeps the task queued when it cannot prove the route. The native adapter records the exact message id, DSH session, task id, and event id; it writes back only a matching `assistant/message` from that session whose visible text is the six-field JSON result. A new or updated upstream event invalidates the previous result, so an old model conclusion cannot survive a changed dependency fact. If a source is temporarily unavailable, Radar keeps the last confirmed state instead of claiming that the project is clean, continues delivering already queued tasks, and creates one source-health notice after three consecutive failures.
|
|
448
|
+
Once running, Radar polls OSV, GitHub Advisory Database, npm, and public GitHub Releases, then queries CISA KEV and FIRST EPSS for matched CVEs. Native DSH enables those two prioritization feeds by default; set `UPSTREAM_RADAR_THREAT_INTEL=false` when a lean run should omit them. The signals do not decide whether a package is vulnerable: they only explain which confirmed incidents deserve attention first. Radar persists incident state before delivery, and submits only changed incidents to the matching DSH project session. With one root Agent, delivery remains automatic; with multiple roots, Radar requires an exact match between `project.workspace` and `Agent.session.header.cwd`, and keeps the task queued when it cannot prove the route. The native adapter records the exact message id, DSH session, task id, and event id; it writes back only a matching `assistant/message` from that session whose visible text is the six-field JSON result. A new or updated upstream event invalidates the previous result, so an old model conclusion cannot survive a changed dependency fact. If a source is temporarily unavailable, Radar keeps the last confirmed state instead of claiming that the project is clean, continues delivering already queued tasks, and creates one source-health notice for that source after three consecutive failures.
|
|
158
449
|
|
|
159
450
|
Each release cycle also checks a bounded prefix of candidate dependency graphs. This is enabled by default in the DSH adapter and CLI; use `--no-deep-candidates` only when you deliberately want manifest-only compatibility checks. The graph resolver is isolated in a temporary directory and uses `package-lock-only` plus `ignore-scripts`, so candidate package code is not loaded or executed.
|
|
160
451
|
|
|
@@ -188,12 +479,20 @@ The command fails unless DSH proves all five facts:
|
|
|
188
479
|
|
|
189
480
|
This proof runs in CI on Node.js 22. See the executable [showcase contract](examples/dsh/README.md) and its checked-in [result](examples/dsh/reports/headless-smoke.json). Run `pnpm run try:dsh:live` to include a current OSV and npm poll before the DSH handoff.
|
|
190
481
|
|
|
482
|
+
To demonstrate the host-runtime dependency path specifically, run `pnpm run showcase:dsh-runtime`. It starts a real DSH `headless` process, begins at the exact DSH executable package, walks the reachable host dependency closure behind an explicit `host-runtime` boundary, queries a local OSV-compatible feed for the real `@deepseek-ai/cordis` version, persists a `dsh-host` vulnerability path, and hands it to the DSH Agent. The model and advisory are deterministic local stubs; this proves integration and provenance, not the safety of a real advisory.
|
|
483
|
+
|
|
484
|
+
To see why one shared host bug should not page every plugin separately, run `pnpm run showcase:dsh-host-alert`. Two plugin roots share the same exact `@deepseek-ai/cordis` version; Radar emits one project event, keeps both exact paths, and creates one DSH analysis task. Add `:report` to refresh the checked-in [deduplication result](examples/dsh/reports/dsh-host-alert-dedup.json).
|
|
485
|
+
|
|
486
|
+
To validate the actual first-use path against the real published [`dsh-cloudflare-browser-run@0.1.1`](https://www.npmjs.com/package/dsh-cloudflare-browser-run), run `pnpm run showcase:dsh-adoption`. It creates a disposable `DSH_HOME`, packs the exact Radar and plugin tarballs with lifecycle scripts disabled, lets DSH build its own host runtime, runs `setup --no-install`, `doctor`, a frozen OSV/npm/GitHub check, and the human-readable status surface. It does not start a DSH Agent or call a model, and it does not treat an empty finding list as a safety certificate. The checked-in [adoption result](examples/dsh/reports/adoption-smoke.json) records the last run's package counts and boundaries.
|
|
487
|
+
|
|
488
|
+
To see the two-source vulnerability contract without contacting the network, run `pnpm run showcase:github-advisories`. It feeds the same parser issue through OSV and a deterministic GitHub Advisory Database client, proves that two reports become one Radar incident with explicit source provenance and a visible fixed-version conflict, then simulates three GitHub failures and recovery. The existing vulnerability remains active throughout; only the GitHub source-health incident changes.
|
|
489
|
+
|
|
191
490
|
## Validate the compatibility rules
|
|
192
491
|
|
|
193
492
|
Before wiring a project into a compatibility gate, run the offline rule benchmark:
|
|
194
493
|
|
|
195
494
|
```bash
|
|
196
|
-
pnpm dlx --package=upstream-radar@0.
|
|
495
|
+
pnpm dlx --package=upstream-radar@0.33.0 upstream-radar benchmark compatibility
|
|
197
496
|
```
|
|
198
497
|
|
|
199
498
|
It covers six contracts: a safe patch, a change that only needs project analysis, an incompatible DSH peer, a publisher-declared breaking release, a vulnerable candidate dependency, and an incomplete candidate graph. The command does not access the network, install a package, load a plugin, or start DSH. It checks the behavior of Radar's deterministic rules and the `breaking`/`any` gates; it is not a runtime compatibility proof.
|
|
@@ -206,7 +505,7 @@ When you have an exact plugin artifact and want to know whether one exact DSH re
|
|
|
206
505
|
# Pack an exact npm release without running its lifecycle scripts.
|
|
207
506
|
npm pack --ignore-scripts dsh-plugin@1.2.3
|
|
208
507
|
|
|
209
|
-
pnpm dlx --package=upstream-radar@0.
|
|
508
|
+
pnpm dlx --package=upstream-radar@0.33.0 upstream-radar probe dsh-load \
|
|
210
509
|
./dsh-plugin-1.2.3.tgz \
|
|
211
510
|
--dsh-version 0.1.0-rc.6
|
|
212
511
|
```
|
|
@@ -232,7 +531,7 @@ It exercises a loadable bundle, a bundle patch DSH rejects, and a package that r
|
|
|
232
531
|
To compare a plugin against more than one DSH release, use the matrix form:
|
|
233
532
|
|
|
234
533
|
```bash
|
|
235
|
-
pnpm dlx --package=upstream-radar@0.
|
|
534
|
+
pnpm dlx --package=upstream-radar@0.33.0 upstream-radar probe dsh-matrix \
|
|
236
535
|
./dsh-plugin-1.2.3.tgz \
|
|
237
536
|
--dsh-version 0.1.0-rc.3 \
|
|
238
537
|
--dsh-version 0.1.0-rc.6 \
|
|
@@ -243,25 +542,62 @@ The matrix runs versions one at a time in separate temporary profiles and evalua
|
|
|
243
542
|
|
|
244
543
|
## Run it in GitHub Actions
|
|
245
544
|
|
|
246
|
-
If your team wants
|
|
545
|
+
If your team wants the shortest scheduled CI gate before wiring a machine to a live DSH profile, copy [the example workflow](examples/github-actions/upstream-radar.yml). It auto-detects the only `pnpm-lock.yaml` or `package-lock.json` after checkout, so no Radar config is required for the first run. If you already maintain a reviewed `upstream-radar.config.json`, pass it explicitly instead. The reusable Action keeps the workflow to two meaningful steps, with an optional third step for DSH load compatibility:
|
|
247
546
|
|
|
248
547
|
```yaml
|
|
249
548
|
steps:
|
|
250
549
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
251
|
-
- uses: MicroMilo/upstream-radar@v0.
|
|
550
|
+
- uses: MicroMilo/upstream-radar@v0.33.0
|
|
252
551
|
with:
|
|
253
|
-
config: upstream-radar.config.json
|
|
254
552
|
fail-on: high
|
|
255
553
|
# Optional: also fail on deterministic DSH/plugin compatibility breaks.
|
|
256
554
|
fail-on-compatibility: breaking
|
|
555
|
+
# Optional: add CISA KEV and FIRST EPSS signals to matched CVEs.
|
|
556
|
+
threat-intel: true
|
|
257
557
|
```
|
|
258
558
|
|
|
259
|
-
The Action is a thin wrapper around `radar check --frozen --state :memory: --fail-on high --json`; when the optional compatibility input is enabled, it also passes `--fail-on-compatibility breaking` or `any`. `--frozen` is deliberate: it uses the graph in the reviewed config and does not try to read a developer's local DSH profile. Each run is independent, exits `2` when an active vulnerability or opted-in compatibility change meets its threshold, and exits `1` for an operational or source error. `breaking` catches confirmed or strong incompatibility signals; `any` catches every active compatibility event. The default is `never`, so vulnerability-only behavior stays unchanged. The Action does not deliver a DSH Agent task or modify a branch; the native DSH bundle remains the always-on analysis path. Pin the Action to a release tag such as `v0.
|
|
559
|
+
The Action is a thin wrapper around `radar check --frozen --state :memory: --fail-on high --json`; when the optional compatibility input is enabled, it also passes `--fail-on-compatibility breaking` or `any`. `--frozen` is deliberate: it uses the graph in the reviewed config and does not try to read a developer's local DSH profile. `threat-intel` is false by default so an ordinary CI gate stays lean; set it to `true` when the Job Summary and raw JSON should include CISA KEV and FIRST EPSS prioritization evidence. Each run is independent, exits `2` when an active vulnerability or opted-in compatibility change meets its threshold, and exits `1` for an operational or source error. `breaking` catches confirmed or strong incompatibility signals; `any` catches every active compatibility event. The default is `never`, so vulnerability-only behavior stays unchanged. In addition to the raw JSON log, the Action writes a short escaped summary to the GitHub Job Summary so a scheduled failure immediately shows the affected package, exact path, published fix version when available, one-line priority evidence, and a suggested next step. The Action does not deliver a DSH Agent task or modify a branch; the native DSH bundle remains the always-on analysis path. Pin the Action to a release tag such as `v0.33.0`, and pin the checkout Action in your workflow according to your repository's policy.
|
|
560
|
+
|
|
561
|
+
If the repository has no committed Radar config yet, the smallest setup is to omit `config`, `pnpm-lock`, and `npm-lock`. After checkout, the Action automatically uses the only one of `pnpm-lock.yaml` or `package-lock.json` that exists, generates a temporary reviewed config, and runs the same frozen check:
|
|
562
|
+
|
|
563
|
+
```yaml
|
|
564
|
+
- uses: MicroMilo/upstream-radar@v0.33.0
|
|
565
|
+
with:
|
|
566
|
+
fail-on: high
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
An existing `config` wins over auto-detection. If both lockfiles exist, or neither a config nor a supported lockfile exists, the Action stops with a direct message instead of guessing.
|
|
570
|
+
|
|
571
|
+
To review the exact plugin artifact before it enters DSH, add `inspect-package`:
|
|
572
|
+
|
|
573
|
+
```yaml
|
|
574
|
+
- uses: MicroMilo/upstream-radar@v0.33.0
|
|
575
|
+
with:
|
|
576
|
+
inspect-package: dsh-cloudflare-browser-run@0.1.1
|
|
577
|
+
# review is the safe default; use block only when incomplete coverage may pass.
|
|
578
|
+
inspect-fail-on: review
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
This downloads that exact npm tarball, verifies the registry integrity/signature and provenance when available, resolves dependencies with lifecycle scripts disabled, and puts the admission verdict, coverage, findings, and next step in the Job Summary. Write the input as `package@version`; the Action adds the internal `npm:` prefix. It does not install or execute the plugin. The optional `inspect-verdict` output exposes `allow`, `warn`, `review`, or `block` to later workflow steps. An empty finding list with incomplete coverage remains a review result, not a safety certificate.
|
|
582
|
+
|
|
583
|
+
If the repository has a pnpm lockfile but no committed Radar config yet, the Action can generate the config in the same job. See the [copyable pnpm workflow](examples/github-actions/upstream-radar-pnpm.yml):
|
|
584
|
+
|
|
585
|
+
```yaml
|
|
586
|
+
- uses: MicroMilo/upstream-radar@v0.33.0
|
|
587
|
+
with:
|
|
588
|
+
pnpm-lock: pnpm-lock.yaml
|
|
589
|
+
fail-on: high
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
This mode runs `init --pnpm-lock` first and then the same frozen check. `root` is optional when `package.json` is beside the lockfile, and can be supplied for an explicit or non-adjacent workspace root. It never installs the project or executes the plugin; `config` is the output path (default `upstream-radar.config.json`). Leave `pnpm-lock` empty to keep the reviewed-config mode above.
|
|
593
|
+
|
|
594
|
+
Set `npm-lock: package-lock.json` instead for npm projects; `pnpm-lock` and `npm-lock` are mutually exclusive. Both modes infer the root from the adjacent `package.json` unless `root` is supplied.
|
|
595
|
+
See the [copyable npm workflow](examples/github-actions/upstream-radar-npm.yml) for that form.
|
|
260
596
|
|
|
261
597
|
The Action requires the caller to check out the repository first. It does not install the project's dependencies or run their lifecycle scripts; it only reads the committed graph and queries the configured upstream sources. For a fully explicit, lower-level invocation, the equivalent command is:
|
|
262
598
|
|
|
263
599
|
```bash
|
|
264
|
-
pnpm dlx --package=upstream-radar@0.
|
|
600
|
+
pnpm dlx --package=upstream-radar@0.33.0 upstream-radar radar check \
|
|
265
601
|
./upstream-radar.config.json --frozen --state :memory: --fail-on high \
|
|
266
602
|
--fail-on-compatibility breaking --json
|
|
267
603
|
```
|
|
@@ -269,7 +605,7 @@ pnpm dlx --package=upstream-radar@0.32.0 upstream-radar radar check \
|
|
|
269
605
|
To add the optional DSH load matrix for a published plugin, provide an exact npm package and at least two exact DSH versions:
|
|
270
606
|
|
|
271
607
|
```yaml
|
|
272
|
-
- uses: MicroMilo/upstream-radar@v0.
|
|
608
|
+
- uses: MicroMilo/upstream-radar@v0.33.0
|
|
273
609
|
id: radar
|
|
274
610
|
with:
|
|
275
611
|
config: upstream-radar.config.json
|
|
@@ -282,18 +618,20 @@ The Action packs the exact package with `--ignore-scripts`, runs `probe dsh-matr
|
|
|
282
618
|
|
|
283
619
|
For a runnable consumer example using the real [`dsh-cloudflare-browser-run@0.1.1`](examples/github-actions/consumer/upstream-radar.config.json) graph, see the [consumer smoke README](examples/github-actions/consumer/README.md) and its [copyable workflow](examples/github-actions/consumer/upstream-radar.yml).
|
|
284
620
|
|
|
285
|
-
Run the
|
|
621
|
+
Run the consumer path locally from this repository with:
|
|
286
622
|
|
|
287
623
|
```bash
|
|
288
624
|
pnpm run try:consumer
|
|
289
625
|
```
|
|
290
626
|
|
|
627
|
+
This builds the current checkout and runs the same frozen consumer check with the local CLI, so it also works before the next npm version is published. To deliberately verify the public npm artifact instead, run `pnpm run try:consumer:published`; it resolves the package version in `package.json` from npm and should only be used after that version exists publicly.
|
|
628
|
+
|
|
291
629
|
For a local or self-hosted DSH machine, omit `--frozen` so Radar refreshes the selected profile before each cycle. Use `--fail-on` or `--fail-on-compatibility` only with `radar check`, `radar status`, or `radar watch --once`; a long-running watch should continue routing incidents instead of terminating on the first one.
|
|
292
630
|
|
|
293
631
|
## How the loop works
|
|
294
632
|
|
|
295
633
|
1. Read the project inventory and exact installed npm graph.
|
|
296
|
-
2. Query OSV with every installed `name@version` pair.
|
|
634
|
+
2. Query OSV and GitHub Advisory Database with every installed `name@version` pair, then merge matching GHSA/CVE aliases while preserving which source(s) confirmed the result. Native DSH also queries CISA KEV and FIRST EPSS for matched CVEs; CLI and Action users opt in with `--threat-intel` or `threat-intel: true`.
|
|
297
635
|
3. Watch npm releases for the installed plugin and DSH/Cordis packages.
|
|
298
636
|
4. Create or update one durable incident with the exact dependency path.
|
|
299
637
|
5. Persist a constrained analysis task before delivery.
|
|
@@ -370,7 +708,7 @@ which API or Cordis configuration would the upgrade disturb?
|
|
|
370
708
|
what is the least disruptive project-specific action?
|
|
371
709
|
```
|
|
372
710
|
|
|
373
|
-
When one DSH runtime release changes several `@deepseek-ai/dsh-*` packages, Radar keeps each package as an independent state record but combines the same project's notices into one Agent analysis. You get one coherent upgrade question without losing the exact package evidence needed for later resolution. The resulting conclusion is copied back to each still-current incident only after the grouped model response passes the same strict validation.
|
|
711
|
+
When one DSH runtime release changes `@deepseek-ai/dsh`, several `@deepseek-ai/dsh-*` packages, or Cordis packages, Radar keeps each package as an independent state record but combines the same project's notices into one Agent analysis. You get one coherent upgrade question without losing the exact package evidence needed for later resolution. The resulting conclusion is copied back to each still-current incident only after the grouped model response passes the same strict validation.
|
|
374
712
|
|
|
375
713
|
Advisories, release notes, links, package names, and repository strings remain untrusted data. The generated task requires read-only analysis, project evidence, explicit uncertainty, and a fixed [result schema](schemas/analysis-result.schema.json).
|
|
376
714
|
|
|
@@ -378,20 +716,30 @@ Advisories, release notes, links, package names, and repository strings remain u
|
|
|
378
716
|
|
|
379
717
|
- installed DSH `node_modules` graphs and npm lockfile graphs with duplicate versions and bounded dependency paths;
|
|
380
718
|
- DSH shared host-runtime dependency resolution discovered from the running DSH process, with profile and `dsh-host` packages kept distinct in both graphs and alerts;
|
|
719
|
+
- exact `@deepseek-ai/dsh` executable-package evidence, including host-boundary OSV alerts and its own npm compatibility stream;
|
|
720
|
+
- one project-level alert for a shared DSH host-runtime vulnerability, retaining every affected plugin root and exact path instead of sending duplicate per-plugin notices;
|
|
381
721
|
- exact-version OSV vulnerability and malicious-package matching;
|
|
722
|
+
- independent GitHub Advisory Database matching for exact npm versions, with GHSA/CVE alias deduplication, merged fix versions, and source-specific health;
|
|
382
723
|
- npm release monitoring for plugins and DSH/Cordis packages, accepting only a candidate newer than the installed exact version (a regressed `latest` dist-tag is not a breaking update), with public GitHub Release notes attached when an exact candidate tag is available;
|
|
383
724
|
- bounded transitive dependency graph checks for the earliest candidate versions, exact OSV matching for every resolved node, vulnerable path evidence, and explicit incomplete/unavailable coverage;
|
|
384
725
|
- durable incident state with current-task replacement and resolution;
|
|
726
|
+
- a bounded transition history with a local `radar history` audit command;
|
|
385
727
|
- strict DSH result writeback bound to the exact message, session, task, and event, with stale-result rejection;
|
|
386
728
|
- native DSH bundle installation, startup polling, `agent/created` retry, and plugin-source attribution;
|
|
729
|
+
- optional provider-neutral HTTPS webhook delivery for changed events, with endpoint-safe deduplication and retry, project-specific environment routes with independent outboxes, plus direct Feishu/Lark V2 text delivery;
|
|
730
|
+
- delivery-only notification controls for per-project minimum vulnerability severity and timezone-aware quiet hours; critical and malicious-package alerts bypass them, while held DSH tasks and webhook events remain durable;
|
|
731
|
+
- read-only pnpm v6/v9 lockfile graph extraction, including project-root importers and explicit ambiguous peer references;
|
|
732
|
+
- static Radar inventory generation from npm or pnpm lockfiles, followed by the same exact-version OSV check used by the DSH monitor;
|
|
387
733
|
- automatic selection of the only DSH profile with third-party bundles, plus a network-free `radar status` snapshot;
|
|
388
734
|
- commit-friendly `init` output that records the project workspace as `.` by default;
|
|
389
735
|
- a reusable GitHub Action that turns the reviewed graph into a two-step, frozen CI gate;
|
|
736
|
+
- a concise escaped GitHub Job Summary alongside the Action's raw JSON result;
|
|
390
737
|
- an opt-in GitHub Action DSH load matrix for exact published plugin versions and exact DSH versions;
|
|
391
738
|
- a real DSH plugin consumer smoke that runs the published Action against 18 exact package versions;
|
|
392
739
|
- an actionable, network-free `radar status` summary with exact active paths, candidate signals, and next steps;
|
|
393
740
|
- a network-free `doctor` command that checks local DSH registration, overlay/config alignment, state readability, and dependency coverage;
|
|
394
741
|
- compatibility signals for Node.js, peers, exports, entrypoints, bundle paths, dependencies, and version boundaries;
|
|
742
|
+
- top-level remediation evidence that compares active vulnerability ids and aliases with complete candidate graphs, identifying the first non-blocked plugin candidate that removes all checked paths without calling it safe;
|
|
395
743
|
- an opt-in CI gate for confirmed/strong (`breaking`) or all (`any`) active compatibility changes;
|
|
396
744
|
- an offline `benchmark compatibility` command that locks the deterministic rule and gate behavior into six reviewable contracts;
|
|
397
745
|
- disposable `probe dsh-load` and `probe dsh-matrix` commands that check one exact DSH version or a bounded exact-version matrix against one bundle and return `compatible`, `incompatible`, or `unknown`;
|
|
@@ -404,20 +752,25 @@ pnpm dlx --package=upstream-radar@latest upstream-radar scan /path/to/dsh-plugin
|
|
|
404
752
|
pnpm dlx --package=upstream-radar@latest upstream-radar inspect npm:dsh-cloudflare-browser-run@0.1.1 --deep
|
|
405
753
|
```
|
|
406
754
|
|
|
755
|
+
The default text gate exits `2` for `review` or `block`, which is useful when every uncertainty needs a human decision. If CI should fail only on hard blocks while still printing review evidence, add `--fail-on block`.
|
|
756
|
+
|
|
407
757
|
## Current boundaries
|
|
408
758
|
|
|
409
|
-
- `init` discovers the only DSH profile with third-party bundles when `--profile` is omitted; multiple candidates still require an explicit profile. By default it follows the installed DSH `node_modules` tree, so pnpm overrides and local resolution choices are included. `--dsh-patch <path>` writes an explicit DSH overlay so first startup needs no environment variables and preserves an explicitly selected registry.
|
|
410
|
-
-
|
|
759
|
+
- `init` discovers the only DSH profile with third-party bundles when `--profile` is omitted; multiple candidates still require an explicit profile. By default it follows the installed DSH `node_modules` tree, so pnpm overrides and local resolution choices are included. `--dsh-patch <path>` writes an explicit DSH overlay so first startup needs no environment variables and preserves an explicitly selected registry. `graph npm-lock` and `graph pnpm-lock` are separate pre-install/CI collectors; they do not themselves query OSV or create a Radar config.
|
|
760
|
+
- `init --pnpm-lock <path>` or `init --npm-lock <path>` creates a static config without a DSH profile; it reads `package.json` beside the lockfile unless `--root <name>@<version>` is supplied. Follow it with `radar check` or `radar watch` to query OSV. It does not itself start DSH or deliver Agent tasks.
|
|
761
|
+
- If the plugin root is not published to the selected npm registry, a registry `404` skips only that package's release comparison; exact lockfile dependencies and published DSH host packages are still checked. Registry outages, timeouts, malformed responses, and OSV failures remain operational errors.
|
|
762
|
+
- A graph with unresolved required dependency declarations is marked as incomplete coverage; optional packages that are not installed for the current platform remain visible but do not create a false required-dependency alert. Missing `@deepseek-ai/dsh`, `@deepseek-ai/dsh-*`, and Cordis peers are called out separately as unobserved DSH host dependencies because Radar cannot query a version it was never shown. If the DSH executable package itself cannot be read from the active host plane, the core-runtime boundary remains unknown rather than being guessed.
|
|
411
763
|
- Candidate upgrade graphs are resolved only for a bounded earliest prefix. A candidate with an incomplete or unavailable graph is not recommended; later unqueried candidates remain visibly unchecked. Pass `--no-deep-candidates` to opt out of this extra registry work.
|
|
764
|
+
- When an active vulnerability belongs to an installed plugin, candidate remediation is narrower than an upgrade recommendation: `removed` means the complete checked candidate graph has no matching OSV finding, `still-affected` means a matching path remains, and `unknown` means the graph/source is incomplete, truncated, unavailable, or the path comes from the shared DSH host runtime. A remediation candidate still needs DSH project analysis.
|
|
412
765
|
- Compatibility CI gating is opt-in: `--fail-on-compatibility breaking` fails on confirmed or strong incompatibility signals, while `any` fails on every active compatibility event; neither setting claims that a candidate is safe.
|
|
413
766
|
- `probe dsh-load` is intentionally narrower than a security scan: a successful load proves only that the selected DSH profile accepted the bundle configuration. It does not execute plugin actions, compare capabilities, or grant admission to an unreviewed package.
|
|
414
767
|
- `probe dsh-matrix` is intentionally sequential and bounded to eight versions. An incomplete matrix is not green: `unknown` propagates to the aggregate result until every selected DSH version has a reliable load result.
|
|
415
768
|
- `radar check/watch --frozen` intentionally uses the graph committed in the config for CI; it does not prove that the installed DSH profile has not changed. Without `--frozen`, native DSH and CLI polling refresh the selected profile first.
|
|
416
|
-
- `radar status` is a local snapshot only: it does not refresh OSV
|
|
769
|
+
- `radar status` is a local snapshot only: it does not refresh OSV, GitHub Advisory, npm, or GitHub Release data, and it cannot prove that a source is current until a check has completed. It does show whether a captured DSH host plane came from the running process or a profile fallback. Its next steps are guidance, not an automatic upgrade or safety decision.
|
|
417
770
|
- `doctor` checks local wiring only; it cannot prove that a running DSH process has delivered a task to a model or that upstream feeds are current.
|
|
418
|
-
- npm lock graphs are supported;
|
|
419
|
-
- OSV, npm `latest`, and public GitHub Release notes are live sources; changelog, comparison-diff, and migration-guide ingestion are deferred.
|
|
420
|
-
- A failed
|
|
771
|
+
- npm and pnpm lock graphs are supported; Yarn graph extraction is not implemented.
|
|
772
|
+
- OSV, GitHub Advisory Database, npm `latest`, and public GitHub Release notes are live sources; changelog, comparison-diff, and migration-guide ingestion are deferred.
|
|
773
|
+
- A failed advisory-source check preserves confirmed matches and returns a visible source warning; each source's health is durable and routed through DSH after three consecutive failures. When OSV and GitHub Advisory Database disagree about severity or fixed versions, the event keeps both source-labeled claims and makes the conflict explicit instead of silently choosing one. Changed events can be sent to a provider-neutral HTTPS endpoint or directly to a Feishu/Lark V2 bot; there is no separate hosted alerting service.
|
|
421
774
|
- `radar watch` is a CLI monitoring fallback; it does not deliver tasks into DSH by itself.
|
|
422
775
|
- Delivery uses one root Agent as the simple default; when several roots exist, it requires an exact project-workspace match and leaves ambiguous tasks queued instead of guessing.
|
|
423
776
|
- DSH result writeback accepts only the exact six-field JSON contract from the matching model session; it does not infer conclusions from ordinary chat or tool output. The result is advisory and never changes deterministic incident state.
|