@lqc123qwe/car-runtime 1.9.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/README.md +17 -1
  2. package/dist/SHA256SUMS +1 -0
  3. package/dist/authz/authz.d.ts +46 -0
  4. package/dist/authz/authz.js +76 -0
  5. package/dist/car-runtime-1.11.0.tgz +0 -0
  6. package/dist/car-runtime-1.11.0.tgz.sig.bundle +1 -0
  7. package/dist/cli.d.ts +1 -0
  8. package/dist/cli.js +825 -0
  9. package/dist/dx/doctor.d.ts +62 -0
  10. package/dist/dx/doctor.js +127 -0
  11. package/dist/governance/dump.d.ts +47 -0
  12. package/dist/governance/dump.js +17 -0
  13. package/dist/host/facade.d.ts +13 -0
  14. package/dist/host/facade.js +154 -0
  15. package/dist/host/hostGateway.d.ts +117 -0
  16. package/dist/host/hostGateway.js +65 -0
  17. package/dist/host/mappings.d.ts +27 -0
  18. package/dist/host/mappings.js +52 -0
  19. package/dist/host/stdio.d.ts +14 -0
  20. package/dist/host/stdio.js +83 -0
  21. package/dist/kernel/context.d.ts +76 -0
  22. package/dist/kernel/context.js +203 -0
  23. package/dist/kernel/events.d.ts +37 -0
  24. package/dist/kernel/events.js +82 -0
  25. package/dist/load/config.d.ts +79 -0
  26. package/dist/load/config.js +285 -0
  27. package/dist/load/loader.d.ts +72 -0
  28. package/dist/load/loader.js +162 -0
  29. package/dist/load/registry.d.ts +44 -0
  30. package/dist/load/registry.js +58 -0
  31. package/dist/load/report.d.ts +98 -0
  32. package/dist/load/report.js +301 -0
  33. package/dist/load/sigGate.d.ts +22 -0
  34. package/dist/load/sigGate.js +68 -0
  35. package/dist/load/sign.d.ts +25 -0
  36. package/dist/load/sign.js +47 -0
  37. package/dist/load/verifier.d.ts +35 -0
  38. package/dist/load/verifier.js +56 -0
  39. package/dist/loop/goal.d.ts +31 -0
  40. package/dist/loop/goal.js +34 -0
  41. package/dist/loop/recover.d.ts +17 -0
  42. package/dist/loop/recover.js +39 -0
  43. package/dist/loop/stop.d.ts +82 -0
  44. package/dist/loop/stop.js +184 -0
  45. package/dist/mcp/gateway.d.ts +96 -0
  46. package/dist/mcp/gateway.js +69 -0
  47. package/dist/mcp/httpClient.d.ts +27 -0
  48. package/dist/mcp/httpClient.js +196 -0
  49. package/dist/mcp/stdioClient.d.ts +8 -0
  50. package/dist/mcp/stdioClient.js +73 -0
  51. package/dist/ptc/budget.d.ts +21 -0
  52. package/dist/ptc/budget.js +36 -0
  53. package/dist/ptc/erasable.d.ts +14 -0
  54. package/dist/ptc/erasable.js +27 -0
  55. package/dist/ptc/runCode.d.ts +65 -0
  56. package/dist/ptc/runCode.js +140 -0
  57. package/dist/ptc/schemaRender.d.ts +15 -0
  58. package/dist/ptc/schemaRender.js +90 -0
  59. package/dist/ptc/sdk.d.ts +27 -0
  60. package/dist/ptc/sdk.js +23 -0
  61. package/dist/ptc/worker-entry.d.ts +1 -0
  62. package/dist/ptc/worker-entry.js +71 -0
  63. package/dist/release-audit.jsonl +4 -0
  64. package/dist/runtime-core/chatStep.d.ts +43 -0
  65. package/dist/runtime-core/chatStep.js +121 -0
  66. package/dist/runtime-core/credentials.d.ts +49 -0
  67. package/dist/runtime-core/credentials.js +118 -0
  68. package/dist/runtime-core/errors.d.ts +30 -0
  69. package/dist/runtime-core/errors.js +36 -0
  70. package/dist/runtime-core/llm.d.ts +76 -0
  71. package/dist/runtime-core/llm.js +638 -0
  72. package/dist/runtime-core/redaction.d.ts +39 -0
  73. package/dist/runtime-core/redaction.js +79 -0
  74. package/dist/runtime-core/telemetry.d.ts +88 -0
  75. package/dist/runtime-core/telemetry.js +332 -0
  76. package/dist/runtime-core/tools.d.ts +15 -0
  77. package/dist/runtime-core/tools.js +12 -0
  78. package/dist/runtime-core/trace.d.ts +55 -0
  79. package/dist/runtime-core/trace.js +137 -0
  80. package/dist/runtime-core/types.d.ts +104 -0
  81. package/dist/runtime-core/types.js +13 -0
  82. package/dist/sandbox/sandbox.d.ts +68 -0
  83. package/dist/sandbox/sandbox.js +153 -0
  84. package/dist/sbom.json +263 -0
  85. package/dist/seam.d.ts +24 -0
  86. package/dist/seam.js +23 -0
  87. package/dist/security/secrets-baseline.d.ts +43 -0
  88. package/dist/security/secrets-baseline.js +176 -0
  89. package/dist/security/secrets.d.ts +45 -0
  90. package/dist/security/secrets.js +138 -0
  91. package/dist/session/export.d.ts +55 -0
  92. package/dist/session/export.js +81 -0
  93. package/dist/session/fork.d.ts +51 -0
  94. package/dist/session/fork.js +63 -0
  95. package/dist/session/format.d.ts +21 -0
  96. package/dist/session/format.js +49 -0
  97. package/dist/session/indexStore.d.ts +44 -0
  98. package/dist/session/indexStore.js +265 -0
  99. package/dist/session/log.d.ts +79 -0
  100. package/dist/session/log.js +157 -0
  101. package/dist/session/store.d.ts +9 -0
  102. package/dist/session/store.js +37 -0
  103. package/dist/telemetry/metrics.d.ts +25 -0
  104. package/dist/telemetry/metrics.js +26 -0
  105. package/package.json +17 -1
  106. package/src/authz/authz.ts +12 -0
  107. package/src/loop/stop.ts +43 -10
  108. package/src/runtime-core/chatStep.ts +22 -2
  109. package/src/runtime-core/llm.ts +96 -13
  110. package/src/runtime-core/types.ts +22 -1
  111. package/src/seam.ts +24 -0
  112. package/src/session/log.ts +1 -1
  113. package/.gitattributes +0 -11
  114. package/.github/workflows/ci.yml +0 -293
  115. package/.github/workflows/release.yml +0 -54
  116. package/adr/ADR-001.md +0 -4
  117. package/adr/ADR-002.md +0 -5
  118. package/adr/ADR-003.md +0 -35
  119. package/adr/host-onboarding.md +0 -68
  120. package/adr/mlps-audit-checklist.md +0 -41
  121. package/adr/win32-spike.md +0 -45
  122. package/docs/plugin-authoring.md +0 -82
  123. package/native/landlock-run/Makefile +0 -19
  124. package/native/landlock-run/landlock-run.c +0 -162
  125. package/scripts/contract-check.ts +0 -56
  126. package/scripts/invariant-n1.ts +0 -96
  127. package/scripts/package-check.ts +0 -29
  128. package/scripts/ptc-baseline/run-baseline.ts +0 -118
  129. package/scripts/release-artifacts.ts +0 -111
  130. package/scripts/release-pipeline.ts +0 -245
  131. package/scripts/secrets-baseline.ts +0 -33
  132. package/scripts/secrets-scan.ts +0 -56
  133. package/scripts/win32-ffi-debug.ts +0 -143
  134. package/scripts/win32-koffi-spike.ts +0 -537
  135. package/test/contract/eventmap.golden.json +0 -7
  136. package/test/fixtures/hello-plugin.ts +0 -5
  137. package/test/kernel.spec.ts +0 -136
  138. package/test/registry-e2e/run-e2e.ts +0 -213
  139. package/test/s11.spec.ts +0 -129
  140. package/test/s12.spec.ts +0 -135
  141. package/test/s13.spec.ts +0 -117
  142. package/test/s14.spec.ts +0 -117
  143. package/test/s15.spec.ts +0 -80
  144. package/test/s16.spec.ts +0 -133
  145. package/test/s17.spec.ts +0 -102
  146. package/test/s18.spec.ts +0 -81
  147. package/test/s19.spec.ts +0 -138
  148. package/test/s2.spec.ts +0 -245
  149. package/test/s20.spec.ts +0 -241
  150. package/test/s21.spec.ts +0 -231
  151. package/test/s22-m7-store-format.spec.ts +0 -135
  152. package/test/s23-m7-export-index.spec.ts +0 -189
  153. package/test/s24-signature-gate.spec.ts +0 -185
  154. package/test/s25-m8-runtime-core.spec.ts +0 -600
  155. package/test/s26-signature-closeout.spec.ts +0 -349
  156. package/test/s27-host-load-wiring.spec.ts +0 -134
  157. package/test/s28-session-index-followup.spec.ts +0 -236
  158. package/test/s29-otel-producer.spec.ts +0 -252
  159. package/test/s3.spec.ts +0 -179
  160. package/test/s30-release-artifacts.spec.ts +0 -127
  161. package/test/s31-real-model-wiring.spec.ts +0 -329
  162. package/test/s32-telemetry-mcp-ptc.spec.ts +0 -218
  163. package/test/s33-anthropic-adapter.spec.ts +0 -354
  164. package/test/s34-mcp-remote-transport.spec.ts +0 -250
  165. package/test/s35-config-ts-zod.spec.ts +0 -145
  166. package/test/s36-host-tool-surface.spec.ts +0 -250
  167. package/test/s37-projection-dedupe.spec.ts +0 -161
  168. package/test/s38-config-jiti.spec.ts +0 -116
  169. package/test/s39-otlp-span-semantics.spec.ts +0 -100
  170. package/test/s4.spec.ts +0 -169
  171. package/test/s40-metrics-cumulative.spec.ts +0 -67
  172. package/test/s41-mcp-serve-turn-span.spec.ts +0 -148
  173. package/test/s42-traceparent-propagation.spec.ts +0 -415
  174. package/test/s43-remote-http-traceparent.spec.ts +0 -262
  175. package/test/s5.spec.ts +0 -95
  176. package/test/s6.spec.ts +0 -169
  177. package/test/s7.spec.ts +0 -136
  178. package/test/s7b-baseline.spec.ts +0 -20
  179. package/test/s9.spec.ts +0 -89
  180. package/test/sandbox-escape/j17-orchestrate.sh +0 -30
  181. package/test/sandbox-escape/run-matrix.sh +0 -98
  182. package/tsconfig.json +0 -18
