dsh-standards 1.6.0 → 1.6.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.
Files changed (64) hide show
  1. package/40-checker/fixtures/security/sec11-cred-declared/index.mjs +3 -0
  2. package/40-checker/fixtures/security/sec11-cred-declared/package.json +21 -0
  3. package/40-checker/fixtures/security/sec11-cred-list/index.mjs +3 -0
  4. package/40-checker/fixtures/security/sec11-cred-list/package.json +21 -0
  5. package/40-checker/fixtures/security/sec11-cred-undeclared/index.mjs +3 -0
  6. package/40-checker/fixtures/security/sec11-cred-undeclared/package.json +19 -0
  7. package/40-checker/fixtures/security/sec15-install-cred/index.mjs +7 -0
  8. package/40-checker/fixtures/security/sec15-install-cred/install.js +8 -0
  9. package/40-checker/fixtures/security/sec15-install-cred/package.json +22 -0
  10. package/40-checker/fixtures/security/sec15-install-curl/index.mjs +7 -0
  11. package/40-checker/fixtures/security/sec15-install-curl/package.json +22 -0
  12. package/40-checker/fixtures/security/sec15-install-curl/scripts/install.sh +4 -0
  13. package/40-checker/fixtures/security/sec15-install-danger/index.mjs +7 -0
  14. package/40-checker/fixtures/security/sec15-install-danger/install.js +5 -0
  15. package/40-checker/fixtures/security/sec15-install-danger/package.json +22 -0
  16. package/40-checker/fixtures/security/sec15-install-download-safe/index.js +2 -0
  17. package/40-checker/fixtures/security/sec15-install-download-safe/package.json +22 -0
  18. package/40-checker/fixtures/security/sec15-install-download-safe/scripts/install.js +11 -0
  19. package/40-checker/fixtures/security/sec15-install-download-safe/scripts/local-util.cjs +1 -0
  20. package/40-checker/fixtures/security/sec15-install-dynamic/index.js +2 -0
  21. package/40-checker/fixtures/security/sec15-install-dynamic/package.json +22 -0
  22. package/40-checker/fixtures/security/sec15-install-dynamic/scripts/install.js +11 -0
  23. package/40-checker/fixtures/security/sec15-install-safe/index.mjs +7 -0
  24. package/40-checker/fixtures/security/sec15-install-safe/install.js +5 -0
  25. package/40-checker/fixtures/security/sec15-install-safe/package.json +22 -0
  26. package/40-checker/fixtures/security/sec16-base64-clean/index.mjs +4 -0
  27. package/40-checker/fixtures/security/sec16-base64-clean/package.json +19 -0
  28. package/40-checker/fixtures/security/sec16-base64-eval/index.mjs +4 -0
  29. package/40-checker/fixtures/security/sec16-base64-eval/package.json +19 -0
  30. package/40-checker/fixtures/security/sec16-exec-curl/index.mjs +4 -0
  31. package/40-checker/fixtures/security/sec16-exec-curl/package.json +19 -0
  32. package/40-checker/fixtures/security/sec16-import-only/index.mjs +4 -0
  33. package/40-checker/fixtures/security/sec16-import-only/package.json +19 -0
  34. package/40-checker/fixtures/security/sec16-spawn-shell/index.mjs +4 -0
  35. package/40-checker/fixtures/security/sec16-spawn-shell/package.json +19 -0
  36. package/40-checker/fixtures/security/sec16-subprocess-safe/index.mjs +4 -0
  37. package/40-checker/fixtures/security/sec16-subprocess-safe/package.json +19 -0
  38. package/40-checker/fixtures/security/sec17-alias-clean/data.txt +1 -0
  39. package/40-checker/fixtures/security/sec17-alias-clean/index.mjs +5 -0
  40. package/40-checker/fixtures/security/sec17-alias-clean/package.json +19 -0
  41. package/40-checker/fixtures/security/sec17-alias-read/index.mjs +7 -0
  42. package/40-checker/fixtures/security/sec17-alias-read/package.json +19 -0
  43. package/40-checker/fixtures/security/sec17-base64-path/index.mjs +11 -0
  44. package/40-checker/fixtures/security/sec17-base64-path/package.json +19 -0
  45. package/40-checker/fixtures/security/sec17-base64-path-clean/data/config.json +1 -0
  46. package/40-checker/fixtures/security/sec17-base64-path-clean/index.mjs +5 -0
  47. package/40-checker/fixtures/security/sec17-base64-path-clean/package.json +19 -0
  48. package/40-checker/fixtures/security/sec17-cred-exfil/index.mjs +22 -0
  49. package/40-checker/fixtures/security/sec17-cred-exfil/package.json +19 -0
  50. package/40-checker/fixtures/security/sec17-home-env/index.js +8 -0
  51. package/40-checker/fixtures/security/sec17-home-env/package.json +19 -0
  52. package/40-checker/fixtures/security/sec17-home-env-clean/index.mjs +6 -0
  53. package/40-checker/fixtures/security/sec17-home-env-clean/package.json +19 -0
  54. package/40-checker/fixtures/security/sec18-split-fetch/index.mjs +5 -0
  55. package/40-checker/fixtures/security/sec18-split-fetch/package.json +19 -0
  56. package/40-checker/fixtures/security/sec18-split-fetch-clean/index.mjs +4 -0
  57. package/40-checker/fixtures/security/sec18-split-fetch-clean/package.json +24 -0
  58. package/40-checker/src/declarations.mjs +6 -1
  59. package/40-checker/src/remediation.mjs +1 -1
  60. package/40-checker/src/security.mjs +568 -44
  61. package/CHANGELOG.md +23 -0
  62. package/docs/coverage.md +17 -7
  63. package/package.json +1 -1
  64. package/spec/coverage-contract.md +10 -7
