@lqc123qwe/car-runtime 1.8.0 → 1.10.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 (178) hide show
  1. package/README.md +29 -1
  2. package/dist/SHA256SUMS +1 -0
  3. package/dist/authz/authz.d.ts +44 -0
  4. package/dist/authz/authz.js +65 -0
  5. package/dist/car-runtime-1.10.0.tgz +0 -0
  6. package/dist/car-runtime-1.10.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 +79 -0
  44. package/dist/loop/stop.js +151 -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 +40 -0
  65. package/dist/runtime-core/chatStep.js +104 -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 +553 -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 +84 -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 +21 -0
  86. package/dist/seam.js +20 -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/mcp/gateway.ts +10 -2
  107. package/src/mcp/httpClient.ts +23 -5
  108. package/src/runtime-core/trace.ts +5 -0
  109. package/src/seam.ts +21 -0
  110. package/.gitattributes +0 -11
  111. package/.github/workflows/ci.yml +0 -293
  112. package/.github/workflows/release.yml +0 -54
  113. package/adr/ADR-001.md +0 -4
  114. package/adr/ADR-002.md +0 -5
  115. package/adr/ADR-003.md +0 -35
  116. package/adr/host-onboarding.md +0 -68
  117. package/adr/mlps-audit-checklist.md +0 -41
  118. package/adr/win32-spike.md +0 -45
  119. package/docs/plugin-authoring.md +0 -82
  120. package/native/landlock-run/Makefile +0 -19
  121. package/native/landlock-run/landlock-run.c +0 -162
  122. package/scripts/contract-check.ts +0 -56
  123. package/scripts/invariant-n1.ts +0 -96
  124. package/scripts/package-check.ts +0 -29
  125. package/scripts/ptc-baseline/run-baseline.ts +0 -118
  126. package/scripts/release-artifacts.ts +0 -111
  127. package/scripts/release-pipeline.ts +0 -245
  128. package/scripts/secrets-baseline.ts +0 -33
  129. package/scripts/secrets-scan.ts +0 -56
  130. package/scripts/win32-ffi-debug.ts +0 -143
  131. package/scripts/win32-koffi-spike.ts +0 -537
  132. package/test/contract/eventmap.golden.json +0 -7
  133. package/test/fixtures/hello-plugin.ts +0 -5
  134. package/test/kernel.spec.ts +0 -136
  135. package/test/registry-e2e/run-e2e.ts +0 -213
  136. package/test/s11.spec.ts +0 -129
  137. package/test/s12.spec.ts +0 -135
  138. package/test/s13.spec.ts +0 -117
  139. package/test/s14.spec.ts +0 -117
  140. package/test/s15.spec.ts +0 -80
  141. package/test/s16.spec.ts +0 -133
  142. package/test/s17.spec.ts +0 -102
  143. package/test/s18.spec.ts +0 -81
  144. package/test/s19.spec.ts +0 -138
  145. package/test/s2.spec.ts +0 -245
  146. package/test/s20.spec.ts +0 -241
  147. package/test/s21.spec.ts +0 -231
  148. package/test/s22-m7-store-format.spec.ts +0 -135
  149. package/test/s23-m7-export-index.spec.ts +0 -189
  150. package/test/s24-signature-gate.spec.ts +0 -185
  151. package/test/s25-m8-runtime-core.spec.ts +0 -600
  152. package/test/s26-signature-closeout.spec.ts +0 -349
  153. package/test/s27-host-load-wiring.spec.ts +0 -134
  154. package/test/s28-session-index-followup.spec.ts +0 -236
  155. package/test/s29-otel-producer.spec.ts +0 -252
  156. package/test/s3.spec.ts +0 -179
  157. package/test/s30-release-artifacts.spec.ts +0 -127
  158. package/test/s31-real-model-wiring.spec.ts +0 -329
  159. package/test/s32-telemetry-mcp-ptc.spec.ts +0 -218
  160. package/test/s33-anthropic-adapter.spec.ts +0 -354
  161. package/test/s34-mcp-remote-transport.spec.ts +0 -250
  162. package/test/s35-config-ts-zod.spec.ts +0 -145
  163. package/test/s36-host-tool-surface.spec.ts +0 -250
  164. package/test/s37-projection-dedupe.spec.ts +0 -161
  165. package/test/s38-config-jiti.spec.ts +0 -116
  166. package/test/s39-otlp-span-semantics.spec.ts +0 -100
  167. package/test/s4.spec.ts +0 -169
  168. package/test/s40-metrics-cumulative.spec.ts +0 -67
  169. package/test/s41-mcp-serve-turn-span.spec.ts +0 -148
  170. package/test/s42-traceparent-propagation.spec.ts +0 -415
  171. package/test/s5.spec.ts +0 -95
  172. package/test/s6.spec.ts +0 -169
  173. package/test/s7.spec.ts +0 -136
  174. package/test/s7b-baseline.spec.ts +0 -20
  175. package/test/s9.spec.ts +0 -89
  176. package/test/sandbox-escape/j17-orchestrate.sh +0 -30
  177. package/test/sandbox-escape/run-matrix.sh +0 -98
  178. 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
- })