@@ -1,185 +0,0 @@
1
- /**
2
- * M5-S28 · 装载签名门(sigGate + loadPlugins verify 阶段 + ReloadManager 透传)
3
- *
4
- * 覆盖(ADR-003 fail-closed 分级 / DEC-1 ② warn 缺省 / S20 §1 零内容计数):
5
- * - warn 缺签:放行 + CAR-W-SIG 横幅(含 fp 指纹)+ confirmed=no 计数
6
- * - unsignedAllow:confirmed=yes 改写(显式确认豁免动作),横幅保留
7
- * - enforce 缺签:verify FAIL + 空 plugins + 后续 SKIPPED + car_load_total failed
8
- * - 有签名验签失败:硬拒绝——unsignedAllow 亦不可放行(ADR-003 第一级)
9
- * - 好签名:静默放行,零签名计数
10
- * - car_load_total{result=ok} 逐插件计数
11
- * - ReloadManager.reload signature 透传(enforce FAIL)
12
- * - verifyPluginFile 单文件口径(car run 直载门同源)+ gateDepsFromEnv env 通道映射
13
- */
14
- import { test } from 'node:test'
15
- import assert from 'node:assert/strict'
16
- import { mkdtempSync, writeFileSync, readFileSync, rmSync } from 'node:fs'
17
- import { tmpdir } from 'node:os'
18
- import { join } from 'node:path'
19
- import { createHash, generateKeyPairSync, sign } from 'node:crypto'
20
- import { loadPlugins, ReloadManager } from '../src/load/report.ts'
21
- import { verifyPluginFile, gateDepsFromEnv } from '../src/load/sigGate.ts'
22
- import { createCounters, assertZeroContent } from '../src/telemetry/metrics.ts'
23
- import type { LoadReportVO } from '../src/load/report.ts'
24
-
25
- // ==================== fixture(抄 s6 密钥生成 + s20 临时目录模式) ====================
26
-
27
- const PLUGIN_BODY = (tool: string) =>
28
- `export default function apply(api) {\n api.registerTool({ name: '${tool}', run: async () => 'ok' })\n}\n`
29
-
30
- function makePlugin(dir: string, file: string, manifest: Record<string, unknown>, tool: string): string {
31
- const p = join(dir, file)
32
- writeFileSync(p, `export const manifest = ${JSON.stringify(manifest)}\n${PLUGIN_BODY(tool)}\n`)
33
- return p
34
- }
35
-
36
- function withTempDir(name: string, fn: (dir: string) => Promise<void> | void): Promise<void> {
37
- const dir = mkdtempSync(join(tmpdir(), `car-s24-${name}-`))
38
- return Promise.resolve()
39
- .then(() => fn(dir))
40
- .finally(() => { try { rmSync(dir, { recursive: true, force: true }) } catch { /* 红线 8 */ } })
41
- }
42
-
43
- const { publicKey, privateKey } = generateKeyPairSync('ed25519')
44
- const PUB_B64 = publicKey.export({ type: 'spki', format: 'der' }).toString('base64')
45
-
46
- /** 对插件文件裸字节求 sha256 hex,以 ed25519 签 hex 串 UTF-8 字节,写 sidecar `<file>.minisig` */
47
- function signSidecar(file: string, signKey = privateKey): string {
48
- const manifestHash = createHash('sha256').update(readFileSync(file)).digest('hex')
49
- const minisig = sign(null, Buffer.from(manifestHash), signKey).toString('base64')
50
- writeFileSync(`${file}.minisig`, minisig)
51
- return manifestHash
52
- }
53
-
54
- const stageNames = (r: LoadReportVO) => r.stages.map(s => `${s.stage}:${s.status}`)
55
- const stageOf = (r: LoadReportVO, s: string) => r.stages.find(x => x.stage === s)!
56
- const SIX_OK = ['discover:PASS', 'verify:PASS', 'parse:PASS', 'validate:PASS', 'topo:PASS', 'register:PASS']
57
-
58
- // ==================== warn 缺省(DEC-1 ②) ====================
59
-
60
- test('S28: warn 缺签——放行 + CAR-W-SIG 横幅含 fp 指纹 + confirmed=no 计数 + 六阶段全 PASS', async () => {
61
- await withTempDir('warn-unsigned', async (dir) => {
62
- makePlugin(dir, 'p.ts', { name: 'p', version: '1.0.0' }, 't')
63
- const c = createCounters()
64
- const { report, plugins } = await loadPlugins({ source: dir, signature: { onCount: (n, l) => c.onCount(n, l) } })
65
- assert.deepEqual(stageNames(report), SIX_OK)
66
- assert.equal(plugins.length, 1)
67
- const banner = report.warnings.find(w => w.startsWith('CAR-W-SIG'))
68
- assert.ok(banner, 'unsigned 横幅在位')
69
- assert.match(banner!, /\[fp:[0-9a-f]{12}\]/, '横幅含 manifestHash 指纹前缀')
70
- assert.deepEqual(c.snapshot(), { 'car_load_total|result=ok': 1, 'car_unsigned_confirmed|confirmed=no': 1 })
71
- assert.equal(assertZeroContent(c.snapshot()), true)
72
- })
73
- })
74
-
75
- test('S28: unsignedAllow 显式豁免——confirmed=yes 改写 + 横幅保留(S20 §4 路径②)', async () => {
76
- await withTempDir('unsigned-allow', async (dir) => {
77
- makePlugin(dir, 'p.ts', { name: 'p', version: '1.0.0' }, 't')
78
- const c = createCounters()
79
- const { report } = await loadPlugins({ source: dir, signature: { unsignedAllow: true, onCount: (n, l) => c.onCount(n, l) } })
80
- assert.equal(stageOf(report, 'verify').status, 'PASS')
81
- assert.ok(report.warnings.some(w => w.startsWith('CAR-W-SIG')), '横幅保留不消失')
82
- assert.deepEqual(c.snapshot(), { 'car_load_total|result=ok': 1, 'car_unsigned_confirmed|confirmed=yes': 1 })
83
- })
84
- })
85
-
86
- // ==================== enforce / 验签失败 fail-closed ====================
87
-
88
- test('S28: enforce 缺签——verify FAIL + 空 plugins + 后续 SKIPPED + load_total failed', async () => {
89
- await withTempDir('enforce-unsigned', async (dir) => {
90
- makePlugin(dir, 'p.ts', { name: 'p', version: '1.0.0' }, 't')
91
- const c = createCounters()
92
- const { report, plugins } = await loadPlugins({ source: dir, signature: { mode: 'enforce', onCount: (n, l) => c.onCount(n, l) } })
93
- assert.deepEqual(stageNames(report), [
94
- 'discover:PASS', 'verify:FAIL', 'parse:SKIPPED', 'validate:SKIPPED', 'topo:SKIPPED', 'register:SKIPPED',
95
- ])
96
- const v = stageOf(report, 'verify')
97
- assert.match(v.error!.reason, /CAR-E-SIG: signature missing/)
98
- assert.match(v.error!.file, /p\.ts$/)
99
- assert.equal(plugins.length, 0, 'fail-closed:拒绝即空')
100
- assert.deepEqual(c.snapshot(), { 'car_load_total|result=failed': 1 })
101
- })
102
- })
103
-
104
- test('S28: 有签名但验签失败——硬拒绝不可配置放行(unsignedAllow 亦不豁免,ADR-003 第一级)', async () => {
105
- await withTempDir('bad-sig', async (dir) => {
106
- const f = makePlugin(dir, 'p.ts', { name: 'p', version: '1.0.0' }, 't')
107
- signSidecar(f)
108
- // 签名后篡改插件文件 → 指纹失配 → 验签失败
109
- writeFileSync(f, `export const manifest = { name: 'p', version: '1.0.0' }\n// tampered\n${PLUGIN_BODY('t')}`)
110
- const { report } = await loadPlugins({ source: dir, signature: { trustRootPublicKey: PUB_B64, unsignedAllow: true } })
111
- assert.equal(stageOf(report, 'verify').status, 'FAIL')
112
- assert.match(stageOf(report, 'verify').error!.reason, /signature verification FAILED.*不可配置放行/)
113
- })
114
- })
115
-
116
- test('S28: 好签名(信任根在位)——静默放行,零签名计数、零横幅', async () => {
117
- await withTempDir('good-sig', async (dir) => {
118
- const f = makePlugin(dir, 'p.ts', { name: 'p', version: '1.0.0' }, 't')
119
- signSidecar(f)
120
- const c = createCounters()
121
- const { report, plugins } = await loadPlugins({ source: dir, signature: { trustRootPublicKey: PUB_B64, onCount: (n, l) => c.onCount(n, l) } })
122
- assert.deepEqual(stageNames(report), SIX_OK)
123
- assert.equal(plugins.length, 1)
124
- assert.equal(report.warnings.some(w => w.startsWith('CAR-W-SIG')), false)
125
- // 好签名路径零签名计数;car_load_total 正常计数(register 成功)
126
- assert.deepEqual(c.snapshot(), { 'car_load_total|result=ok': 1 })
127
- })
128
- })
129
-
130
- test('S28: car_load_total{result=ok} 逐插件计数(S27 采集面分母)', async () => {
131
- await withTempDir('load-total', async (dir) => {
132
- makePlugin(dir, 'a.ts', { name: 'a', version: '1.0.0' }, 'ta')
133
- makePlugin(dir, 'b.ts', { name: 'b', version: '1.0.0' }, 'tb')
134
- const c = createCounters()
135
- await loadPlugins({ source: dir, signature: { onCount: (n, l) => c.onCount(n, l) } })
136
- assert.deepEqual(c.snapshot(), { 'car_load_total|result=ok': 2, 'car_unsigned_confirmed|confirmed=no': 2 })
137
- })
138
- })
139
-
140
- // ==================== ReloadManager 透传 + 单文件门 + env 通道 ====================
141
-
142
- test('S28: ReloadManager.reload signature 透传——enforce FAIL 且不残留实例', async () => {
143
- await withTempDir('reload-sig', async (dir) => {
144
- const f = makePlugin(dir, 'hot.ts', { name: 'hot', version: '1.0.0' }, 't')
145
- const mgr = new ReloadManager()
146
- const r1 = await mgr.reload(f)
147
- assert.deepEqual(stageNames(r1.report), SIX_OK)
148
- const r2 = await mgr.reload(f, { signature: { mode: 'enforce' } })
149
- assert.equal(stageOf(r2.report, 'verify').status, 'FAIL')
150
- assert.equal(r2.plugins.length, 0)
151
- })
152
- })
153
-
154
- test('S28: verifyPluginFile 单文件口径——car run 直载门同源;他人签名 warn 下同样硬拒绝', async () => {
155
- await withTempDir('single-file', async (dir) => {
156
- const f = makePlugin(dir, 'p.ts', { name: 'p', version: '1.0.0' }, 't')
157
- const g1 = verifyPluginFile(f, { mode: 'warn' })
158
- assert.equal(g1.allowed, true)
159
- assert.ok(g1.warning)
160
- assert.match(g1.manifestHash!, /^[0-9a-f]{64}$/)
161
- const g2 = verifyPluginFile(f, { mode: 'enforce' })
162
- assert.equal(g2.allowed, false)
163
- // 好签名 + 信任根在位 → enforce 静默放行
164
- signSidecar(f)
165
- const g3 = verifyPluginFile(f, { mode: 'enforce', trustRootPublicKey: PUB_B64 })
166
- assert.equal(g3.allowed, true)
167
- assert.equal(g3.warning, undefined)
168
- // 信任根失配(他人签名)→ 验签失败硬拒绝(warn 模式也不放行——第一级 fail-closed)
169
- const { privateKey: other } = generateKeyPairSync('ed25519')
170
- signSidecar(f, other)
171
- const g4 = verifyPluginFile(f, { mode: 'warn', trustRootPublicKey: PUB_B64 })
172
- assert.equal(g4.allowed, false, '验签失败级不受模式影响')
173
- })
174
- })
175
-
176
- test('S28: gateDepsFromEnv env 通道映射(CAR_SIG_ENFORCE / CAR_TRUST_ROOT / CAR_UNSIGNED_ALLOW)', () => {
177
- const d1 = gateDepsFromEnv({})
178
- assert.equal(d1.mode, 'warn')
179
- assert.equal(d1.trustRootPublicKey, undefined)
180
- assert.equal(d1.unsignedAllow, false)
181
- const d2 = gateDepsFromEnv({ CAR_SIG_ENFORCE: '1', CAR_TRUST_ROOT: PUB_B64, CAR_UNSIGNED_ALLOW: '1' })
182
- assert.equal(d2.mode, 'enforce')
183
- assert.equal(d2.trustRootPublicKey, PUB_B64)
184
- assert.equal(d2.unsignedAllow, true)
185
- })