package/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ ## 1.6.2 — 2026-11-07
2
+
3
+ ### Fixed
4
+
5
+ - 红队加固:`process.env.HOME` 拼接凭据路径、`exec/spawn` 危险命令、安装脚本「下载后动态 require」、一层 read 别名、base64+eval、拆分 fetch 均能命中;恶意变体阻断从 1/11 升到 7/11,负对照误报 0/12。
6
+ - `ctx.credentials` 触发补入 C-11.2,声明 credentials:read 不再反报 C-11.5。
7
+ - 文档口径:C-15 读脚本正文、C-17 readdir 可判、C-21 WARN-only、coverage 12/14、security 块 partial/读法、SECURITY 支持版本、advice 链接改 guide 0.5.0(security.md)。
8
+ - 10 个真实包 DSC-15/17 FAIL 0/10。
9
+
10
+ ### Verified
11
+
12
+ - `npm test` 282/282。
13
+ ## 1.6.1 — 2026-11-07
14
+
15
+ ### Fixed
16
+
17
+ - DSC-17 现在识别 `os.homedir()`/`HOME`/`DSH_HOME` 与 `.dsh`/`.ssh`/`credentials`/`tokens` 的组合,并对“读取后外发”判 FAIL;恶意样本 s2 由 pass 改为 fail/exit 1。
18
+ - DSC-15 现在读取 `scripts` 引用的本地 JS/SH 内容(限包内、≤512 KB),`curl|sh`、`base64 -d`、`eval`、读凭据、下载执行判 FAIL;普通构建脚本仍 WARN。
19
+ - 10 个真实包回归:DSC-17 0 误报,DSC-15 0 新增 FAIL。
20
+
21
+ ### Verified
22
+
23
+ - `npm test` 274/274。
1
24
  ## 1.6.0 — 2026-11-07
2
25
 
3
26
  ### Added
package/docs/coverage.md CHANGED
@@ -15,8 +15,10 @@ dsh-standards check <package-dir> \
15
15
  |---|---|---|
