dsh-plugin-guide 0.5.0 → 0.5.2
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/SKILL.md +4 -2
- package/docs/boost.md +7 -6
- package/docs/entry.md +17 -13
- package/docs/flow.md +7 -4
- package/docs/levels.md +6 -4
- package/docs/rules.md +21 -17
- package/docs/security.md +89 -38
- package/package.json +1 -1
package/SKILL.md
CHANGED
|
@@ -58,5 +58,7 @@ audit, or market gate. It does not score or rank plugins. When in doubt, link to
|
|
|
58
58
|
the source document and state what was not run.
|
|
59
59
|
|
|
60
60
|
For plugin security — capabilities, credentials, egress, install scripts, and
|
|
61
|
-
supply chain — read `docs/security.md`.
|
|
62
|
-
|
|
61
|
+
supply chain — read `docs/security.md`. The security scope is static and shipped
|
|
62
|
+
in `dsh-standards` 1.6.0+; `DSC-15`/`DSC-16`/`DSC-17` can block only under
|
|
63
|
+
`--scope security`, `DSC-21` is WARN-only, and runtime security needs a sandbox,
|
|
64
|
+
not a checker.
|
package/docs/boost.md
CHANGED
|
@@ -95,12 +95,13 @@ pitfalls”), record it as a WARN or a note. Do not invent a number.
|
|
|
95
95
|
|
|
96
96
|
BOOST measures Cordis practice, not security. A reversible effect or a seam is
|
|
97
97
|
good engineering, and it reduces blast radius, but it is not a sandbox: the
|
|
98
|
-
plugin still shares the host process, the user, and the network. The
|
|
99
|
-
`DSC-15`–`DSC-22` checks
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
plugin still shares the host process, the user, and the network. The static
|
|
99
|
+
`DSC-15`–`DSC-22` checks run in a separate `--scope security` (1.6.0+); outside
|
|
100
|
+
it they are capped to WARN in the separate `security` block. `DSC-15`/`16`/`17`
|
|
101
|
+
can block only under that scope, and `DSC-21` is WARN-only. They never change a
|
|
102
|
+
BOOST result and none of them proves a plugin safe. Runtime questions — actual
|
|
103
|
+
egress, file reads, prompt corruption — require a sandbox with a network policy
|
|
104
|
+
and capture, not an evidence card. Keep the security claim `not-run` instead of
|
|
104
105
|
borrowing BOOST evidence for it. See [security.md](security.md#scope).
|
|
105
106
|
|
|
106
107
|
## Run the audit
|
package/docs/entry.md
CHANGED
|
@@ -311,27 +311,31 @@ export function apply(ctx) {
|
|
|
311
311
|
## Security checks (DSC-15 to DSC-22)
|
|
312
312
|
|
|
313
313
|
ENTRY is a compatibility gate; it does not answer "is this safe to install". The
|
|
314
|
-
|
|
314
|
+
static security scope ships in `dsh-standards` 1.6.0+ and evaluates eight
|
|
315
|
+
checks; with `--scope security` the report's `checks[]` carries all 22
|
|
316
|
+
(`DSC-01`–`DSC-14` plus `DSC-15`–`DSC-22`).
|
|
315
317
|
|
|
316
318
|
| Check | What it looks for | Verdict in `--scope security` |
|
|
317
319
|
|---|---|---|
|
|
318
|
-
| `DSC-15` | `preinstall`/`install`/`postinstall`/`prepare` that download, decode, or execute | blocking |
|
|
319
|
-
| `DSC-16` | `eval`, `new Function`, `vm`, `module._compile`, `process.binding` | blocking |
|
|
320
|
+
| `DSC-15` | `preinstall`/`install`/`postinstall`/`prepare` that download, decode, or execute (command string and referenced in-package script body, ≤512 KB) | blocking |
|
|
321
|
+
| `DSC-16` | `eval`, `new Function`, `vm`, `module._compile`, `process.binding`; bare `child_process` is WARN in 1.6.1 | blocking |
|
|
320
322
|
| `DSC-17` | reads of `~/.ssh`, `~/.aws`, `.npmrc`, `.netrc`, or credential backing files | blocking |
|
|
321
323
|
| `DSC-18` | non-https, userinfo, bare-IP, webhook/paste/tunnel egress targets | WARN (clue) |
|
|
322
324
|
| `DSC-19` | minified blobs, large base64 blocks, wasm/native without source | advisory |
|
|
323
|
-
| `DSC-20` | tool/web text flowing into the system prompt without a boundary | advisory (runtime
|
|
324
|
-
| `DSC-21` | typosquat names, fake scopes, unpinned or script-bearing dependencies | blocking
|
|
325
|
+
| `DSC-20` | tool/web text flowing into the system prompt without a boundary | advisory (static v1 + runtime hook v2) |
|
|
326
|
+
| `DSC-21` | typosquat names, fake scopes, unpinned or script-bearing dependencies | mandatory but **WARN-only, never blocking** (listing included) |
|
|
325
327
|
| `DSC-22` | `dist.integrity`, signatures, provenance attestations | advisory |
|
|
326
328
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
329
|
+
`--scope security` is released in 1.6.0+; 1.5.x and earlier exit `3` for the
|
|
330
|
+
unknown scope. Outside that scope the eight are not in `checks[]`; a security
|
|
331
|
+
`FAIL` is capped to WARN in the separate `security` block, never enters
|
|
332
|
+
`buckets.blocking`, and cannot change an ENTRY verdict. Only `15`/`16`/`17` can
|
|
333
|
+
block (and only under `--scope security`); `21` never blocks; `18`/`19`/`20`/`22`
|
|
334
|
+
are advice. `DSC-16` subprocess FAIL is scoped to 1.6.2; 1.6.1 keeps a bare
|
|
335
|
+
`child_process` import at WARN.
|
|
332
336
|
|
|
333
337
|
```sh
|
|
334
|
-
#
|
|
338
|
+
# 1.6.0+; exits 3 only on 1.5.x and earlier
|
|
335
339
|
npx dsh-standards ./my-plugin --scope security --format json
|
|
336
340
|
```
|
|
337
341
|
|
|
@@ -343,6 +347,6 @@ and neither is a `DSC-11` PASS.
|
|
|
343
347
|
## What ENTRY does not do
|
|
344
348
|
|
|
345
349
|
It is not a security audit, sandbox, full contract audit, market gate, score, or
|
|
346
|
-
ranking. Those are separate concerns; do not borrow their authority. The
|
|
347
|
-
|
|
350
|
+
ranking. Those are separate concerns; do not borrow their authority. The static
|
|
351
|
+
`DSC-15`–`DSC-22` checks are a separate security scope, covered in
|
|
348
352
|
[security.md](security.md), not part of the ENTRY verdict.
|
package/docs/flow.md
CHANGED
|
@@ -205,10 +205,13 @@ example `J2.toggle → 32-DSH-FLOW #R2`).
|
|
|
205
205
|
## Security boundary
|
|
206
206
|
|
|
207
207
|
J5 checks that permissions are declared consistently; it is static preflight,
|
|
208
|
-
not a security test. The
|
|
209
|
-
`--scope security
|
|
210
|
-
turn a FLOW journey into a security pass. Outside that
|
|
211
|
-
is advisory: it is capped
|
|
208
|
+
not a security test. The static `DSC-15`–`DSC-22` checks live behind a separate
|
|
209
|
+
`--scope security`, shipped in `dsh-standards` 1.6.0+ (1.5.x and earlier exit
|
|
210
|
+
`3`), and they never turn a FLOW journey into a security pass. Outside that
|
|
211
|
+
scope a security finding is advisory: it is capped to WARN in the separate
|
|
212
|
+
`security` block, never enters `buckets.blocking`, and cannot change the FLOW
|
|
213
|
+
verdict. Under `--scope security` only `DSC-15`/`DSC-16`/`DSC-17` can block;
|
|
214
|
+
`DSC-21` is WARN-only.
|
|
212
215
|
|
|
213
216
|
Static checks also cannot observe what a plugin does at runtime — which URLs it
|
|
214
217
|
reaches, which files it reads, or whether a prompt was corrupted. Those answers
|
package/docs/levels.md
CHANGED
|
@@ -76,10 +76,12 @@ The card fields are in
|
|
|
76
76
|
|
|
77
77
|
## Security is not a fourth layer
|
|
78
78
|
|
|
79
|
-
Security checks are a **scope**, not a level, and they
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
Security checks are a **scope**, not a level, and they ship in `dsh-standards`
|
|
80
|
+
1.6.0+ (1.5.x and earlier exit `3` for the unknown scope): `DSC-15`–`DSC-22`
|
|
81
|
+
sit behind `--scope security`. They never change an ENTRY, FLOW, or BOOST
|
|
82
|
+
verdict. Outside that scope a security `FAIL` is capped to WARN in the separate
|
|
83
|
+
`security` block and does not enter `buckets.blocking`; under it only
|
|
84
|
+
`DSC-15`/`16`/`17` can block, and `DSC-21` is WARN-only.
|
|
83
85
|
|
|
84
86
|
- Static checks only match known source shapes; they cannot see runtime egress,
|
|
85
87
|
file reads, or prompt corruption. Runtime security needs a sandbox with a
|
package/docs/rules.md
CHANGED
|
@@ -22,8 +22,10 @@ incomplete/not-run, `3` usage error. `WARN` is not a clean pass and
|
|
|
22
22
|
The JSON report also carries a sibling `advice[]` array: one entry per live
|
|
23
23
|
detail, with `title`, `why`, `fix`, `docsUrl`, `severity`, and `evidence`. It is
|
|
24
24
|
additive and never changes the verdict (turn it off with `--no-advice`). The
|
|
25
|
-
`docsUrl` follows the checker's `DOCS_BASE
|
|
26
|
-
|
|
25
|
+
`docsUrl` follows the checker's `DOCS_BASE`: 1.6.1 pins `v0.4.6`, and the 1.6.2
|
|
26
|
+
release moves it to guide `v0.5.0`. The `docs/security.md` anchors used by the
|
|
27
|
+
`C-15`–`C-22` advice exist in 0.5.0; if a link points at an older page, this
|
|
28
|
+
table is the current mapping.
|
|
27
29
|
|
|
28
30
|
<a id="scope-matrix"></a>
|
|
29
31
|
## Which checks run in which scope
|
|
@@ -35,7 +37,7 @@ at an older page, this table is the current mapping.
|
|
|
35
37
|
| `--scope entry --entry-claim static` | 01, 02, 11, 12, 13 (+ 03 for listing) | 04–09 are attempted and printed (usually `ERROR`/`NA`), 14 is `NA`; a `DSC-11`/`DSC-12`/`DSC-13` FAIL is downgraded to `WARN` |
|
|
36
38
|
| `--scope entry --entry-claim runtime` | + 14 | 14 carries the runtime verdict, not 04–09 |
|
|
37
39
|
| `--scope mvp` | 01, 02, 04–09 | the MVP subset, labelled `MVP-13` |
|
|
38
|
-
| `--scope security` (
|
|
40
|
+
| `--scope security` (1.6.0+) | + 15, 16, 17, 21; 18/19/20/22 advisory | `checks[]` becomes 22 (14 + 8); DS-C 01–14 are unchanged and the report gains an additive `security` block. `15`/`16`/`17` blocking, `21` mandatory but WARN-only |
|
|
39
41
|
|
|
40
42
|
<a id="table"></a>
|
|
41
43
|
## The check table
|
|
@@ -56,24 +58,26 @@ at an older page, this table is the current mapping.
|
|
|
56
58
|
| **DSC-12** | C-12 credentials + seams | Blocking (ds-c); `WARN` in ENTRY. | Read credentials through `ctx.credentials`, declare `credentials:list` for `listRecords()` and `credentials:provider` for a provider, and never read the backing file. | [entry.md § credentials and seams](entry.md#credentials-and-seams) |
|
|
57
59
|
| **DSC-13** | C-13 labels + mirror | Blocking (ds-c); `WARN` in ENTRY, advisory as a WARN. | Use only the five labels, add the label each capability requires, point `dsh.upstream` at an https URL that is not this package **and** add `mirror`, and drop endorsement words. | [entry.md § labels and mirror](entry.md#labels-and-mirror) |
|
|
58
60
|
| **DSC-14** | C-14 entry run | Blocking only for a runtime claim (`--scope entry`). | Supply the real host: `--host` for a bundle (G0–G3) or `--runtime` for a plugin (L1); a client or preset cannot claim runtime. | [entry.md § runtime surface](entry.md#runtime-surface) |
|
|
59
|
-
| **DSC-15** | C-15 lifecycle scripts
|
|
60
|
-
| **DSC-16** | C-16 dynamic execution
|
|
61
|
-
| **DSC-17** | C-17 sensitive files
|
|
62
|
-
| **DSC-18** | C-18 egress endpoints
|
|
63
|
-
| **DSC-19** | C-19 obfuscation/binary
|
|
64
|
-
| **DSC-20** | C-20 prompt injection
|
|
65
|
-
| **DSC-21** | C-21 supply chain
|
|
66
|
-
| **DSC-22** | C-22 provenance/integrity
|
|
61
|
+
| **DSC-15** | C-15 lifecycle scripts | **Blocking only under `--scope security`** (1.6.0+); not run in the default scopes. It reads the referenced in-package script body (≤512 KB) as well as the command string. | Ship no `preinstall`/`install`/`postinstall`/`prepare`; if one is unavoidable, no download-to-shell, `base64 -d`, or `node -e`. | [security.md § author 4](security.md#author-files) |
|
|
62
|
+
| **DSC-16** | C-16 dynamic execution | **Blocking only under `--scope security`**. `eval`/`Function`/`vm`/`_compile`/`process.binding` FAIL; a bare `child_process` import is WARN in 1.6.1, and the dangerous-subprocess FAIL is 1.6.2. | Remove `eval`, `new Function`, `vm.runIn*`, `module._compile`, and `process.binding`; dynamic `import()` takes a static path only. | [security.md § author 4](security.md#author-files) |
|
|
63
|
+
| **DSC-17** | C-17 sensitive files | **Blocking only under `--scope security`**. | Read credentials through `ctx.credentials`; never read `~/.ssh`, `~/.aws`, `.npmrc`, `.netrc`, or a credential backing file. | [security.md § author 2](security.md#author-credentials) |
|
|
64
|
+
| **DSC-18** | C-18 egress endpoints | **WARN** under `--scope security` (clue, not blocking). | Use a constant `https` allowlist, `redirect: 'manual'`, no credentials across origins, and disclose third-party endpoints. | [security.md § author 3](security.md#author-egress) |
|
|
65
|
+
| **DSC-19** | C-19 obfuscation/binary | **Advisory** under `--scope security`. | No minified blobs or binary-only code; ship wasm/native with source, build method, and `sha256`. | [security.md § author 4](security.md#author-files) |
|
|
66
|
+
| **DSC-20** | C-20 prompt injection | **Advisory**: static v1 (external text into `systemPrompt`, instruction-like literals) plus a runtime hook in v2; never blocking. | Treat tool/web/file/session text as untrusted, validate `output.schema`, and wrap external text before it reaches a prompt. | [security.md § author 5](security.md#author-prompt) |
|
|
67
|
+
| **DSC-21** | C-21 supply chain | **Mandatory under `--scope security`, but WARN-only and never blocking** (listing included). | Commit the lockfile, pin dependencies, reject typosquat/lookalike scopes, and treat an unpinned or script-bearing dependency as `not-run`. | [security.md § author 6](security.md#author-publish) |
|
|
68
|
+
| **DSC-22** | C-22 provenance/integrity | **Advisory**, never blocking. | Publish with provenance/attestations; `dist.integrity` only binds the tarball to the registry, not the code to a source. | [security.md § author 6](security.md#author-publish) |
|
|
67
69
|
|
|
68
70
|
`DSC-14` has no `C-14` in the clause text; it is the ENTRY run-set gate
|
|
69
71
|
(`ENT-14` in 31-DSH-ENTRY). Treat it as "did the thing actually start".
|
|
70
72
|
|
|
71
|
-
`DSC-15`–`DSC-22`
|
|
72
|
-
`
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
`DSC-15`–`DSC-22` shipped in `dsh-standards` 1.6.0; 1.5.x and earlier treat
|
|
74
|
+
`--scope security` as an unknown scope and exit `3`. Only `--scope security`
|
|
75
|
+
makes `15`/`16`/`17` blocking; `21` is mandatory but WARN-only and never blocks
|
|
76
|
+
(listing included). In every other scope the eight stay out of `checks[]`; their
|
|
77
|
+
FAILs are capped to WARN in the separate `security` block and never change the
|
|
78
|
+
DS-C verdict. They are static evidence: three can fail mechanically, one only
|
|
79
|
+
warns, four only return clues, and no PASS proves a plugin safe. The
|
|
80
|
+
author/user/market checklists are in [security.md](security.md).
|
|
77
81
|
|
|
78
82
|
<a id="warn"></a>
|
|
79
83
|
## Two things that look like passes but are not
|
package/docs/security.md
CHANGED
|
@@ -8,17 +8,26 @@
|
|
|
8
8
|
> files, spawn processes, reach the network, and read the credential store
|
|
9
9
|
> whether or not it declares that it does.
|
|
10
10
|
|
|
11
|
-
`DSC-15`–`DSC-22` are **
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
`DSC-15`–`DSC-22` are the **static security checks** shipped in
|
|
12
|
+
`dsh-standards` **1.6.0**; `--scope security` is a released flag
|
|
13
|
+
from 1.6.0 on (1.5.x and earlier treat `security` as an unknown scope and exit
|
|
14
|
+
`3`; 1.6.1 supports it).
|
|
15
|
+
With `--scope security`, `checks[]` carries all **22** checks (`DSC-01`–`DSC-14`
|
|
16
|
+
plus `DSC-15`–`DSC-22`); the default `ds-c` run still carries 14 and reports the
|
|
17
|
+
eight in the additive `security` block. Three can block (`15`, `16`, `17`), one
|
|
18
|
+
is mandatory but **WARN-only and never blocks** (`21`, listing included), and
|
|
19
|
+
four only produce clues (`18`, `19`, `20`, `22`); all eight reduce risk, and
|
|
20
|
+
**none of them proves a plugin is safe**.
|
|
21
|
+
|
|
22
|
+
The `security` block is a **separate view**, a scope, not a fourth layer. In the default
|
|
23
|
+
scope a security `FAIL` is capped to `WARN` inside `security.checks[]`; it is
|
|
24
|
+
listed only in `security.warn[]` (`security.blocking[]` stays empty), does not
|
|
25
|
+
enter `buckets.blocking` or `conclusion.headline`, and changes neither `status`
|
|
26
|
+
nor the exit code. Only `--scope security` puts `15`/`16`/`17` into `checks[]`,
|
|
27
|
+
where a `FAIL` enters `buckets.blocking`, the headline, `status=fail` and exit
|
|
28
|
+
`1`. `DSC-21` never FAILs, so it never blocks in either profile. Read the scope,
|
|
29
|
+
and read the block's `checks[]`, not just its four arrays — see
|
|
30
|
+
[Reading the `security` block](#security-block).
|
|
22
31
|
|
|
23
32
|
## The trust boundary in one table
|
|
24
33
|
|
|
@@ -99,9 +108,10 @@ forward a token "just in case".
|
|
|
99
108
|
### 3. Egress endpoints (DSC-18)
|
|
100
109
|
|
|
101
110
|
Use a constant allowlist of exact hostnames and `https` only. Never fetch a URL
|
|
102
|
-
that came from a model, a tool result, or a user message;
|
|
103
|
-
|
|
104
|
-
|
|
111
|
+
that came from a model, a tool result, or a user message; use
|
|
112
|
+
`redirect: 'manual'` and refuse a redirect unless every `Location` hop passes the
|
|
113
|
+
same allowlist (bounded), and never send a credential across an origin. Disclose
|
|
114
|
+
third-party endpoints, what is retained, and whether session text is forwarded.
|
|
105
115
|
|
|
106
116
|
```ts
|
|
107
117
|
const ALLOW = new Set(['api.example.com'])
|
|
@@ -174,9 +184,10 @@ not shell it, and do not let it choose an arbitrary URL.
|
|
|
174
184
|
```ts
|
|
175
185
|
import { randomUUID } from 'node:crypto'
|
|
176
186
|
|
|
177
|
-
const
|
|
178
|
-
const
|
|
179
|
-
`<untrusted-${id}>\n${JSON.stringify(s).replaceAll('<', '\\u003c')}\n</untrusted-${id}>`
|
|
187
|
+
const wrap = (s: string) => {
|
|
188
|
+
const id = randomUUID() // per call, so reused wrappers get a fresh boundary
|
|
189
|
+
return `<untrusted-${id}>\n${JSON.stringify(s).replaceAll('<', '\\u003c')}\n</untrusted-${id}>`
|
|
190
|
+
}
|
|
180
191
|
```
|
|
181
192
|
|
|
182
193
|
Rendering is part of the same boundary: use `textContent`/React escaping, never
|
|
@@ -238,10 +249,13 @@ Include the version, DSH version, impact, and a minimal repro. First response wi
|
|
|
238
249
|
## User guide
|
|
239
250
|
|
|
240
251
|
The checks tell you what a package declares; they do not tell you what it does.
|
|
241
|
-
Assume a loaded plugin can do anything the user can. The
|
|
242
|
-
touch this path are `DSC-15` (lifecycle scripts), `DSC-
|
|
243
|
-
|
|
244
|
-
|
|
252
|
+
Assume a loaded plugin can do anything the user can. The static checks that
|
|
253
|
+
touch this path are `DSC-15` (lifecycle scripts), `DSC-17` (credential files),
|
|
254
|
+
`DSC-21` (typosquat/lookalike names, WARN-only) and `DSC-22`
|
|
255
|
+
(integrity/provenance) before install; `DSC-18` only ever produces a static clue
|
|
256
|
+
about egress. Under `--scope security`, `DSC-15`/`DSC-16`/`DSC-17` can block;
|
|
257
|
+
outside it every security finding is capped to WARN in the separate `security`
|
|
258
|
+
block.
|
|
245
259
|
|
|
246
260
|
**Before installing.** Read the manifest: `dsh.capabilities`, `dsh.labels`,
|
|
247
261
|
`scripts`, `files`, `engines.dsh`, and the source pin. Then look at the source
|
|
@@ -255,16 +269,20 @@ clearance.
|
|
|
255
269
|
|
|
256
270
|
```sh
|
|
257
271
|
npm view pkg@1.2.3 version dsh scripts dist.integrity dist.signatures dist.attestations repository.url time.modified --json
|
|
272
|
+
|
|
273
|
+
# the released static security scope (1.6.0+; does not run the plugin)
|
|
274
|
+
npx dsh-standards check ./pkg --scope security --json
|
|
258
275
|
```
|
|
259
276
|
|
|
260
277
|
**During install.** Start from a throwaway profile (`dsh plugin --profile lab
|
|
261
278
|
...` initializes it), add `--ignore-scripts`, and understand that it stops
|
|
262
279
|
install scripts only, not the code the host loads. The GUI build approval runs
|
|
263
|
-
a script with your permissions
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
280
|
+
a script with your permissions, but the approval list shows only the package
|
|
281
|
+
name, not the script body: inspect the referenced script first (`npm pack`, then
|
|
282
|
+
read `scripts/*`). The CLI inherits your whole environment, so launch it from a
|
|
283
|
+
clean shell with no tokens. A new session defaults to `workspace-write` + `ask`;
|
|
284
|
+
do not switch to `danger-full-access` with `never`.
|
|
285
|
+
`DSH_PERMISSION_MODE=read-only` constrains tool subprocesses, not plugins.
|
|
268
286
|
|
|
269
287
|
```sh
|
|
270
288
|
dsh plugin --profile lab add pkg@1.2.3 --ignore-scripts
|
|
@@ -303,12 +321,21 @@ read from the manifest. Missing data is never a pass. State that static checks
|
|
|
303
321
|
cover known patterns and are not a security audit. The checker can import the
|
|
304
322
|
plugin, so do not run it against an untrusted package on a host you care about.
|
|
305
323
|
|
|
306
|
-
**Disputes and delisting.** Hard-reject only four cases
|
|
307
|
-
|
|
308
|
-
security
|
|
309
|
-
finding attached.
|
|
310
|
-
|
|
311
|
-
|
|
324
|
+
**Disputes and delisting.** Hard-reject only four cases, each with its reason
|
|
325
|
+
code: `not-a-plugin`, `source-not-pinnable`, `impersonation-or-infringement`,
|
|
326
|
+
and `security-hold` (manual review with an appeal). List everything else with
|
|
327
|
+
the finding attached. Market actions are not label fields: every listing and
|
|
328
|
+
rejection is one row of `market-actions.jsonl`
|
|
329
|
+
(`ts/subject/action/reasonCode/evidenceUrls/actor/signature/appealUrl`); a
|
|
330
|
+
rejection carries one of the four reason codes above, and the authoritative
|
|
331
|
+
fields, acting roles, and appeal link are in
|
|
332
|
+
`00-live/market-contract/DECISION-TABLE.md` §2 and
|
|
333
|
+
`00-live/market-contract/CONTRACT.md` §7. The author can withdraw at any time
|
|
334
|
+
(`lifecycle` becomes `withdrawn` at `withdrawnAt`); a 90-day expiry counts from
|
|
335
|
+
the record's `checkedAt` (rev1 records: from `generatedAt` to `expiresAt`) and
|
|
336
|
+
removes only the label; a project-initiated withdrawal must carry a reason and
|
|
337
|
+
evidence and opens a 14-day appeal window counted from `withdrawnAt` (shown as
|
|
338
|
+
`under-review` while open). Keep record history for at least two years.
|
|
312
339
|
|
|
313
340
|
**Wording ban.** Never write "secure", "certified", "official", "audited", or
|
|
314
341
|
"100% risk-free", and never imply certification with a shield or a checkmark.
|
|
@@ -316,7 +343,7 @@ Use the fixed disclaimer: "unofficial · not certified · not security-audited
|
|
|
316
343
|
not endorsed · no warranty".
|
|
317
344
|
|
|
318
345
|
<a id="template"></a>
|
|
319
|
-
## Template: minimal
|
|
346
|
+
## Template: minimal low-risk defaults
|
|
320
347
|
|
|
321
348
|
The smallest honest starting point is: no lifecycle scripts, empty
|
|
322
349
|
capabilities, a permissions disclosure marked draft, and a `SECURITY.md` in the
|
|
@@ -361,13 +388,37 @@ stale empty array hides the very `C-11.2` failure the check is for.
|
|
|
361
388
|
|
|
362
389
|
| Scope | What runs | Verdict |
|
|
363
390
|
|---|---|---|
|
|
364
|
-
| `--scope ds-c` (default) / `entry` / `flow` / `boost` | DSC-01
|
|
365
|
-
| `--scope security` (
|
|
391
|
+
| `--scope ds-c` (default) / `entry` / `flow` / `boost` | `DSC-01`–`DSC-14`: only the scope's mandatory subset counts (`DSC-10` is advisory; `03`/`14` can be NA/not-run). `DSC-15`–`DSC-22` run in the separate `security` block (`scope=advisory`) | a security `FAIL` is capped to `WARN` in that block; it is not in `checks[]`/`buckets.blocking` and cannot change `status`/exit |
|
|
392
|
+
| `--scope security` (1.6.0+) | all 22 checks in `checks[]`: DSC-01–14 plus DSC-15–22 | `15`/`16`/`17` blocking (FAIL → exit 1); `21` mandatory **WARN-only**, never blocking (listing too); `18` WARN; `19`/`20`/`22` advisory |
|
|
366
393
|
| runtime observation | sandbox with a network policy + capture | the only evidence that code actually egressed, read a file, or rewrote a prompt |
|
|
367
394
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
395
|
+
`DSC-16` blocks on `eval`/`new Function`/`vm`/`module._compile`/`process.binding`.
|
|
396
|
+
A bare `child_process` import is WARN in 1.6.1; the FAIL for a statically
|
|
397
|
+
dangerous subprocess command is scoped to 1.6.2.
|
|
398
|
+
|
|
399
|
+
The JSON report carries an additive top-level `security` block; the DS-C verdicts
|
|
400
|
+
stay unchanged. A PASS in that block means "no blocking FAIL, no WARN, and the
|
|
401
|
+
mandatory `15`/`16`/`17`/`21` all produced a result", not "safe".
|
|
402
|
+
|
|
403
|
+
<a id="security-block"></a>
|
|
404
|
+
### Reading the `security` block
|
|
405
|
+
|
|
406
|
+
- `conclusion.headline`'s `blocking N` and `buckets.blocking[]` are
|
|
407
|
+
**report-level**: they only count `checks[]` FAILs. `security.blocking[]` is
|
|
408
|
+
the block's own list and can only ever hold `DSC-15`/`DSC-16`/`DSC-17`.
|
|
409
|
+
- **Default scope:** the eight run in `security.checks[]` with
|
|
410
|
+
`security.scope="advisory"`. A `FAIL` is capped to `WARN` (listed in
|
|
411
|
+
`security.warn[]`), `security.blocking=[]`, no security row appears in
|
|
412
|
+
`buckets.blocking`, the headline is unchanged, and `status`/exit stay the same.
|
|
413
|
+
- **`--scope security`:** the eight join `checks[]`. A `15`/`16`/`17` FAIL →
|
|
414
|
+
`security.blocking=[...]` plus `buckets.blocking=[...]`, headline `blocking N`,
|
|
415
|
+
`status=fail`, exit `1`. `DSC-21` findings are WARN-only and never block;
|
|
416
|
+
`18`/`19`/`20`/`22` are advisory. A mandatory check with no result makes
|
|
417
|
+
`security.status=incomplete`.
|
|
418
|
+
- **Partial:** 1.6.1 has no `security.partial[]`. A partly-run check is
|
|
419
|
+
`security.checks[].coverage === "partial"` (and top-level `coverage.partial` /
|
|
420
|
+
`buckets.partial`); `security.notRun[]` only carries `NA`/`ERROR`/full
|
|
421
|
+
`not-run`. Do not read the four arrays as complete coverage.
|
|
371
422
|
|
|
372
423
|
<a id="limits"></a>
|
|
373
424
|
## What no static check can tell you
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-guide",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "A practical guide to DSH plugin quality: ENTRY checks, FLOW checks, and BOOST guidance. Community guide; not official, not a certification, not a ranking.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|