@coralai/sps-cli 0.65.84 → 0.65.86

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 (35) hide show
  1. package/dist/console/index.d.ts.map +1 -1
  2. package/dist/console/index.js +10 -1
  3. package/dist/console/index.js.map +1 -1
  4. package/dist/console/routes/projects.d.ts.map +1 -1
  5. package/dist/console/routes/projects.js +47 -0
  6. package/dist/console/routes/projects.js.map +1 -1
  7. package/dist/console/routes/templates.d.ts +16 -0
  8. package/dist/console/routes/templates.d.ts.map +1 -0
  9. package/dist/console/routes/templates.js +78 -0
  10. package/dist/console/routes/templates.js.map +1 -0
  11. package/dist/core/skills/configure.d.ts +2 -0
  12. package/dist/core/skills/configure.d.ts.map +1 -1
  13. package/dist/core/skills/configure.js +8 -5
  14. package/dist/core/skills/configure.js.map +1 -1
  15. package/dist/core/skills/distribution.d.ts +4 -1
  16. package/dist/core/skills/distribution.d.ts.map +1 -1
  17. package/dist/core/skills/distribution.js +48 -3
  18. package/dist/core/skills/distribution.js.map +1 -1
  19. package/dist/core/skills/policy.d.ts +3 -1
  20. package/dist/core/skills/policy.d.ts.map +1 -1
  21. package/dist/core/skills/policy.js +4 -2
  22. package/dist/core/skills/policy.js.map +1 -1
  23. package/dist/core/templates/scaffold.d.ts +55 -0
  24. package/dist/core/templates/scaffold.d.ts.map +1 -0
  25. package/dist/core/templates/scaffold.js +162 -0
  26. package/dist/core/templates/scaffold.js.map +1 -0
  27. package/dist/core/templates/templateDigest.d.ts +16 -0
  28. package/dist/core/templates/templateDigest.d.ts.map +1 -0
  29. package/dist/core/templates/templateDigest.js +57 -0
  30. package/dist/core/templates/templateDigest.js.map +1 -0
  31. package/dist/core/templates/templatePackage.d.ts +100 -0
  32. package/dist/core/templates/templatePackage.d.ts.map +1 -0
  33. package/dist/core/templates/templatePackage.js +298 -0
  34. package/dist/core/templates/templatePackage.js.map +1 -0
  35. package/package.json +2 -1