16
16
  | 完整口径 | **22** | `DSC-01` … `DSC-22`;`--scope security` 时 `checks[]` 带全 22 项 |
17
17
  | 默认 `checks[]` | **14** | `DSC-01` … `DSC-14`;默认 DS-C 判定只看这 14 项 |
18
- | 默认实际评估 | **6** | `DSC-01`、`DSC-02`、`DSC-10`、`DSC-11`、`DSC-12`、`DSC-13` |
19
- | 默认未检查 | **8** | `DSC-03`(NA)+ `DSC-04`–`DSC-09`(not-run)+ `DSC-14`(NA) |
18
+ | 默认 ds-c 实际评估(bundle) | **12 / 14** | bundle 的 `DSC-04`–`09` 以静态子集 `PASS`+`partial` 计入;`DSC-03`/`DSC-14` 为 NA |
19
+ | 默认 ds-c 实际评估(plugin,无 `--runtime`) | **6 / 14** | `DSC-04`–`09` 为 not-run;`DSC-03`/`DSC-14` 为 NA |
20
+ | 默认未检查(plugin 静态) | **8** | 2 NA + 6 not-run;不等于通过 |
21
+ | `--scope security` `checks[]` | **22** | 加 `DSC-15`–`DSC-22`;`coverage.mandatory=4`(15/16/17/21),仍可能 not-run |
20
22
  | 默认 security 块 | **8** | `DSC-15`–`DSC-22` 在 `security` 块里跑 advisory;FAIL 封顶 WARN,不改变 DS-C 结论 |
21
23
 
22
24
  `not checked` 桶把 NA / not-run / ERROR 都列出来;**没检查不等于通过**。`DSC-10` 是 advisory,只提供信号,不改变结论。
@@ -45,7 +47,7 @@ dsh-standards check <package-dir> \
45
47
  | `DSC-18` | L0 | **advisory(security 块)** | 端点线索,永不 FAIL | `--scope security`;外联端点 |
46
48
  | `DSC-19` | L0 | **advisory(security 块)** | 只登记不判恶 | `--scope security`;混淆/二进制 |
47
49
  | `DSC-20` | L0 | **advisory(security 块)** | 语义不可判、误报高 | `--scope security`;提示词注入 |
48
- | `DSC-21` | L0 | **advisory WARN(security 块)** | 名字线索;默认 scope 不 FAIL | `--scope security`;供应链,强制项但只 WARN |
50
+ | `DSC-21` | L0 | **WARN(security 块)** | 名字线索;默认 scope 不 FAIL | `--scope security`;供应链,强制项但只 WARN、不阻断 |
49
51
  | `DSC-22` | L0 | **advisory(security 块)** | 只有字段自证 | `--scope security`;来源/完整性,v1 只读字段 |
50
52
 
51
53
  ## security scope(C-15~C-22)
@@ -55,17 +57,21 @@ dsh-standards check <package-dir> \
55
57
  | 项 | security scope 判定 | 触发 |
56
58
  |---|---|---|
57
59
  | `DSC-15` 生命周期脚本 | **blocking**(可 FAIL) | 安装期 `curl\|sh`、`base64 -d`、`node -e`、`sh -c`、`powershell -enc`、引用缺失脚本、写 `$HOME`/`/etc` |
58
- | `DSC-16` 动态执行 | **blocking**(可 FAIL) | `eval`/`new Function(非空)`/`vm`/`module._compile`/`process.binding` → FAIL;裸 `child_process` → WARN |
60
+ | `DSC-16` 动态执行 | **blocking**(可 FAIL) | `eval`/`new Function(非空)`/`vm`/`module._compile`/`process.binding` → FAIL;裸 `child_process` → WARN;静态危险子进程命令 1.6.2 起 FAIL |
59
61
  | `DSC-17` 敏感文件 | **blocking**(可 FAIL) | 直接读 `~/.ssh`、`$DSH_HOME` credentials、`id_rsa`、`.aws`、`.npmrc`、`.netrc` 等;`.env` 只 WARN |
