@dzhechkov/harness-core 0.3.124 → 0.3.126
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/.dz-manifest.json +1485 -0
- package/README.md +3 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/release.d.ts +206 -0
- package/dist/release.d.ts.map +1 -0
- package/dist/release.js +509 -0
- package/dist/release.js.map +1 -0
- package/dist/sign.d.ts +6 -0
- package/dist/sign.d.ts.map +1 -1
- package/dist/sign.js +33 -0
- package/dist/sign.js.map +1 -1
- package/package.json +8 -6
- package/sbom.json +3703 -0
- package/src/index.ts +32 -0
- package/src/release.ts +692 -0
- package/src/sign.ts +29 -0
package/dist/release.js
ADDED
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verified-release engine (`dz release`, feature release-verified, ADR-001).
|
|
3
|
+
*
|
|
4
|
+
* VERIFY phase of the DETECT→VERIFY→ANALYZE→RELEASE conveyor (grounded in open-claude-code
|
|
5
|
+
* ADR-003 nightly-verified-release): four HARD gates — tests / audit / syntax / smoke-boot —
|
|
6
|
+
* planned and classified here as PURE functions over injected data, executed only by the CLI.
|
|
7
|
+
*
|
|
8
|
+
* Architecture contract (ADR-001, D1–D4):
|
|
9
|
+
* - NO `node:child_process` anywhere in this file — the engine plans commands as DATA
|
|
10
|
+
* (`GateStep.cmd` strings a test can assert, `publishArgv` precedent) and classifies
|
|
11
|
+
* injected execution results. The CLI (`cmdRelease`) is the single executor.
|
|
12
|
+
* - The only fs access lives in {@link collectPackageFacts} (readFileSync/readdirSync/statSync,
|
|
13
|
+
* `discoverPackages` precedent); everything downstream of the facts is pure.
|
|
14
|
+
* - The existing publish gates (guard, claim-check, signature, provenance, files-whitelist)
|
|
15
|
+
* are NEVER duplicated here: a green release hands off to the untouched `dz publish`,
|
|
16
|
+
* and an anti-duplication test greps every planned command for gate keywords.
|
|
17
|
+
* - Fail-closed: any `fail` ⇒ `publishAction: 'blocked'`; a planned-but-unexecuted step is a
|
|
18
|
+
* FAILURE (an under-executed plan can never pass); all-skip is NOT `proceed` (nothing
|
|
19
|
+
* verified is not verified).
|
|
20
|
+
*
|
|
21
|
+
* @packageDocumentation
|
|
22
|
+
*/
|
|
23
|
+
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
24
|
+
import { join } from 'node:path';
|
|
25
|
+
import { discoverPackages, orderByDependencies } from './publish.js';
|
|
26
|
+
/** Order the CLI executes and the verdict reports gates in. */
|
|
27
|
+
export const RELEASE_GATE_ORDER = ['tests', 'audit', 'syntax', 'smoke'];
|
|
28
|
+
/** Default per-step timeouts (NFR-4: a hung child is a classified failure, not a hung release). */
|
|
29
|
+
export const RELEASE_TIMEOUTS = {
|
|
30
|
+
testMs: 600_000,
|
|
31
|
+
auditMs: 120_000,
|
|
32
|
+
syntaxMs: 30_000,
|
|
33
|
+
smokeMs: 20_000,
|
|
34
|
+
};
|
|
35
|
+
/* ------------------------------------------------------------------ */
|
|
36
|
+
/* DETECT — facts collection (the only fs in this file) */
|
|
37
|
+
/* ------------------------------------------------------------------ */
|
|
38
|
+
/** Recursively list `*.js` files under `dir`, returned relative to `base`. */
|
|
39
|
+
function listJsFiles(base, dir) {
|
|
40
|
+
const out = [];
|
|
41
|
+
let entries;
|
|
42
|
+
try {
|
|
43
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return out; // unreadable dir → no files (dist absence is reported by the plan, not here)
|
|
47
|
+
}
|
|
48
|
+
for (const e of entries) {
|
|
49
|
+
const full = join(dir, e.name);
|
|
50
|
+
if (e.isDirectory())
|
|
51
|
+
out.push(...listJsFiles(base, full));
|
|
52
|
+
else if (e.isFile() && e.name.endsWith('.js'))
|
|
53
|
+
out.push(full.slice(base.length + 1));
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
/** Newest file mtime (ms) under `dir`, recursively; 0 when empty/unreadable. */
|
|
58
|
+
function newestMtime(dir) {
|
|
59
|
+
let newest = 0;
|
|
60
|
+
let entries;
|
|
61
|
+
try {
|
|
62
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return newest;
|
|
66
|
+
}
|
|
67
|
+
for (const e of entries) {
|
|
68
|
+
const full = join(dir, e.name);
|
|
69
|
+
try {
|
|
70
|
+
if (e.isDirectory())
|
|
71
|
+
newest = Math.max(newest, newestMtime(full));
|
|
72
|
+
else if (e.isFile())
|
|
73
|
+
newest = Math.max(newest, statSync(full).mtimeMs);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
/* raced/unreadable entry — skip */
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return newest;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Gather {@link ReleasePackageFacts} for the release set: `discoverPackages` +
|
|
83
|
+
* `orderByDependencies` (imported from publish — reuse, never copy: G9) plus each package's
|
|
84
|
+
* `scripts.test` / `bin` / `dist/**\/*.js` and dist-vs-src staleness (AM-3 input).
|
|
85
|
+
*
|
|
86
|
+
* `filter` mirrors `dz publish --filter` substring semantics (name OR dir); an explicitly
|
|
87
|
+
* empty filter is REJECTED (throws) — "match all on empty" was the publish P0 this mirrors.
|
|
88
|
+
*
|
|
89
|
+
* Failure contract (load-bearing path — fail FAST, not open): a corrupt `package.json`
|
|
90
|
+
* throws up to the caller; a missing/foreign root degrades to `[]` per the
|
|
91
|
+
* `discoverPackages` contract (the CLI reports "no publishable packages" and exits non-zero).
|
|
92
|
+
*/
|
|
93
|
+
export function collectPackageFacts(monorepoRoot, filter) {
|
|
94
|
+
if (filter !== undefined && filter.length === 0) {
|
|
95
|
+
throw new Error('release: --filter requires a non-empty list of package-name substrings (empty would match ALL packages)');
|
|
96
|
+
}
|
|
97
|
+
const discovered = discoverPackages(monorepoRoot);
|
|
98
|
+
const selected = filter === undefined ? discovered : discovered.filter((p) => filter.some((f) => p.name.includes(f) || p.dir.includes(f)));
|
|
99
|
+
const ordered = orderByDependencies(selected);
|
|
100
|
+
return ordered.map((p) => {
|
|
101
|
+
const pkgJson = JSON.parse(readFileSync(join(p.dir, 'package.json'), 'utf-8'));
|
|
102
|
+
const bins = [];
|
|
103
|
+
if (typeof pkgJson.bin === 'string') {
|
|
104
|
+
// `"bin": "cli.js"` — bin name defaults to the package basename; path may lack `./` (G3).
|
|
105
|
+
const rel = pkgJson.bin.replace(/^\.\//, '');
|
|
106
|
+
const abs = join(p.dir, rel);
|
|
107
|
+
bins.push({ name: p.name.split('/').pop() ?? p.name, path: abs, exists: existsSync(abs) });
|
|
108
|
+
}
|
|
109
|
+
else if (pkgJson.bin !== undefined && pkgJson.bin !== null && typeof pkgJson.bin === 'object') {
|
|
110
|
+
for (const [name, relRaw] of Object.entries(pkgJson.bin)) {
|
|
111
|
+
const rel = String(relRaw).replace(/^\.\//, '');
|
|
112
|
+
const abs = join(p.dir, rel);
|
|
113
|
+
bins.push({ name, path: abs, exists: existsSync(abs) });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const distDir = join(p.dir, 'dist');
|
|
117
|
+
const srcDir = join(p.dir, 'src');
|
|
118
|
+
const distJs = existsSync(distDir) ? listJsFiles(p.dir, distDir).sort() : [];
|
|
119
|
+
let srcNewerThanDist;
|
|
120
|
+
if (existsSync(distDir) && existsSync(srcDir)) {
|
|
121
|
+
srcNewerThanDist = newestMtime(srcDir) > newestMtime(distDir);
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
name: p.name,
|
|
125
|
+
dir: p.dir,
|
|
126
|
+
version: p.version,
|
|
127
|
+
hasTestScript: typeof pkgJson.scripts?.['test'] === 'string' && pkgJson.scripts['test'].trim().length > 0,
|
|
128
|
+
hasBuildScript: typeof pkgJson.scripts?.['build'] === 'string' && pkgJson.scripts['build'].trim().length > 0,
|
|
129
|
+
bins,
|
|
130
|
+
distJs,
|
|
131
|
+
srcNewerThanDist,
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* AM-8: affected-package selection is a PURE function of an injected changed-file list.
|
|
137
|
+
* `null` (diff unavailable), an empty list, or a list matching zero packages all FAIL OPEN
|
|
138
|
+
* to the full set — a release can never pass on zero verified packages.
|
|
139
|
+
*/
|
|
140
|
+
export function selectAffectedPackages(changedFiles, facts) {
|
|
141
|
+
if (changedFiles === null || changedFiles.length === 0)
|
|
142
|
+
return [...facts];
|
|
143
|
+
const norm = (s) => s.replace(/\\/g, '/');
|
|
144
|
+
const affected = facts.filter((f) => {
|
|
145
|
+
const dir = norm(f.dir).replace(/\/$/, '');
|
|
146
|
+
const tail = dir.split('/').slice(-3).join('/'); // packages/@dzhechkov/<name>
|
|
147
|
+
return changedFiles.some((file) => {
|
|
148
|
+
const nf = norm(String(file));
|
|
149
|
+
return nf.startsWith(dir + '/') || nf === dir || nf.includes(tail + '/');
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
return affected.length === 0 ? [...facts] : affected;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Plan the four gates from injected facts. Pure: same facts ⇒ byte-identical plan; nothing
|
|
156
|
+
* is executed; every command is an assertable string. Anti-duplication (ADR D1): no step may
|
|
157
|
+
* re-enact a publish gate — the dedicated test greps `cmd`s for guard/claim/sign/provenance.
|
|
158
|
+
*/
|
|
159
|
+
export function planReleaseGates(facts, opts) {
|
|
160
|
+
const steps = [];
|
|
161
|
+
const skips = [];
|
|
162
|
+
const t = {
|
|
163
|
+
tests: opts.testTimeoutMs ?? RELEASE_TIMEOUTS.testMs,
|
|
164
|
+
audit: opts.auditTimeoutMs ?? RELEASE_TIMEOUTS.auditMs,
|
|
165
|
+
syntax: opts.syntaxTimeoutMs ?? RELEASE_TIMEOUTS.syntaxMs,
|
|
166
|
+
smoke: opts.smokeTimeoutMs ?? RELEASE_TIMEOUTS.smokeMs,
|
|
167
|
+
};
|
|
168
|
+
// Gate 1 — tests: the package's FULL suite via its own `test` script (pnpm test → vitest run).
|
|
169
|
+
for (const f of facts) {
|
|
170
|
+
if (f.hasTestScript) {
|
|
171
|
+
steps.push({
|
|
172
|
+
id: `tests:${f.name}`,
|
|
173
|
+
gate: 'tests',
|
|
174
|
+
pkg: f.name,
|
|
175
|
+
cmd: 'pnpm test',
|
|
176
|
+
cwd: f.dir,
|
|
177
|
+
timeoutMs: t.tests,
|
|
178
|
+
reason: 'full package test suite must pass',
|
|
179
|
+
kind: 'exec',
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
// AM-2: an explicit, named skip — never a silent pass.
|
|
184
|
+
skips.push({
|
|
185
|
+
gate: 'tests',
|
|
186
|
+
pkg: f.name,
|
|
187
|
+
reason: 'no "test" script in package.json — nothing was verified for this package',
|
|
188
|
+
class: 'SKIP_NO_TEST_SCRIPT',
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Gate 2 — audit: ONE workspace-level step (AM-1: pnpm primary; npm only without pnpm-lock).
|
|
193
|
+
const dev = opts.includeDevDeps === true;
|
|
194
|
+
steps.push({
|
|
195
|
+
id: 'audit:workspace',
|
|
196
|
+
gate: 'audit',
|
|
197
|
+
cmd: opts.pnpmLockPresent
|
|
198
|
+
? `pnpm audit${dev ? '' : ' --prod'} --audit-level high`
|
|
199
|
+
: `npm audit${dev ? '' : ' --omit=dev'} --audit-level=high`,
|
|
200
|
+
cwd: opts.monorepoRoot,
|
|
201
|
+
timeoutMs: t.audit,
|
|
202
|
+
reason: dev
|
|
203
|
+
? 'no >=high advisories across ALL workspace dependencies (dev included via --audit-dev)'
|
|
204
|
+
: 'no >=high advisories in production dependencies (dev-only chains excluded — widen with --audit-dev)',
|
|
205
|
+
kind: 'exec',
|
|
206
|
+
});
|
|
207
|
+
// Gates 3+4 — per package. AM-3: a stale dist is NEVER checked/booted as-is.
|
|
208
|
+
for (const f of facts) {
|
|
209
|
+
if (f.srcNewerThanDist === true) {
|
|
210
|
+
steps.push({
|
|
211
|
+
id: `syntax:${f.name}:stale-dist`,
|
|
212
|
+
gate: 'syntax',
|
|
213
|
+
pkg: f.name,
|
|
214
|
+
cmd: '',
|
|
215
|
+
cwd: f.dir,
|
|
216
|
+
timeoutMs: 0,
|
|
217
|
+
reason: 'dist/ is OLDER than src/ — rebuild before release; a stale dist is not checked as-is',
|
|
218
|
+
kind: 'synthetic-fail',
|
|
219
|
+
failClass: 'STALE_DIST',
|
|
220
|
+
});
|
|
221
|
+
if (f.bins.length > 0) {
|
|
222
|
+
steps.push({
|
|
223
|
+
id: `smoke:${f.name}:stale-dist`,
|
|
224
|
+
gate: 'smoke',
|
|
225
|
+
pkg: f.name,
|
|
226
|
+
cmd: '',
|
|
227
|
+
cwd: f.dir,
|
|
228
|
+
timeoutMs: 0,
|
|
229
|
+
reason: 'dist/ is OLDER than src/ — rebuild before release; a stale bin is not booted as-is',
|
|
230
|
+
kind: 'synthetic-fail',
|
|
231
|
+
failClass: 'STALE_DIST',
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
// AM-10 — the fail-closed INVERSE of AM-3: a package that DECLARES a build but has zero
|
|
237
|
+
// dist JS was never built — zero syntax/smoke steps must read as a FAILURE, never as a
|
|
238
|
+
// clean gate (the dead-SKIP_NO_ARTIFACTS defect Step-8 QE + the delivery gate both caught).
|
|
239
|
+
// A pack with no build script, no artifacts and no bins is a template-only pack: an honest
|
|
240
|
+
// NAMED skip (AM-2), never a silent zero-step pass.
|
|
241
|
+
if (f.distJs.length === 0) {
|
|
242
|
+
if (f.hasBuildScript === true) {
|
|
243
|
+
steps.push({
|
|
244
|
+
id: `syntax:${f.name}:missing-dist`,
|
|
245
|
+
gate: 'syntax',
|
|
246
|
+
pkg: f.name,
|
|
247
|
+
cmd: '',
|
|
248
|
+
cwd: f.dir,
|
|
249
|
+
timeoutMs: 0,
|
|
250
|
+
reason: 'package declares a "build" script but dist/ contains no JS — build before release; an unbuilt package must be impossible to ship',
|
|
251
|
+
kind: 'synthetic-fail',
|
|
252
|
+
failClass: 'MISSING_DIST',
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
else if (f.bins.length === 0) {
|
|
256
|
+
skips.push({
|
|
257
|
+
gate: 'syntax',
|
|
258
|
+
pkg: f.name,
|
|
259
|
+
reason: 'no dist/ JS, no bin, no build script — template-only pack; nothing to syntax-check or boot',
|
|
260
|
+
class: 'SKIP_NO_ARTIFACTS',
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// Gate 3 — syntax: node --check every dist/**/*.js and every existing bin file (deduped).
|
|
265
|
+
const checked = new Set();
|
|
266
|
+
for (const rel of f.distJs) {
|
|
267
|
+
const abs = join(f.dir, rel);
|
|
268
|
+
checked.add(abs);
|
|
269
|
+
steps.push({
|
|
270
|
+
id: `syntax:${f.name}:${rel}`,
|
|
271
|
+
gate: 'syntax',
|
|
272
|
+
pkg: f.name,
|
|
273
|
+
cmd: `node --check "${abs}"`,
|
|
274
|
+
cwd: f.dir,
|
|
275
|
+
timeoutMs: t.syntax,
|
|
276
|
+
reason: `dist file must parse (${rel})`,
|
|
277
|
+
kind: 'exec',
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
for (const bin of f.bins) {
|
|
281
|
+
if (bin.exists && !checked.has(bin.path)) {
|
|
282
|
+
checked.add(bin.path);
|
|
283
|
+
steps.push({
|
|
284
|
+
id: `syntax:${f.name}:bin:${bin.name}`,
|
|
285
|
+
gate: 'syntax',
|
|
286
|
+
pkg: f.name,
|
|
287
|
+
cmd: `node --check "${bin.path}"`,
|
|
288
|
+
cwd: f.dir,
|
|
289
|
+
timeoutMs: t.syntax,
|
|
290
|
+
reason: `bin file must parse (${bin.name})`,
|
|
291
|
+
kind: 'exec',
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// Gate 4 — smoke-boot: node <bin> --help, DIRECT node (never npx: signals reach the wrapper,
|
|
296
|
+
// not the child), temp cwd + timeout (AM-4). A missing bin file is a synthetic MISSING_BIN.
|
|
297
|
+
for (const bin of f.bins) {
|
|
298
|
+
if (!bin.exists) {
|
|
299
|
+
steps.push({
|
|
300
|
+
id: `smoke:${f.name}:${bin.name}:missing`,
|
|
301
|
+
gate: 'smoke',
|
|
302
|
+
pkg: f.name,
|
|
303
|
+
cmd: '',
|
|
304
|
+
cwd: f.dir,
|
|
305
|
+
timeoutMs: 0,
|
|
306
|
+
reason: `bin "${bin.name}" points at ${bin.path} which does not exist — build before release`,
|
|
307
|
+
kind: 'synthetic-fail',
|
|
308
|
+
failClass: 'MISSING_BIN',
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
steps.push({
|
|
313
|
+
id: `smoke:${f.name}:${bin.name}`,
|
|
314
|
+
gate: 'smoke',
|
|
315
|
+
pkg: f.name,
|
|
316
|
+
cmd: `node "${bin.path}" --help`,
|
|
317
|
+
cwd: f.dir,
|
|
318
|
+
timeoutMs: t.smoke,
|
|
319
|
+
reason: `bin "${bin.name}" must boot (--help, exit 0)`,
|
|
320
|
+
kind: 'exec',
|
|
321
|
+
tempCwd: true,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return { steps, skips, packages: facts.map((f) => f.name) };
|
|
327
|
+
}
|
|
328
|
+
/* ------------------------------------------------------------------ */
|
|
329
|
+
/* VERIFY — pure classification */
|
|
330
|
+
/* ------------------------------------------------------------------ */
|
|
331
|
+
/**
|
|
332
|
+
* AM-1: split an audit non-zero exit into VULNS_HIGH (advisories found) vs AUDIT_ERROR
|
|
333
|
+
* (audit could not run). BOTH block (fail-closed either way); only the message differs, so a
|
|
334
|
+
* misclassification is cosmetic, never a false pass. Unrecognized output ⇒ AUDIT_ERROR — we
|
|
335
|
+
* never claim "vulnerabilities found" from output we cannot read.
|
|
336
|
+
*/
|
|
337
|
+
function classifyAuditFailure(output) {
|
|
338
|
+
const text = String(output ?? '');
|
|
339
|
+
const looksLikeError = /(ERR_PNPM|npm ERR!|ENOTFOUND|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN|audit endpoint|registry .*(unreachable|error)|no .*lockfile|missing .*lockfile|cannot audit)/i.test(text);
|
|
340
|
+
const looksLikeVulns = /\d+\s+vulnerabilit(y|ies)|severity\s*[:>]|\bhigh\b.*\bvulnerabilit|advisor(y|ies)\b/i.test(text);
|
|
341
|
+
if (looksLikeVulns && !looksLikeError) {
|
|
342
|
+
return { cls: 'VULNS_HIGH', reason: 'audit found >=high advisories — fix or consciously fall back to plain dz publish' };
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
cls: 'AUDIT_ERROR',
|
|
346
|
+
reason: 'audit could not complete (network/registry/lockfile) — a gate that cannot run is NOT a passed gate',
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* One-line detail for an AUDIT failure: prefer the line that actually SUMMARIZES the
|
|
351
|
+
* advisories (pnpm/npm print it to stdout) over execSync's generic stderr "Command failed…".
|
|
352
|
+
*/
|
|
353
|
+
function auditDetailLine(stdout, stderr) {
|
|
354
|
+
const all = `${stdout == null ? '' : String(stdout)}\n${stderr == null ? '' : String(stderr)}`;
|
|
355
|
+
const summary = all
|
|
356
|
+
.split('\n')
|
|
357
|
+
.map((l) => l.trim())
|
|
358
|
+
.find((l) => /\d+\s+vulnerabilit|severity|advisor/i.test(l));
|
|
359
|
+
return (summary ?? firstLine(stdout, stderr)).slice(0, 200);
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* First non-empty output line, for one-line failure reasons; hostile input coerced safely.
|
|
363
|
+
* Exported so the CLI reuses it for gh/tag periphery messages (G9 reuse-never-copy).
|
|
364
|
+
*/
|
|
365
|
+
export function firstOutputLine(...chunks) {
|
|
366
|
+
return firstLine(...chunks);
|
|
367
|
+
}
|
|
368
|
+
function firstLine(...chunks) {
|
|
369
|
+
for (const c of chunks) {
|
|
370
|
+
const s = c == null ? '' : String(c);
|
|
371
|
+
const line = s.split('\n').find((l) => l.trim().length > 0);
|
|
372
|
+
if (line !== undefined)
|
|
373
|
+
return line.trim().slice(0, 200);
|
|
374
|
+
}
|
|
375
|
+
return '';
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Merge plan + executions into the {@link ReleaseVerdict} — the single fail-closed decision
|
|
379
|
+
* point (ADR load-bearing property):
|
|
380
|
+
*
|
|
381
|
+
* - any `fail` ⇒ `publishAction: 'blocked'`, `ok: false`;
|
|
382
|
+
* - a planned exec step with NO execution record ⇒ `UNEXECUTED_STEP` failure;
|
|
383
|
+
* - all-skip (nothing executed anywhere) ⇒ NOT `proceed` — nothing verified is not verified;
|
|
384
|
+
* - never throws on hostile input (`formatPublishError` discipline).
|
|
385
|
+
*/
|
|
386
|
+
export function classifyGateExecutions(plan, executions, now = new Date()) {
|
|
387
|
+
const byId = new Map();
|
|
388
|
+
for (const e of executions ?? []) {
|
|
389
|
+
if (e != null && typeof e.stepId === 'string')
|
|
390
|
+
byId.set(e.stepId, e);
|
|
391
|
+
}
|
|
392
|
+
const gates = RELEASE_GATE_ORDER.map((gate) => {
|
|
393
|
+
const gateSteps = (plan?.steps ?? []).filter((s) => s?.gate === gate);
|
|
394
|
+
const gateSkips = (plan?.skips ?? []).filter((s) => s?.gate === gate);
|
|
395
|
+
const failures = [];
|
|
396
|
+
let passed = 0;
|
|
397
|
+
for (const step of gateSteps) {
|
|
398
|
+
try {
|
|
399
|
+
if (step.kind === 'synthetic-fail') {
|
|
400
|
+
failures.push({ pkg: step.pkg, reason: step.reason, class: step.failClass ?? 'EXIT_NONZERO' });
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
const exec = byId.get(step.id);
|
|
404
|
+
if (exec === undefined) {
|
|
405
|
+
failures.push({
|
|
406
|
+
pkg: step.pkg,
|
|
407
|
+
reason: `planned step "${step.id}" was never executed — an under-executed plan cannot pass`,
|
|
408
|
+
class: 'UNEXECUTED_STEP',
|
|
409
|
+
});
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
if (exec.timedOut === true) {
|
|
413
|
+
failures.push({
|
|
414
|
+
pkg: step.pkg,
|
|
415
|
+
reason: `timed out after ${step.timeoutMs}ms: ${step.cmd}`,
|
|
416
|
+
class: gate === 'smoke' ? 'SMOKE_TIMEOUT' : 'TIMEOUT',
|
|
417
|
+
});
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
if (typeof exec.exitCode !== 'number' || exec.exitCode !== 0) {
|
|
421
|
+
if (gate === 'audit') {
|
|
422
|
+
const { cls, reason } = classifyAuditFailure(`${exec.stdout ?? ''}\n${exec.stderr ?? ''}`);
|
|
423
|
+
const detail = auditDetailLine(exec.stdout, exec.stderr);
|
|
424
|
+
failures.push({ pkg: step.pkg, reason: `${reason}${detail ? ` — ${detail}` : ''}`, class: cls });
|
|
425
|
+
}
|
|
426
|
+
else {
|
|
427
|
+
failures.push({
|
|
428
|
+
pkg: step.pkg,
|
|
429
|
+
reason: `exit ${String(exec.exitCode)}: ${step.cmd}${firstLine(exec.stderr, exec.stdout) ? ` — ${firstLine(exec.stderr, exec.stdout)}` : ''}`,
|
|
430
|
+
class: 'EXIT_NONZERO',
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
passed += 1;
|
|
436
|
+
}
|
|
437
|
+
catch {
|
|
438
|
+
// Hostile/malformed step or execution record: classify as failure, never throw.
|
|
439
|
+
failures.push({ pkg: step?.pkg, reason: 'unclassifiable step/execution record', class: 'EXIT_NONZERO' });
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
const status = failures.length > 0 ? 'fail' : passed > 0 ? 'pass' : 'skip';
|
|
443
|
+
return { gate, status, passed, failures, skips: gateSkips };
|
|
444
|
+
});
|
|
445
|
+
const failedGates = gates.filter((g) => g.status === 'fail');
|
|
446
|
+
const anyPass = gates.some((g) => g.status === 'pass');
|
|
447
|
+
const blockedBy = failedGates.map((g) => `${g.gate}: ${g.failures.length} failure(s) [${[...new Set(g.failures.map((f) => f.class))].join(', ')}]`);
|
|
448
|
+
if (failedGates.length === 0 && !anyPass) {
|
|
449
|
+
blockedBy.push('nothing-verified: no gate executed a single step — an all-skip run is not a verified release');
|
|
450
|
+
}
|
|
451
|
+
const ok = failedGates.length === 0 && anyPass;
|
|
452
|
+
return {
|
|
453
|
+
gates,
|
|
454
|
+
ok,
|
|
455
|
+
blockedBy,
|
|
456
|
+
skipped: plan?.skips ?? [],
|
|
457
|
+
publishAction: ok ? 'proceed' : 'blocked',
|
|
458
|
+
timestamp: now.toISOString(),
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* gh-2.4-safe `gh issue create` payload (only `--title`/`--body` are assumed downstream).
|
|
463
|
+
* Pure + deterministic for a fixed verdict — the issue is the verdict's echo, never its judge.
|
|
464
|
+
*/
|
|
465
|
+
export function buildFailureIssue(verdict, ctx = {}) {
|
|
466
|
+
const failed = verdict.gates.filter((g) => g.status === 'fail').map((g) => g.gate);
|
|
467
|
+
const title = `dz release: gate failure — ${failed.length > 0 ? failed.join(', ') : 'nothing verified'}`;
|
|
468
|
+
const lines = [
|
|
469
|
+
`Verified release blocked at ${verdict.timestamp}.`,
|
|
470
|
+
'',
|
|
471
|
+
...(ctx.invocation ? [`Invocation: \`${ctx.invocation}\``, ''] : []),
|
|
472
|
+
...(ctx.repo ? [`Repo: ${ctx.repo}`, ''] : []),
|
|
473
|
+
'## Gate verdict',
|
|
474
|
+
'',
|
|
475
|
+
];
|
|
476
|
+
for (const g of verdict.gates) {
|
|
477
|
+
const icon = g.status === 'pass' ? '✓' : g.status === 'fail' ? '✗' : '○';
|
|
478
|
+
lines.push(`- ${icon} **${g.gate}** — ${g.status} (${g.passed} passed, ${g.failures.length} failed, ${g.skips.length} skipped)`);
|
|
479
|
+
for (const f of g.failures)
|
|
480
|
+
lines.push(` - [${f.class}] ${f.pkg ? `${f.pkg}: ` : ''}${f.reason}`);
|
|
481
|
+
}
|
|
482
|
+
if (verdict.skipped.length > 0) {
|
|
483
|
+
lines.push('', '## Skipped (honestly reported, never counted as passed)', '');
|
|
484
|
+
for (const s of verdict.skipped)
|
|
485
|
+
lines.push(`- [${s.class}] ${s.pkg}: ${s.reason}`);
|
|
486
|
+
}
|
|
487
|
+
lines.push('', `Blocked by: ${verdict.blockedBy.join('; ')}`, '', '_Auto-created by `dz release` (best-effort; the release verdict is independent of this issue)._');
|
|
488
|
+
return { title, body: lines.join('\n') };
|
|
489
|
+
}
|
|
490
|
+
/** Short, bounded release notes from injected `git log --oneline`-style lines. */
|
|
491
|
+
export function buildReleaseNotes(gitLogLines, limit = 15) {
|
|
492
|
+
const bullets = (gitLogLines ?? [])
|
|
493
|
+
.map((l) => String(l ?? '').trim())
|
|
494
|
+
.filter((l) => l.length > 0)
|
|
495
|
+
.slice(0, Math.max(1, limit))
|
|
496
|
+
.map((l) => `- ${l.slice(0, 200)}`);
|
|
497
|
+
if (bullets.length === 0)
|
|
498
|
+
return 'Verified release (no commit subjects available).';
|
|
499
|
+
return `Verified release — recent changes:\n${bullets.join('\n')}`;
|
|
500
|
+
}
|
|
501
|
+
/** Deterministic tag name from injected data: `release-<yyyymmdd>-<shortsha>`. */
|
|
502
|
+
export function releaseTagName(now, shortSha) {
|
|
503
|
+
const y = now.getUTCFullYear();
|
|
504
|
+
const m = String(now.getUTCMonth() + 1).padStart(2, '0');
|
|
505
|
+
const d = String(now.getUTCDate()).padStart(2, '0');
|
|
506
|
+
const sha = String(shortSha ?? '').replace(/[^0-9a-zA-Z]/g, '').slice(0, 12);
|
|
507
|
+
return sha.length > 0 ? `release-${y}${m}${d}-${sha}` : `release-${y}${m}${d}`;
|
|
508
|
+
}
|
|
509
|
+
//# sourceMappingURL=release.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release.js","sourceRoot":"","sources":["../src/release.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE1E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAKrE,+DAA+D;AAC/D,MAAM,CAAC,MAAM,kBAAkB,GAA6B,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AA0HlG,mGAAmG;AACnG,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,MAAM,EAAE,OAAO;IACf,OAAO,EAAE,OAAO;IAChB,QAAQ,EAAE,MAAM;IAChB,OAAO,EAAE,MAAM;CACP,CAAC;AAEX,wEAAwE;AACxE,yEAAyE;AACzE,wEAAwE;AAExE,8EAA8E;AAC9E,SAAS,WAAW,CAAC,IAAY,EAAE,GAAW;IAC5C,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC,CAAC,6EAA6E;IAC3F,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,CAAC,WAAW,EAAE;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;aACrD,IAAI,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gFAAgF;AAChF,SAAS,WAAW,CAAC,GAAW;IAC9B,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC;YACH,IAAI,CAAC,CAAC,WAAW,EAAE;gBAAE,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;iBAC7D,IAAI,CAAC,CAAC,MAAM,EAAE;gBAAE,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;QACzE,CAAC;QAAC,MAAM,CAAC;YACP,mCAAmC;QACrC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CAAC,YAAoB,EAAE,MAA0B;IAClF,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,yGAAyG,CAAC,CAAC;IAC7H,CAAC;IACD,MAAM,UAAU,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;IAClD,MAAM,QAAQ,GACZ,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5H,MAAM,OAAO,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAE9C,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAI5E,CAAC;QACF,MAAM,IAAI,GAAsB,EAAE,CAAC;QACnC,IAAI,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YACpC,0FAA0F;YAC1F,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAC7B,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7F,CAAC;aAAM,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,KAAK,IAAI,IAAI,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YAChG,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzD,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBAChD,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBAC7B,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7E,IAAI,gBAAqC,CAAC;QAC1C,IAAI,UAAU,CAAC,OAAO,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9C,gBAAgB,GAAG,WAAW,CAAC,MAAM,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QAChE,CAAC;QACD,OAAO;YACL,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,aAAa,EAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YACzG,cAAc,EAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAC5G,IAAI;YACJ,MAAM;YACN,gBAAgB;SACjB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACpC,YAAsC,EACtC,KAAqC;IAErC,IAAI,YAAY,KAAK,IAAI,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;IAC1E,MAAM,IAAI,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,6BAA6B;QAC9E,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YAChC,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YAC9B,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACvD,CAAC;AAsBD;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAqC,EAAE,IAA6B;IACnG,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,MAAM,CAAC,GAAG;QACR,KAAK,EAAE,IAAI,CAAC,aAAa,IAAI,gBAAgB,CAAC,MAAM;QACpD,KAAK,EAAE,IAAI,CAAC,cAAc,IAAI,gBAAgB,CAAC,OAAO;QACtD,MAAM,EAAE,IAAI,CAAC,eAAe,IAAI,gBAAgB,CAAC,QAAQ;QACzD,KAAK,EAAE,IAAI,CAAC,cAAc,IAAI,gBAAgB,CAAC,OAAO;KACvD,CAAC;IAEF,+FAA+F;IAC/F,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;YACpB,KAAK,CAAC,IAAI,CAAC;gBACT,EAAE,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE;gBACrB,IAAI,EAAE,OAAO;gBACb,GAAG,EAAE,CAAC,CAAC,IAAI;gBACX,GAAG,EAAE,WAAW;gBAChB,GAAG,EAAE,CAAC,CAAC,GAAG;gBACV,SAAS,EAAE,CAAC,CAAC,KAAK;gBAClB,MAAM,EAAE,mCAAmC;gBAC3C,IAAI,EAAE,MAAM;aACb,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,uDAAuD;YACvD,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,OAAO;gBACb,GAAG,EAAE,CAAC,CAAC,IAAI;gBACX,MAAM,EAAE,0EAA0E;gBAClF,KAAK,EAAE,qBAAqB;aAC7B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,6FAA6F;IAC7F,MAAM,GAAG,GAAG,IAAI,CAAC,cAAc,KAAK,IAAI,CAAC;IACzC,KAAK,CAAC,IAAI,CAAC;QACT,EAAE,EAAE,iBAAiB;QACrB,IAAI,EAAE,OAAO;QACb,GAAG,EAAE,IAAI,CAAC,eAAe;YACvB,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,qBAAqB;YACxD,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,qBAAqB;QAC7D,GAAG,EAAE,IAAI,CAAC,YAAY;QACtB,SAAS,EAAE,CAAC,CAAC,KAAK;QAClB,MAAM,EAAE,GAAG;YACT,CAAC,CAAC,uFAAuF;YACzF,CAAC,CAAC,qGAAqG;QACzG,IAAI,EAAE,MAAM;KACb,CAAC,CAAC;IAEH,6EAA6E;IAC7E,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CAAC;gBACT,EAAE,EAAE,UAAU,CAAC,CAAC,IAAI,aAAa;gBACjC,IAAI,EAAE,QAAQ;gBACd,GAAG,EAAE,CAAC,CAAC,IAAI;gBACX,GAAG,EAAE,EAAE;gBACP,GAAG,EAAE,CAAC,CAAC,GAAG;gBACV,SAAS,EAAE,CAAC;gBACZ,MAAM,EAAE,sFAAsF;gBAC9F,IAAI,EAAE,gBAAgB;gBACtB,SAAS,EAAE,YAAY;aACxB,CAAC,CAAC;YACH,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,KAAK,CAAC,IAAI,CAAC;oBACT,EAAE,EAAE,SAAS,CAAC,CAAC,IAAI,aAAa;oBAChC,IAAI,EAAE,OAAO;oBACb,GAAG,EAAE,CAAC,CAAC,IAAI;oBACX,GAAG,EAAE,EAAE;oBACP,GAAG,EAAE,CAAC,CAAC,GAAG;oBACV,SAAS,EAAE,CAAC;oBACZ,MAAM,EAAE,oFAAoF;oBAC5F,IAAI,EAAE,gBAAgB;oBACtB,SAAS,EAAE,YAAY;iBACxB,CAAC,CAAC;YACL,CAAC;YACD,SAAS;QACX,CAAC;QAED,wFAAwF;QACxF,uFAAuF;QACvF,4FAA4F;QAC5F,2FAA2F;QAC3F,oDAAoD;QACpD,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;gBAC9B,KAAK,CAAC,IAAI,CAAC;oBACT,EAAE,EAAE,UAAU,CAAC,CAAC,IAAI,eAAe;oBACnC,IAAI,EAAE,QAAQ;oBACd,GAAG,EAAE,CAAC,CAAC,IAAI;oBACX,GAAG,EAAE,EAAE;oBACP,GAAG,EAAE,CAAC,CAAC,GAAG;oBACV,SAAS,EAAE,CAAC;oBACZ,MAAM,EAAE,kIAAkI;oBAC1I,IAAI,EAAE,gBAAgB;oBACtB,SAAS,EAAE,cAAc;iBAC1B,CAAC,CAAC;YACL,CAAC;iBAAM,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC/B,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,QAAQ;oBACd,GAAG,EAAE,CAAC,CAAC,IAAI;oBACX,MAAM,EAAE,4FAA4F;oBACpG,KAAK,EAAE,mBAAmB;iBAC3B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,0FAA0F;QAC1F,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;QAClC,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;YAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACjB,KAAK,CAAC,IAAI,CAAC;gBACT,EAAE,EAAE,UAAU,CAAC,CAAC,IAAI,IAAI,GAAG,EAAE;gBAC7B,IAAI,EAAE,QAAQ;gBACd,GAAG,EAAE,CAAC,CAAC,IAAI;gBACX,GAAG,EAAE,iBAAiB,GAAG,GAAG;gBAC5B,GAAG,EAAE,CAAC,CAAC,GAAG;gBACV,SAAS,EAAE,CAAC,CAAC,MAAM;gBACnB,MAAM,EAAE,yBAAyB,GAAG,GAAG;gBACvC,IAAI,EAAE,MAAM;aACb,CAAC,CAAC;QACL,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACzB,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACtB,KAAK,CAAC,IAAI,CAAC;oBACT,EAAE,EAAE,UAAU,CAAC,CAAC,IAAI,QAAQ,GAAG,CAAC,IAAI,EAAE;oBACtC,IAAI,EAAE,QAAQ;oBACd,GAAG,EAAE,CAAC,CAAC,IAAI;oBACX,GAAG,EAAE,iBAAiB,GAAG,CAAC,IAAI,GAAG;oBACjC,GAAG,EAAE,CAAC,CAAC,GAAG;oBACV,SAAS,EAAE,CAAC,CAAC,MAAM;oBACnB,MAAM,EAAE,wBAAwB,GAAG,CAAC,IAAI,GAAG;oBAC3C,IAAI,EAAE,MAAM;iBACb,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,6FAA6F;QAC7F,4FAA4F;QAC5F,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACzB,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;gBAChB,KAAK,CAAC,IAAI,CAAC;oBACT,EAAE,EAAE,SAAS,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,UAAU;oBACzC,IAAI,EAAE,OAAO;oBACb,GAAG,EAAE,CAAC,CAAC,IAAI;oBACX,GAAG,EAAE,EAAE;oBACP,GAAG,EAAE,CAAC,CAAC,GAAG;oBACV,SAAS,EAAE,CAAC;oBACZ,MAAM,EAAE,QAAQ,GAAG,CAAC,IAAI,eAAe,GAAG,CAAC,IAAI,8CAA8C;oBAC7F,IAAI,EAAE,gBAAgB;oBACtB,SAAS,EAAE,aAAa;iBACzB,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,IAAI,CAAC;oBACT,EAAE,EAAE,SAAS,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE;oBACjC,IAAI,EAAE,OAAO;oBACb,GAAG,EAAE,CAAC,CAAC,IAAI;oBACX,GAAG,EAAE,SAAS,GAAG,CAAC,IAAI,UAAU;oBAChC,GAAG,EAAE,CAAC,CAAC,GAAG;oBACV,SAAS,EAAE,CAAC,CAAC,KAAK;oBAClB,MAAM,EAAE,QAAQ,GAAG,CAAC,IAAI,8BAA8B;oBACtD,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE,IAAI;iBACd,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED,wEAAwE;AACxE,yEAAyE;AACzE,wEAAwE;AAExE;;;;;GAKG;AACH,SAAS,oBAAoB,CAAC,MAAc;IAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAClC,MAAM,cAAc,GAClB,wKAAwK,CAAC,IAAI,CAC3K,IAAI,CACL,CAAC;IACJ,MAAM,cAAc,GAAG,sFAAsF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzH,IAAI,cAAc,IAAI,CAAC,cAAc,EAAE,CAAC;QACtC,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,EAAE,kFAAkF,EAAE,CAAC;IAC3H,CAAC;IACD,OAAO;QACL,GAAG,EAAE,aAAa;QAClB,MAAM,EAAE,oGAAoG;KAC7G,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,MAAe,EAAE,MAAe;IACvD,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;IAC/F,MAAM,OAAO,GAAG,GAAG;SAChB,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,sCAAsC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,OAAO,CAAC,OAAO,IAAI,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC9D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,GAAG,MAA0B;IAC3D,OAAO,SAAS,CAAC,GAAG,MAAM,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,SAAS,CAAC,GAAG,MAA0B;IAC9C,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC5D,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAAc,EACd,UAAoC,EACpC,MAAY,IAAI,IAAI,EAAE;IAEtB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC9C,KAAK,MAAM,CAAC,IAAI,UAAU,IAAI,EAAE,EAAE,CAAC;QACjC,IAAI,CAAC,IAAI,IAAI,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;YAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,KAAK,GAAiB,kBAAkB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC1D,MAAM,SAAS,GAAG,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC;QACtE,MAAM,SAAS,GAAG,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC;QACtE,MAAM,QAAQ,GAAkB,EAAE,CAAC;QACnC,IAAI,MAAM,GAAG,CAAC,CAAC;QAEf,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,IAAI,IAAI,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;oBACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,IAAI,cAAc,EAAE,CAAC,CAAC;oBAC/F,SAAS;gBACX,CAAC;gBACD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC/B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;oBACvB,QAAQ,CAAC,IAAI,CAAC;wBACZ,GAAG,EAAE,IAAI,CAAC,GAAG;wBACb,MAAM,EAAE,iBAAiB,IAAI,CAAC,EAAE,2DAA2D;wBAC3F,KAAK,EAAE,iBAAiB;qBACzB,CAAC,CAAC;oBACH,SAAS;gBACX,CAAC;gBACD,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;oBAC3B,QAAQ,CAAC,IAAI,CAAC;wBACZ,GAAG,EAAE,IAAI,CAAC,GAAG;wBACb,MAAM,EAAE,mBAAmB,IAAI,CAAC,SAAS,OAAO,IAAI,CAAC,GAAG,EAAE;wBAC1D,KAAK,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS;qBACtD,CAAC,CAAC;oBACH,SAAS;gBACX,CAAC;gBACD,IAAI,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;oBAC7D,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;wBACrB,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,oBAAoB,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,KAAK,IAAI,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC;wBAC3F,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;wBACzD,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;oBACnG,CAAC;yBAAM,CAAC;wBACN,QAAQ,CAAC,IAAI,CAAC;4BACZ,GAAG,EAAE,IAAI,CAAC,GAAG;4BACb,MAAM,EAAE,QAAQ,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;4BAC7I,KAAK,EAAE,cAAc;yBACtB,CAAC,CAAC;oBACL,CAAC;oBACD,SAAS;gBACX,CAAC;gBACD,MAAM,IAAI,CAAC,CAAC;YACd,CAAC;YAAC,MAAM,CAAC;gBACP,gFAAgF;gBAChF,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,sCAAsC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;YAC3G,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAyB,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;QACjG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IACvD,MAAM,SAAS,GAAa,WAAW,CAAC,GAAG,CACzC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,gBAAgB,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACjH,CAAC;IACF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACzC,SAAS,CAAC,IAAI,CAAC,8FAA8F,CAAC,CAAC;IACjH,CAAC;IACD,MAAM,EAAE,GAAG,WAAW,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC;IAE/C,OAAO;QACL,KAAK;QACL,EAAE;QACF,SAAS;QACT,OAAO,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE;QAC1B,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;QACzC,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE;KAC7B,CAAC;AACJ,CAAC;AAYD;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAuB,EAAE,MAA2B,EAAE;IACtF,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACnF,MAAM,KAAK,GAAG,8BAA8B,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,kBAAkB,EAAE,CAAC;IACzG,MAAM,KAAK,GAAa;QACtB,+BAA+B,OAAO,CAAC,SAAS,GAAG;QACnD,EAAE;QACF,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,iBAAiB,GAAG,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9C,iBAAiB;QACjB,EAAE;KACH,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QACzE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,YAAY,CAAC,CAAC,QAAQ,CAAC,MAAM,YAAY,CAAC,CAAC,KAAK,CAAC,MAAM,WAAW,CAAC,CAAC;QACjI,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IACrG,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,yDAAyD,EAAE,EAAE,CAAC,CAAC;QAC9E,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IACtF,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,eAAe,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,iGAAiG,CAAC,CAAC;IACrK,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAC3C,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,iBAAiB,CAAC,WAA8B,EAAE,KAAK,GAAG,EAAE;IAC1E,MAAM,OAAO,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;SAChC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;SAClC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;SAC3B,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;SAC5B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACtC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,kDAAkD,CAAC;IACpF,OAAO,uCAAuC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACrE,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,cAAc,CAAC,GAAS,EAAE,QAAgB;IACxD,MAAM,CAAC,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;IAC/B,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACzD,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACpD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7E,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;AACjF,CAAC"}
|
package/dist/sign.d.ts
CHANGED
|
@@ -51,6 +51,12 @@ export declare function isSafeManifestPath(p: unknown): p is string;
|
|
|
51
51
|
export declare function checkManifestEntries(files: unknown): string | null;
|
|
52
52
|
/** Every file under `root`, POSIX-relative, excluding the manifest and the SBOM themselves. */
|
|
53
53
|
export declare function listPackFiles(root: string): string[];
|
|
54
|
+
/**
|
|
55
|
+
* The SIGN-side file list: same exclusions as {@link listPackFiles}, but REGULAR FILES ONLY — `dz sign`
|
|
56
|
+
* never signs a symlink (hashing one would follow it outside the pack). The verify sweep intentionally
|
|
57
|
+
* sees MORE than this (symlinks/specials outside node_modules), so a smuggled entry fails verification.
|
|
58
|
+
*/
|
|
59
|
+
export declare function listSignablePackFiles(root: string): string[];
|
|
54
60
|
/**
|
|
55
61
|
* The bytes that get signed (FR-7). Sorted by path, LF endings, no trailing whitespace, and no
|
|
56
62
|
* dependence on JSON key order — a signature must not depend on how a serialiser felt that day.
|
package/dist/sign.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sign.d.ts","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,eAAO,MAAM,aAAa,sBAAsB,CAAC;AACjD,eAAO,MAAM,SAAS,cAAc,CAAC;AACrC,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;CAC7C;AAED,uGAAuG;AACvG,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWtE;AAeD,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAK1D;AAED,qFAAqF;AACrF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAkBlE;AAED,+FAA+F;AAC/F,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"sign.d.ts","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"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"}
|
package/dist/sign.js
CHANGED
|
@@ -96,12 +96,21 @@ export function listPackFiles(root) {
|
|
|
96
96
|
const out = [];
|
|
97
97
|
const walk = (dir, rel) => {
|
|
98
98
|
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
99
|
+
// node_modules/.git are unsigned territory BY DESIGN (installed deps / VCS metadata — not pack
|
|
100
|
+
// content; npm tarballs ship neither). The SIGN and VERIFY walks MUST share these exclusions:
|
|
101
|
+
// an asymmetry here false-TAMPERs every pnpm workspace pack whose node_modules holds symlinks
|
|
102
|
+
// (found live arming task #36 — 10 of 23 skill packs flagged right after signing).
|
|
103
|
+
if (e.name === 'node_modules' || e.name === '.git')
|
|
104
|
+
continue;
|
|
99
105
|
if (e.name === MANIFEST_NAME || e.name === SBOM_NAME)
|
|
100
106
|
continue;
|
|
101
107
|
const abs = join(dir, e.name);
|
|
102
108
|
const r = rel ? rel + '/' + e.name : e.name;
|
|
103
109
|
if (e.isDirectory())
|
|
104
110
|
walk(abs, r);
|
|
111
|
+
// NOT else-isFile: a symlink (or other non-file) OUTSIDE the excluded dirs must stay VISIBLE to the
|
|
112
|
+
// verify sweep — it fails as "present but not signed" / "is a symlink" (R3-4: a smuggled symlink is a
|
|
113
|
+
// finding, not something to silently ignore). Only node_modules/.git are exempt territory.
|
|
105
114
|
else
|
|
106
115
|
out.push(r);
|
|
107
116
|
}
|
|
@@ -109,6 +118,30 @@ export function listPackFiles(root) {
|
|
|
109
118
|
walk(root, '');
|
|
110
119
|
return out.sort();
|
|
111
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* The SIGN-side file list: same exclusions as {@link listPackFiles}, but REGULAR FILES ONLY — `dz sign`
|
|
123
|
+
* never signs a symlink (hashing one would follow it outside the pack). The verify sweep intentionally
|
|
124
|
+
* sees MORE than this (symlinks/specials outside node_modules), so a smuggled entry fails verification.
|
|
125
|
+
*/
|
|
126
|
+
export function listSignablePackFiles(root) {
|
|
127
|
+
const out = [];
|
|
128
|
+
const walk = (dir, rel) => {
|
|
129
|
+
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
130
|
+
if (e.name === 'node_modules' || e.name === '.git')
|
|
131
|
+
continue;
|
|
132
|
+
if (e.name === MANIFEST_NAME || e.name === SBOM_NAME)
|
|
133
|
+
continue;
|
|
134
|
+
const abs = join(dir, e.name);
|
|
135
|
+
const r = rel ? rel + '/' + e.name : e.name;
|
|
136
|
+
if (e.isDirectory())
|
|
137
|
+
walk(abs, r);
|
|
138
|
+
else if (e.isFile())
|
|
139
|
+
out.push(r);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
walk(root, '');
|
|
143
|
+
return out.sort();
|
|
144
|
+
}
|
|
112
145
|
/**
|
|
113
146
|
* The bytes that get signed (FR-7). Sorted by path, LF endings, no trailing whitespace, and no
|
|
114
147
|
* dependence on JSON key order — a signature must not depend on how a serialiser felt that day.
|