@@ -0,0 +1,298 @@
1
+ /**
2
+ * @module core/templates/templatePackage
3
+ * @description 模板包的解包 / 校验 / 落盘。**收别人的 tar = 收不可信输入**,安全全在这一处。
4
+ * @layer core
5
+ * @boundedContext templates
6
+ *
7
+ * 解包在**内存里**完成、校验全过之后才落盘 —— 边解边写会让"校验失败"留下半棵树。
8
+ * 内存用量由下面的上限兜住。
9
+ */
10
+ import { createHash } from 'node:crypto';
11
+ import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
12
+ import { dirname, join, resolve } from 'node:path';
13
+ import { list as tarList } from 'tar';
14
+ import { templateId, templateTreeDigest } from './templateDigest.js';
15
+ /** 解包上限。超限一律拒绝,并**说清超的是哪一条、当前值、上限值**(别给 "too large")。 */
16
+ export const TEMPLATE_LIMITS = {
17
+ /** 压缩包字节(路由层还有一道 bodyLimit)。 */
18
+ maxArchiveBytes: 8 * 1024 * 1024,
19
+ /** 解包后总字节。 */
20
+ maxTotalBytes: 32 * 1024 * 1024,
21
+ /** 文件条目数。 */
22
+ maxFiles: 2000,
23
+ /** 单个文件字节。 */
24
+ maxFileBytes: 8 * 1024 * 1024,
25
+ /** 解压比上限(解包后 / 压缩后)—— 防解压炸弹。 */
26
+ maxCompressionRatio: 100,
27
+ };
28
+ const err = (code, detail) => ({ ok: false, error: { code, detail } });
29
+ /**
30
+ * 路径安全:必须是相对路径、不含 `..` 段、不以 `/` 开头、无空段、无盘符。
31
+ * 🔴 用**段级**判断,不用字符串 startsWith —— `..foo` 合法而 `a/../../b` 不合法,
32
+ * 只看前缀两者会判反。
33
+ */
34
+ export function isSafeRelPath(p) {
35
+ if (!p || p.startsWith('/') || p.includes('\0') || /^[A-Za-z]:/.test(p))
36
+ return false;
37
+ if (p.endsWith('/'))
38
+ return false;
39
+ const segs = p.split('/');
40
+ return segs.every((s) => s.length > 0 && s !== '.' && s !== '..');
41
+ }
42
+ /**
43
+ * tar 条目路径归一:去掉前导 `./`、压掉重复 `/`、反斜杠转正斜杠。
44
+ *
45
+ * 🔴 **不归一就会把好包也拒掉**:`tar czf x.tgz -C dir .` 产出的条目全是 `./foo` ——
46
+ * 那是最常见的打包姿势。实测踩到过:三个恶意包全被拒,但 symlink / 炸弹两个是栽在 `./` 上,
47
+ * **它们各自那道守卫根本没被执行到**(假绿)。归一之后才轮得到真正该拒它们的那一条。
48
+ */
49
+ export function normalizeEntryPath(raw) {
50
+ let p = raw.replace(/\\/g, '/').replace(/\/{2,}/g, '/');
51
+ while (p.startsWith('./'))
52
+ p = p.slice(2);
53
+ return p;
54
+ }
55
+ function parseManifest(raw) {
56
+ let obj;
57
+ try {
58
+ obj = JSON.parse(raw.toString('utf-8'));
59
+ }
60
+ catch (e) {
61
+ return { ok: false, detail: `template.json 不是合法 JSON:${e instanceof Error ? e.message : String(e)}` };
62
+ }
63
+ if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
64
+ return { ok: false, detail: 'template.json 必须是对象' };
65
+ }
66
+ const o = obj;
67
+ const engine = o.engine;
68
+ if (typeof engine !== 'string' || !/^[A-Za-z0-9_-]{1,64}$/.test(engine)) {
69
+ return { ok: false, detail: 'engine 必须匹配 [A-Za-z0-9_-]{1,64}' };
70
+ }
71
+ const arr = (key) => {
72
+ const v = o[key];
73
+ if (v === undefined)
74
+ return [];
75
+ if (!Array.isArray(v) || v.some((x) => typeof x !== 'string'))
76
+ return null;
77
+ return v;
78
+ };
79
+ const vars = arr('vars');
80
+ const render = arr('render');
81
+ const replaceable = arr('replaceable');
82
+ const exec = arr('exec');
83
+ if (!vars || !render || !replaceable || !exec) {
84
+ return { ok: false, detail: 'vars / render / replaceable / exec 必须是 string[]' };
85
+ }
86
+ // 🔴 模板作者也是不可信输入:声明里的路径同样要过安全校验。
87
+ for (const [key, list] of [['render', render], ['replaceable', replaceable], ['exec', exec]]) {
88
+ for (const p of list) {
89
+ if (!isSafeRelPath(p))
90
+ return { ok: false, detail: `${key} 含非法路径:${JSON.stringify(p)}` };
91
+ }
92
+ }
93
+ for (const v of vars) {
94
+ if (!/^[A-Z][A-Z0-9_]*$/.test(v))
95
+ return { ok: false, detail: `变量名必须是 [A-Z][A-Z0-9_]*:${JSON.stringify(v)}` };
96
+ }
97
+ return { ok: true, value: { engine, vars, render, replaceable, exec } };
98
+ }
99
+ /** 收集 tar 条目到内存(边收边判上限);拒绝一切非普通文件的条目。 */
100
+ async function readEntries(archive) {
101
+ const files = new Map();
102
+ let total = 0;
103
+ let fatal = null;
104
+ await new Promise((done) => {
105
+ const parser = tarList({
106
+ onentry(entry) {
107
+ if (fatal) {
108
+ entry.resume();
109
+ return;
110
+ }
111
+ const type = String(entry.type);
112
+ // 🔴 只收普通文件。软链/硬链/设备/FIFO 一概拒 —— 软链条目是解包逃逸的经典入口
113
+ // (链指向 /etc,后续写入就落到链外)。目录条目不需要:落盘时按文件路径 mkdir -p。
114
+ if (type === 'Directory') {
115
+ entry.resume();
116
+ return;
117
+ } // 目录不进指纹,落盘时按需 mkdir -p
118
+ if (type !== 'File' && type !== 'OldFile' && type !== 'ContiguousFile') {
119
+ fatal = { code: 'UNSAFE_ENTRY', detail: `拒绝非普通文件条目:${entry.path}(type=${type})` };
120
+ entry.resume();
121
+ return;
122
+ }
123
+ const p = normalizeEntryPath(String(entry.path));
124
+ if (!isSafeRelPath(p)) {
125
+ fatal = { code: 'UNSAFE_ENTRY', detail: `拒绝不安全路径:${JSON.stringify(p)}(不许 ..、绝对路径、空段)` };
126
+ entry.resume();
127
+ return;
128
+ }
129
+ if (files.size + 1 > TEMPLATE_LIMITS.maxFiles) {
130
+ fatal = { code: 'LIMIT_EXCEEDED', detail: `文件数超限:> ${TEMPLATE_LIMITS.maxFiles}(上限 ${TEMPLATE_LIMITS.maxFiles})` };
131
+ entry.resume();
132
+ return;
133
+ }
134
+ const chunks = [];
135
+ let size = 0;
136
+ entry.on('data', (c) => {
137
+ if (fatal)
138
+ return;
139
+ size += c.length;
140
+ total += c.length;
141
+ if (size > TEMPLATE_LIMITS.maxFileBytes) {
142
+ fatal = { code: 'LIMIT_EXCEEDED', detail: `单文件超限:${p} 已达 ${size} 字节(上限 ${TEMPLATE_LIMITS.maxFileBytes})` };
143
+ return;
144
+ }
145
+ if (total > TEMPLATE_LIMITS.maxTotalBytes) {
146
+ fatal = { code: 'LIMIT_EXCEEDED', detail: `解包后总字节超限:已达 ${total}(上限 ${TEMPLATE_LIMITS.maxTotalBytes})` };
147
+ return;
148
+ }
149
+ chunks.push(c);
150
+ });
151
+ entry.on('end', () => {
152
+ if (fatal)
153
+ return;
154
+ files.set(p, { content: Buffer.concat(chunks), tarExec: (Number(entry.mode ?? 0) & 0o111) !== 0 });
155
+ });
156
+ },
157
+ });
158
+ parser.on('error', (e) => {
159
+ if (!fatal)
160
+ fatal = { code: 'BAD_ARCHIVE', detail: `解包失败:${e.message}` };
161
+ done();
162
+ });
163
+ parser.on('end', () => done());
164
+ parser.end(archive);
165
+ });
166
+ if (fatal)
167
+ return { ok: false, error: fatal };
168
+ return { ok: true, files, total };
169
+ }
170
+ /**
171
+ * 解包 + 校验 + 算指纹。**不落盘** —— 调用方拿到 UnpackedTemplate 后自行决定存不存。
172
+ */
173
+ export async function unpackTemplate(archive) {
174
+ if (archive.length > TEMPLATE_LIMITS.maxArchiveBytes) {
175
+ return err('ARCHIVE_TOO_LARGE', `压缩包 ${archive.length} 字节,超过上限 ${TEMPLATE_LIMITS.maxArchiveBytes}`);
176
+ }
177
+ const read = await readEntries(archive);
178
+ if (!read.ok)
179
+ return { ok: false, error: read.error };
180
+ const { files, total } = read;
181
+ // 解压比:防炸弹。放在收完之后判(收的过程已被总字节上限兜住,不会 OOM)。
182
+ const ratio = archive.length > 0 ? total / archive.length : 0;
183
+ if (ratio > TEMPLATE_LIMITS.maxCompressionRatio) {
184
+ return err('LIMIT_EXCEEDED', `解压比 ${ratio.toFixed(1)}:1 超限(压缩后 ${archive.length} → 解包后 ${total},上限 ${TEMPLATE_LIMITS.maxCompressionRatio}:1)`);
185
+ }
186
+ const manifestRaw = files.get('template.json');
187
+ if (!manifestRaw)
188
+ return err('MANIFEST_INVALID', '包根缺 template.json');
189
+ const parsed = parseManifest(manifestRaw.content);
190
+ if (!parsed.ok)
191
+ return err('MANIFEST_INVALID', parsed.detail);
192
+ const manifest = parsed.value;
193
+ const missing = [...manifest.render, ...manifest.exec].filter((p) => !files.has(p));
194
+ if (missing.length) {
195
+ return err('MANIFEST_INVALID', `render / exec 指向包里不存在的文件:${missing.join(', ')}`);
196
+ }
197
+ // 🔴 执行位的真源是 exec 声明。tar 里有执行位却没声明 → **当场 422**,
198
+ // 否则"忘了声明"会变成静默降级(文件拷过去没执行位 ⇒ hook 打不上 ACK 标签 ⇒ 每次构建必死,
199
+ // 而症状看起来像超时不像权限)。
200
+ const execSet = new Set(manifest.exec);
201
+ const undeclared = [...files.entries()].filter(([p, f]) => f.tarExec && !execSet.has(p)).map(([p]) => p);
202
+ if (undeclared.length) {
203
+ return err('EXEC_UNDECLARED', `这些文件在 tar 里带执行位但不在 template.json 的 exec 声明里:${undeclared.join(', ')}` +
204
+ '(执行位以声明为准;把它们加进 exec,或去掉执行位后重新打包)');
205
+ }
206
+ const entries = [...files.entries()].map(([path, f]) => ({
207
+ path,
208
+ content: f.content,
209
+ executable: execSet.has(path),
210
+ }));
211
+ return {
212
+ ok: true,
213
+ value: {
214
+ manifest,
215
+ files: entries,
216
+ digest: templateTreeDigest(entries),
217
+ id: templateId(manifest.engine, entries),
218
+ totalBytes: total,
219
+ },
220
+ };
221
+ }
222
+ // ─── 落盘 ────────────────────────────────────────────────────────────
223
+ /** `~/.coral/templates` —— 每次调用现读 HOME(与 runtimePaths 同惯例,方便测试)。 */
224
+ export function templatesRoot() {
225
+ return resolve(process.env.HOME ?? '/home/coral', '.coral', 'templates');
226
+ }
227
+ export function templateDir(id) {
228
+ return join(templatesRoot(), id);
229
+ }
230
+ export function isTemplateRegistered(id) {
231
+ return existsSync(join(templateDir(id), 'template.json'));
232
+ }
233
+ /**
234
+ * 落盘。**先写临时目录再整体 rename** —— 半棵树被别人读到,比没有更糟
235
+ * (调用方会以为注册成功)。同 id 已存在 = 幂等,直接返回。
236
+ */
237
+ export function storeTemplate(t) {
238
+ const dir = templateDir(t.id);
239
+ if (isTemplateRegistered(t.id))
240
+ return { stored: false, dir };
241
+ const tmp = `${dir}.tmp-${process.pid}-${createHash('sha256').update(t.id).digest('hex').slice(0, 8)}`;
242
+ rmSync(tmp, { recursive: true, force: true });
243
+ mkdirSync(tmp, { recursive: true });
244
+ for (const f of t.files) {
245
+ const abs = join(tmp, f.path);
246
+ mkdirSync(dirname(abs), { recursive: true });
247
+ writeFileSync(abs, f.content, { mode: f.executable ? 0o755 : 0o644 });
248
+ }
249
+ mkdirSync(templatesRoot(), { recursive: true });
250
+ try {
251
+ renameSync(tmp, dir);
252
+ }
253
+ catch {
254
+ // 并发下别人先 rename 到位了 → 幂等成功,清掉自己的临时树。
255
+ rmSync(tmp, { recursive: true, force: true });
256
+ return { stored: false, dir };
257
+ }
258
+ return { stored: true, dir };
259
+ }
260
+ /** 读回已注册模板的文件树(scaffold 用)。未注册 → null。 */
261
+ export function loadTemplate(id) {
262
+ const dir = templateDir(id);
263
+ const manifestPath = join(dir, 'template.json');
264
+ if (!existsSync(manifestPath))
265
+ return null;
266
+ const parsed = parseManifest(readFileSync(manifestPath));
267
+ if (!parsed.ok)
268
+ return null;
269
+ const execSet = new Set(parsed.value.exec);
270
+ const files = [];
271
+ const walk = (abs, rel) => {
272
+ for (const e of readdirSync(abs, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
273
+ const childAbs = join(abs, e.name);
274
+ const childRel = rel ? `${rel}/${e.name}` : e.name;
275
+ if (e.isDirectory()) {
276
+ walk(childAbs, childRel);
277
+ continue;
278
+ }
279
+ if (!e.isFile())
280
+ continue; // 落盘的树里不该有软链;有也不读
281
+ files.push({ path: childRel, content: readFileSync(childAbs), executable: execSet.has(childRel) });
282
+ }
283
+ };
284
+ walk(dir, '');
285
+ return { manifest: parsed.value, files };
286
+ }
287
+ /** 已注册模板的摘要(GET /api/templates/:id)。 */
288
+ export function templateSummary(id) {
289
+ const t = loadTemplate(id);
290
+ if (!t)
291
+ return null;
292
+ const dir = templateDir(id);
293
+ let bytes = 0;
294
+ for (const f of t.files)
295
+ bytes += statSync(join(dir, f.path)).size;
296
+ return { id, engine: t.manifest.engine, files: t.files.length, bytes };
297
+ }
298
+ //# sourceMappingURL=templatePackage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templatePackage.js","sourceRoot":"","sources":["../../../src/core/templates/templatePackage.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coralai/sps-cli",
3
- "version": "0.65.84",
3
+ "version": "0.65.86",
4
4
  "description": "SPS CLI — AI-driven development pipeline orchestrator",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",
@@ -74,6 +74,7 @@
74
74
  "open": "^11.0.0",
75
75
  "openai": "^6.45.0",
76
76
  "sharp": "^0.35.3",
77
+ "tar": "^7.5.22",
77
78
  "yaml": "^2.8.3",
78
79
  "zod": "^4.4.3"
79
80
  },