60
62
  | `DSC-18` 外联端点 | **advisory**(永不 FAIL) | 非 https、userinfo、公网裸 IP、webhook/paste/ngrok/onion、未披露端点 |
61
63
  | `DSC-19` 混淆/二进制 | **advisory** | 二进制 sha256、超长单行、大块 base64、高熵;只登记不判恶 |
62
64
  | `DSC-20` 提示词注入 | **advisory** | 外部文本进 systemPrompt、指令样字面量、无 untrusted 包裹;语义不可判 |
63
- | `DSC-21` 供应链 | **blocking(强制项)/ WARN(发现封顶)** | scope 同形字/近似 scope、近似名、元数据缺失;**永不 FAIL**,但未跑会使 security `incomplete` |
65
+ | `DSC-21` 供应链 | **WARN-only(强制项,不阻断)** | scope 同形字/近似 scope、近似名、元数据缺失;**永不 FAIL**,listing/package 均只 WARN;未跑会使 security `incomplete` |
64
66
  | `DSC-22` 来源/完整性 | **advisory**(永不 FAIL) | 只读 `dist.integrity` / `dsh.attestation` / `dsh.signature` 字段是否存在;不验签、不比对 digest;无输入即 `not-run` |
65
67
 
66
68
  **默认不改变判定**:不传 `--scope security` 时,这 8 项不进 `checks[]`,只在 `security` 块里以 `scope=advisory` 运行;任何 FAIL 封顶 WARN,`DS-C` 的 11/12 条强制集合与 exit code 不变。security 的 FAIL 不能撤销 `DS-C` PASS,`DS-C` PASS 也不能证明 security 通过。
67
69
 
68
- **边界**:C-15/C-16/C-17 可以 FAIL;C-21 是强制项但发现只到 WARN;C-18/C-19/C-20/C-22 是 advisory;其余安全面(实际网络流量、审批绕过、同进程逃逸、client DOM、`!!js` 配置、Remote 调用方身份)**没有机械判据**。任何 PASS 都只是"本次覆盖内未见该类线索",不是"安全/已审计"。
70
+ **报告读法(headline vs buckets)**:`conclusion.headline` 的 `blocking N` 与 `buckets.blocking[]` 只数 `checks[]` 里的 FAIL。默认 scope 下 security FAIL 封顶 WARN,只在 `security` 块(`security.warn[]`,`security.blocking=[]`),**不进 `buckets.blocking`**;`--scope security` 下 `DSC-15/16/17` FAIL 才进 `buckets.blocking`、抬高 headline 并 exit 1。`DSC-21` 永不 FAIL,两个 profile 都不阻断。
71
+
72
+ **partial 怎么读**:`checks[].coverage=partial` 仍计入 `coverage.checked`(若结果 PASS/WARN/FAIL),并单列到 `coverage.partial` / `buckets.partial`;它**不并入** `coverage.notRun`(后者只数完整 `not-run` + `ERROR` + 缺失强制项)。`security` 块没有独立 `partial[]`:看 `security.checks[].coverage`;`security.notRun[]` 不收 partial。
73
+
74
+ **边界**:C-15/C-16/C-17 可以 FAIL;C-21 是强制项但 **WARN-only、不阻断(listing 同)**;C-18/C-19/C-20/C-22 是 advisory;其余安全面(实际网络流量、审批绕过、同进程逃逸、client DOM、`!!js` 配置、Remote 调用方身份)**没有机械判据**。任何 PASS 都只是"本次覆盖内未见该类线索",不是"安全/已审计"。
69
75
 
70
76
  ## 执行 opt-in
71
77
 
@@ -95,10 +101,14 @@ dsh-standards check <package-dir> \
95
101
  - **WSL2(Ubuntu 24.04):** Linux 沙箱可用,能提供 `unshare` / `prlimit`;这是本仓做 runtime 采集的环境。WSL2 可用不等于某个 host × Node × checker 组合已经跑过,具体以 [SUPPORTED.md](../SUPPORTED.md) 的格子为准。
96
102
  - **Node:** 包声明 `engines.node >=24.9.0`;Node 22 只在自测 / 静态矩阵中有记录(见 SUPPORTED.md)。
97
103
 
104
+ ## advice 的 docsUrl
105
+
106
+ 报告 `advice[].docsUrl` 的基址是 checker 的 `DOCS_BASE`:1.6.1 为 `dsh-plugin-guide` `v0.4.6`,计划在 **1.6.2 升到 `v0.5.0`**。guide 0.5.0 的 `docs/security.md` 中 C-15~C-22 advice 使用的锚点(`#2-credentials-and-sensitive-files-dsc-17`、`#3-egress-endpoints-dsc-18`、`#4-files-subprocesses-and-dynamic-execution-dsc-15-dsc-16-dsc-17-dsc-19`、`#5-tool-output-and-prompt-injection-dsc-20`、`#6-dependencies-build-and-publish-dsc-15-dsc-21-dsc-22`)以及显式锚点 `#author-files`、`#author-credentials`、`#author-egress`、`#author-prompt`、`#author-publish`、`#scope` 已核对存在。
107
+
98
108
  ## 复核命令
99
109
 
100
110
  ```sh
101
- # 默认:6/14 评估,8 项 not-run/NA;security 块是 advisory
111
+ # 默认静态:plugin 6/14(04–09 not-run),bundle 12/14(04–09 PASS+partial);security 块是 advisory
102
112
  dsh-standards check <package-dir> --json | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const r=JSON.parse(s);console.log(r.coverage.checked+"/"+r.coverage.total);console.log(r.anchor);console.log(r.security)})'
103
113
 
104
114
  # 默认 + security scope:checks[] 变 22 项(不执行插件)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-standards",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "DSH plugin standards and conformance checks: ENTRY/FLOW checks plus BOOST guidance. Non-official; no certification or ranking.",
5
5
  "type": "module",
6
6
  "main": "40-checker/src/index.mjs",
@@ -1,6 +1,6 @@
1
1
  # coverage 契约(`dsh-conformance/1`)
2
2
 
3
- > 适用版本:dsh-standards **1.6.0**(计划版本;1.5.0 及更早为 14 项)。`40-checker/src/report.mjs` 的 `buildReport()` 负责计数;`security` 块见 §6。
3
+ > 适用版本:dsh-standards **1.6.0+**(当前 1.6.1;1.5.0 及更早为 14 项)。`40-checker/src/report.mjs` 的 `buildReport()` 负责计数;`security` 块见 §6。
4
4
  > 机器可校验形状见 [`schemas/conformance.schema.json`](schemas/conformance.schema.json);本文只统一字段含义。
5
5
  > 结论:`coverage` 是**加性计数**,不参与 verdict;`PASS/WARN/FAIL` 与 `status/level` 由 `conclusion` 和对应 profile 的强制项决定。
6
6
 
@@ -25,14 +25,14 @@
25
25
  | `advisory` | `check.advisory === true` 且结果为 `WARN` 的数量;是 `warn` 的子集,只作信号,永不改 verdict。 |
26
26
  | `fail` | 结果 `FAIL` 的数量。 |
27
27
  | `na` | 结果 `NA` 的数量(对象形态/上下文不适用),**不是通过**。 |
28
- | `notRun` | `coverage` 为 `not-run`/`partial` 且结果非 `NA` 的项、结果 `ERROR` 的项、以及**缺失的强制项** ID 去重后的数量;包含 `error`。 |
28
+ | `notRun` | `coverage` 为 `not-run` 且结果非 `NA` 的项、结果 `ERROR` 的项、以及**缺失的强制项** ID 去重后的数量;包含 `error`。**不含** `partial`。 |
29
29
  | `error` | 结果 `ERROR` 的数量(检查器失效或该跑没跑);是 `notRun` 的子集。 |
30
30
 
31
31
  加性诊断字段(1.3.0 工作树同时输出;旧消费者应按“可选”处理,不参与 verdict):
32
32
 
33
33
  | 字段 | 定义 |
34
34
  |---|---|
35
- | `coverage.partial` | `checks[].coverage === "partial"` 的数量。它同时保留在 `checked`(若结果 PASS/WARN/FAIL)和 `notRun` 中;这个计数只是把重叠显式化,**不是第 10 个通过口径**。 |
35
+ | `coverage.partial` | `checks[].coverage === "partial"` 的数量。结果 PASS/WARN/FAIL 时仍计入 `checked`;但**不并入** `coverage.notRun`,只在 `coverage.partial` 与 `buckets.partial` 中单列。这个计数**不是第 10 个通过口径**。 |
36
36
  | 顶层 `notChecked` | `buckets.notChecked` 与 `buckets.partial` 按 `id` 去重后的可读视图,每行带 `howToEnable`。等价信息已在 `buckets` 里子集化,消费者可忽略。 |
37
37
  | `buckets.partial` | `coverage: "partial"` 的检查行;同一行可能也出现在 `blocking` / `hygiene`。 |
38
38
  | 行级 `howToEnable` | 让该 NA/ERROR/partial 行可运行的命令或 flag;仅提示。 |
@@ -42,7 +42,8 @@
42
42
  - `checked = pass + warn + fail`(`advisory <= warn`)。
43
43
  - `error <= notRun`;`notRun` 统计的是“没拿到完整结论”的项,`NA` 不算没跑。
44
44
  - 默认 `ds-c` 完整跑(14 项、无缺失)与 `--scope security` 完整跑(22 项、无缺失)都满足 `checked + na + notRun = total`;两份报告的 `total` 不同,不能混算通过率。
45
- - **例外**:若某项 `coverage: "partial"` 但结果仍是 `WARN`/`FAIL`,它会同时出现在 `checked` 与 `notRun` 中——已评估但不完整,不能当成 `full`。有缺失强制项时,`notRun` 会含不在 `checks[]` 里的 ID,此时上述加法可大于 `total`。
45
+ - **例外**:`coverage: "partial"` 的项若结果仍是 `WARN`/`FAIL`,它同时出现在 `checked` 与 `coverage.partial`/`buckets.partial`;它是"已评估但不完整",不并入 `notRun`。有缺失强制项时,`notRun` 会含不在 `checks[]` 里的 ID,此时加法可大于 `total`。
46
+ - **注**:`schemas/conformance.schema.json` 里 `coverage.notRun` 的旧描述仍写“含 partial”,与本表不符;以 `buildReport()` 当前输出(不含 partial)为准,schema 文案待后续版本同步。
46
47
  - `metrics = { checked, total, declaredFields }`:`checked`/`total` 与 `coverage` 同源;`declaredFields` 是 capabilities/labels/commitments/disclosure/engines.dsh 五个可选声明面中实际声明的个数(0–5),只作上下文。
47
48
 
48
49
  ## 3. 与旧检查级 `full` / `partial` 的映射
@@ -53,7 +54,7 @@
53
54
  |---|---|---|
54
55
  | `full` + `PASS`/`WARN`/`FAIL` | `checked`,并落入 `pass`/`warn`/`fail` | 完整评估,计入结论。 |
55
56
  | `full` + `NA` | `na` | 显式不适用;旧报告常把 NA 记在 `full` 之外。 |
56
- | `partial`(无论结果) | `notRun` | 只跑了一部分,必须当未完成;若结果仍是 `WARN`/`FAIL`,同时计入 `checked`。 |
57
+ | `partial`(无论结果) | `checked`(若结果 PASS/WARN/FAIL)+ `coverage.partial` / `buckets.partial` | 只跑了一部分:已评估但不完整;**不计入** `coverage.notRun`,不得当 `full`。 |
57
58
  | `not-run` | `notRun` | 完全没跑。 |
58
59
  | `ERROR`(旧 `error` 计数) | `notRun` + `error` | 检查器失效/未执行;两者都计。 |
59
60
 
@@ -61,7 +62,8 @@
61
62
 
62
63
  - 旧 `mandatory` → 新 `mandatory`(同义,选出的强制项数)。
63
64
  - 旧 `full` → 新 `checked` **减去** `partial` 但已评估的项,再减去 `full + NA` 的项;最稳妥的读法是“旧 full 只看覆盖,新 checked 看结果”。
64
- - 旧 `partial` / `notRun` → 新 `notRun`。
65
+ - 旧 `partial` → 新 `coverage.partial` / `buckets.partial`(结果 PASS/WARN/FAIL 时同时在 `checked`;不进 `notRun`)。
66
+ - 旧 `notRun` → 新 `notRun`。
65
67
  - 旧 `na` → 新 `na`。
66
68
  - 旧 `error` → 新 `error`(并已包含在 `notRun`)。
67
69
  - 旧对象没有 `total` / `pass` / `warn` / `advisory` / `fail` / `checked`;这些是 1.3.0 的新增计数。
@@ -108,10 +110,11 @@
108
110
  | `security.status=fail` | **仅 security scope**:`DSC-15`/`DSC-16`/`DSC-17` 任一 FAIL。`DSC-21` 永不 FAIL;默认模式 FAIL 封顶 WARN,不会出现 fail。 |
109
111
  | `security.status=warn` | 无 FAIL,但有 `DSC-21` 或 15/16/17 的 WARN,或 18/19/20/22 的 advisory WARN。 |
110
112
  | `security.status=incomplete` | **security scope 下** `DSC-15`/`DSC-16`/`DSC-17`/`DSC-21` 任一结果不在 `PASS`/`WARN`/`FAIL`(即 `NA`/`ERROR`/`not-run`)。 |
113
+ | `security` 块的 `partial` | 1.6.1 **没有** `security.partial[]`:部分覆盖看 `security.checks[].coverage === "partial"`;`security.notRun[]` 只收 `NA`/`ERROR`/完整 `not-run`,**不收 partial**。`security.status=pass` 不要求 partial 为空,市场必须读 `checks[]`,不能只看四个数组。顶层 `coverage.partial` / `buckets.partial` 在 security scope 下统计 `checks[]` 全部 22 项(含这 8 项)。 |
111
114
  | 与 DS-C 关系 | **独立**:security FAIL 不撤销 DS-C PASS;DS-C PASS 不证明 security 通过;反之亦然。 |
112
115
  | 徽章 | **不得**发 security 徽章;市场只透传 `security.status`、`security.checks[]` 与 `security.notRun[]`,不按安全分排序/筛选。 |
113
116
 
114
- 严重度以 `spec/dsc-clauses.json` 的 `mandatory`/`advisory` 与 31 §2 C-15~C-22 为准:`DSC-15/16/17` 为 blocking(可 FAIL);`DSC-21` 是强制项但发现封顶 WARN(永不 FAIL,未跑才 `incomplete`);`DSC-18/19/20/22` 为 advisory(`advisory:true`,永不改 verdict)。`security` 块只汇总这 8 项,不与顶层 `coverage` 换算成第二套通过率。
117
+ 严重度以 `spec/dsc-clauses.json` 的 `mandatory`/`advisory` 与 31 §2 C-15~C-22 为准:`DSC-15/16/17` 为 blocking(可 FAIL);`DSC-21` 是强制项但 **WARN-only、不阻断(listing 同;永不 FAIL,未跑才 `incomplete`)**;`DSC-18/19/20/22` 为 advisory(`advisory:true`,永不改 verdict)。`security` 块只汇总这 8 项,不与顶层 `coverage` 换算成第二套通过率。
115
118
 
116
119
  ## 7. 禁止事项
117
120