@testmuai/evidence-cli 0.1.1
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/LICENSE +201 -0
- package/README.md +124 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +55 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +71 -0
- package/dist/config.js.map +1 -0
- package/dist/contract.d.ts +66 -0
- package/dist/contract.js +50 -0
- package/dist/contract.js.map +1 -0
- package/dist/diagnostics.d.ts +3 -0
- package/dist/diagnostics.js +11 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/finalize/index.d.ts +21 -0
- package/dist/finalize/index.js +196 -0
- package/dist/finalize/index.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/pack/byte-source.d.ts +33 -0
- package/dist/pack/byte-source.js +50 -0
- package/dist/pack/byte-source.js.map +1 -0
- package/dist/pack/container.d.ts +58 -0
- package/dist/pack/container.js +215 -0
- package/dist/pack/container.js.map +1 -0
- package/dist/pack/remote.d.ts +49 -0
- package/dist/pack/remote.js +258 -0
- package/dist/pack/remote.js.map +1 -0
- package/dist/report/reporter.d.ts +22 -0
- package/dist/report/reporter.js +66 -0
- package/dist/report/reporter.js.map +1 -0
- package/dist/schemas/0.1/L0/result.schema.json +150 -0
- package/dist/schemas/0.1/L0/run.schema.json +114 -0
- package/dist/schemas/0.1/L1/logs-meta.schema.json +39 -0
- package/dist/schemas/0.1/L1/video.schema.json +16 -0
- package/dist/schemas/compile.d.ts +11 -0
- package/dist/schemas/compile.js +45 -0
- package/dist/schemas/compile.js.map +1 -0
- package/dist/schemas/registry.d.ts +11 -0
- package/dist/schemas/registry.js +40 -0
- package/dist/schemas/registry.js.map +1 -0
- package/dist/validate/checks.d.ts +15 -0
- package/dist/validate/checks.js +152 -0
- package/dist/validate/checks.js.map +1 -0
- package/dist/validate/index.d.ts +5 -0
- package/dist/validate/index.js +99 -0
- package/dist/validate/index.js.map +1 -0
- package/dist/validate/l1.d.ts +12 -0
- package/dist/validate/l1.js +117 -0
- package/dist/validate/l1.js.map +1 -0
- package/dist/yaml.d.ts +4 -0
- package/dist/yaml.js +16 -0
- package/dist/yaml.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { ByteSource } from "./byte-source";
|
|
2
|
+
import type { DirEntry, PackContainer } from "./container";
|
|
3
|
+
/** A single central-directory entry — everything needed to range-read its data. */
|
|
4
|
+
interface ZipEntry {
|
|
5
|
+
name: string;
|
|
6
|
+
method: number;
|
|
7
|
+
compressedSize: number;
|
|
8
|
+
uncompressedSize: number;
|
|
9
|
+
localHeaderOffset: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A PackContainer that reads a sealed `.evidence` zip through a ranged
|
|
13
|
+
* ByteSource — the central directory once, then only the entry byte-ranges it
|
|
14
|
+
* needs. Implements decision 0041 over the existing container interface (0040):
|
|
15
|
+
* the validator and viewer are unchanged; only *how* a pack is read differs.
|
|
16
|
+
*
|
|
17
|
+
* Construct via `openRemoteZip` (it parses the central directory up front).
|
|
18
|
+
*/
|
|
19
|
+
export declare class RemoteZipContainer implements PackContainer {
|
|
20
|
+
private readonly src;
|
|
21
|
+
private readonly packName;
|
|
22
|
+
readonly kind: "zip";
|
|
23
|
+
private readonly byName;
|
|
24
|
+
/** All entry names (including any explicit directory entries) for prefix ops. */
|
|
25
|
+
private readonly names;
|
|
26
|
+
constructor(src: ByteSource, packName: string, entries: ZipEntry[]);
|
|
27
|
+
get name(): string;
|
|
28
|
+
/** Range-read and decompress a single entry's bytes, or null if absent. */
|
|
29
|
+
private readEntryBytes;
|
|
30
|
+
private readEntryText;
|
|
31
|
+
/** True if any entry sits under `<rel>/` — i.e. rel names a directory. */
|
|
32
|
+
private hasPrefix;
|
|
33
|
+
readManifest(): Promise<string | null>;
|
|
34
|
+
listTestIds(): Promise<string[]>;
|
|
35
|
+
readResult(testId: string): Promise<string | null>;
|
|
36
|
+
fileExists(testId: string, relPath: string): Promise<boolean>;
|
|
37
|
+
readBytes(testId: string, relPath: string): Promise<Buffer | null>;
|
|
38
|
+
exists(rel: string): Promise<boolean>;
|
|
39
|
+
isDir(rel: string): Promise<boolean>;
|
|
40
|
+
listDir(rel: string): Promise<DirEntry[]>;
|
|
41
|
+
readText(rel: string): Promise<string | null>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Open a sealed pack over a ranged ByteSource. Reads and caches the central
|
|
45
|
+
* directory (tail + CD only), so subsequent reads fetch just the entries asked
|
|
46
|
+
* for. `packName` is the pack's file base name (e.g. "smoke.evidence").
|
|
47
|
+
*/
|
|
48
|
+
export declare function openRemoteZip(src: ByteSource, packName: string): Promise<RemoteZipContainer>;
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RemoteZipContainer = void 0;
|
|
4
|
+
exports.openRemoteZip = openRemoteZip;
|
|
5
|
+
const node_zlib_1 = require("node:zlib");
|
|
6
|
+
const node_util_1 = require("node:util");
|
|
7
|
+
const inflateRawAsync = (0, node_util_1.promisify)(node_zlib_1.inflateRaw);
|
|
8
|
+
// ZIP record signatures (little-endian uint32).
|
|
9
|
+
const SIG_EOCD = 0x06054b50; // end of central directory
|
|
10
|
+
const SIG_EOCD64 = 0x06064b50; // ZIP64 end of central directory record
|
|
11
|
+
const SIG_EOCD64_LOC = 0x07064b50; // ZIP64 EOCD locator
|
|
12
|
+
const SIG_CD = 0x02014b50; // central directory file header
|
|
13
|
+
const SIG_LFH = 0x04034b50; // local file header
|
|
14
|
+
const EOCD_MIN = 22; // EOCD without comment
|
|
15
|
+
const MAX_COMMENT = 0xffff;
|
|
16
|
+
const ZIP64_SENTINEL32 = 0xffffffff;
|
|
17
|
+
const ZIP64_SENTINEL16 = 0xffff;
|
|
18
|
+
const METHOD_STORE = 0;
|
|
19
|
+
const METHOD_DEFLATE = 8;
|
|
20
|
+
/** Read an 8-byte LE value as a Number (offsets/sizes < 2^53; never realistic to exceed). */
|
|
21
|
+
function readU64(buf, off) {
|
|
22
|
+
return Number(buf.readBigUInt64LE(off));
|
|
23
|
+
}
|
|
24
|
+
function stripEvidence(base) {
|
|
25
|
+
return base.replace(/\.evidence$/, "");
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Locate and parse the (optionally ZIP64) End-Of-Central-Directory, returning
|
|
29
|
+
* the central directory's byte offset, size, and entry count. Reads only the
|
|
30
|
+
* tail of the source — never the whole archive.
|
|
31
|
+
*/
|
|
32
|
+
async function readEocd(src) {
|
|
33
|
+
const total = await src.size();
|
|
34
|
+
const tailLen = Math.min(total, EOCD_MIN + MAX_COMMENT);
|
|
35
|
+
const tail = await src.read(total - tailLen, tailLen);
|
|
36
|
+
// Scan backwards for the EOCD signature, honouring the comment length so a
|
|
37
|
+
// stray signature inside a comment can't fool us.
|
|
38
|
+
let p = -1;
|
|
39
|
+
for (let i = tail.length - EOCD_MIN; i >= 0; i--) {
|
|
40
|
+
if (tail.readUInt32LE(i) !== SIG_EOCD)
|
|
41
|
+
continue;
|
|
42
|
+
const commentLen = tail.readUInt16LE(i + 20);
|
|
43
|
+
if (i + EOCD_MIN + commentLen === tail.length) {
|
|
44
|
+
p = i;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (p === -1)
|
|
49
|
+
throw new Error("not a zip: end-of-central-directory not found");
|
|
50
|
+
let count = tail.readUInt16LE(p + 10);
|
|
51
|
+
let cdSize = tail.readUInt32LE(p + 12);
|
|
52
|
+
let cdOffset = tail.readUInt32LE(p + 16);
|
|
53
|
+
const needsZip64 = count === ZIP64_SENTINEL16 ||
|
|
54
|
+
cdSize === ZIP64_SENTINEL32 ||
|
|
55
|
+
cdOffset === ZIP64_SENTINEL32;
|
|
56
|
+
if (needsZip64) {
|
|
57
|
+
// The ZIP64 EOCD locator sits immediately before the EOCD (20 bytes).
|
|
58
|
+
const locPos = p - 20;
|
|
59
|
+
const eocdStart = total - tailLen;
|
|
60
|
+
if (locPos >= 0 && tail.readUInt32LE(locPos) === SIG_EOCD64_LOC) {
|
|
61
|
+
const z64Offset = readU64(tail, locPos + 8);
|
|
62
|
+
// The ZIP64 EOCD record may live before our tail window — read it directly.
|
|
63
|
+
const inTail = z64Offset - eocdStart;
|
|
64
|
+
const z64 = inTail >= 0 && inTail + 56 <= tail.length
|
|
65
|
+
? tail.subarray(inTail, inTail + 56)
|
|
66
|
+
: await src.read(z64Offset, 56);
|
|
67
|
+
if (z64.readUInt32LE(0) === SIG_EOCD64) {
|
|
68
|
+
count = readU64(z64, 32);
|
|
69
|
+
cdSize = readU64(z64, 40);
|
|
70
|
+
cdOffset = readU64(z64, 48);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { cdOffset, cdSize, count };
|
|
75
|
+
}
|
|
76
|
+
/** Apply ZIP64 overrides from a central-header extra field to the sentinel values. */
|
|
77
|
+
function applyZip64Extra(extra, e) {
|
|
78
|
+
let i = 0;
|
|
79
|
+
while (i + 4 <= extra.length) {
|
|
80
|
+
const id = extra.readUInt16LE(i);
|
|
81
|
+
const size = extra.readUInt16LE(i + 2);
|
|
82
|
+
const body = i + 4;
|
|
83
|
+
if (id === 0x0001) {
|
|
84
|
+
// Fields appear in fixed order, only for those that overflowed to sentinel.
|
|
85
|
+
let o = body;
|
|
86
|
+
if (e.uncompressedSize === ZIP64_SENTINEL32 && o + 8 <= body + size) {
|
|
87
|
+
e.uncompressedSize = readU64(extra, o);
|
|
88
|
+
o += 8;
|
|
89
|
+
}
|
|
90
|
+
if (e.compressedSize === ZIP64_SENTINEL32 && o + 8 <= body + size) {
|
|
91
|
+
e.compressedSize = readU64(extra, o);
|
|
92
|
+
o += 8;
|
|
93
|
+
}
|
|
94
|
+
if (e.localHeaderOffset === ZIP64_SENTINEL32 && o + 8 <= body + size) {
|
|
95
|
+
e.localHeaderOffset = readU64(extra, o);
|
|
96
|
+
o += 8;
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
i = body + size;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** Parse the central directory bytes into an ordered list of entries. */
|
|
104
|
+
function parseCentralDirectory(cd) {
|
|
105
|
+
const entries = [];
|
|
106
|
+
let i = 0;
|
|
107
|
+
while (i + 46 <= cd.length && cd.readUInt32LE(i) === SIG_CD) {
|
|
108
|
+
const method = cd.readUInt16LE(i + 10);
|
|
109
|
+
const compressedSize = cd.readUInt32LE(i + 20);
|
|
110
|
+
const uncompressedSize = cd.readUInt32LE(i + 24);
|
|
111
|
+
const nameLen = cd.readUInt16LE(i + 28);
|
|
112
|
+
const extraLen = cd.readUInt16LE(i + 30);
|
|
113
|
+
const commentLen = cd.readUInt16LE(i + 32);
|
|
114
|
+
const localHeaderOffset = cd.readUInt32LE(i + 42);
|
|
115
|
+
const name = cd.toString("utf8", i + 46, i + 46 + nameLen);
|
|
116
|
+
const extra = cd.subarray(i + 46 + nameLen, i + 46 + nameLen + extraLen);
|
|
117
|
+
const entry = {
|
|
118
|
+
name,
|
|
119
|
+
method,
|
|
120
|
+
compressedSize,
|
|
121
|
+
uncompressedSize,
|
|
122
|
+
localHeaderOffset,
|
|
123
|
+
};
|
|
124
|
+
if (compressedSize === ZIP64_SENTINEL32 ||
|
|
125
|
+
uncompressedSize === ZIP64_SENTINEL32 ||
|
|
126
|
+
localHeaderOffset === ZIP64_SENTINEL32) {
|
|
127
|
+
applyZip64Extra(extra, entry);
|
|
128
|
+
}
|
|
129
|
+
entries.push(entry);
|
|
130
|
+
i += 46 + nameLen + extraLen + commentLen;
|
|
131
|
+
}
|
|
132
|
+
return entries;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* A PackContainer that reads a sealed `.evidence` zip through a ranged
|
|
136
|
+
* ByteSource — the central directory once, then only the entry byte-ranges it
|
|
137
|
+
* needs. Implements decision 0041 over the existing container interface (0040):
|
|
138
|
+
* the validator and viewer are unchanged; only *how* a pack is read differs.
|
|
139
|
+
*
|
|
140
|
+
* Construct via `openRemoteZip` (it parses the central directory up front).
|
|
141
|
+
*/
|
|
142
|
+
class RemoteZipContainer {
|
|
143
|
+
src;
|
|
144
|
+
packName;
|
|
145
|
+
kind = "zip";
|
|
146
|
+
byName;
|
|
147
|
+
/** All entry names (including any explicit directory entries) for prefix ops. */
|
|
148
|
+
names;
|
|
149
|
+
constructor(src, packName, entries) {
|
|
150
|
+
this.src = src;
|
|
151
|
+
this.packName = packName;
|
|
152
|
+
this.byName = new Map();
|
|
153
|
+
this.names = [];
|
|
154
|
+
for (const e of entries) {
|
|
155
|
+
this.names.push(e.name);
|
|
156
|
+
if (!e.name.endsWith("/"))
|
|
157
|
+
this.byName.set(e.name, e);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
get name() {
|
|
161
|
+
return stripEvidence(this.packName);
|
|
162
|
+
}
|
|
163
|
+
/** Range-read and decompress a single entry's bytes, or null if absent. */
|
|
164
|
+
async readEntryBytes(entryName) {
|
|
165
|
+
const e = this.byName.get(entryName);
|
|
166
|
+
if (!e)
|
|
167
|
+
return null;
|
|
168
|
+
// The local header's name/extra lengths can differ from the central
|
|
169
|
+
// directory's, so the data offset must be read from the local header.
|
|
170
|
+
const lfh = await this.src.read(e.localHeaderOffset, 30);
|
|
171
|
+
if (lfh.length < 30 || lfh.readUInt32LE(0) !== SIG_LFH) {
|
|
172
|
+
throw new Error(`corrupt local header for ${entryName}`);
|
|
173
|
+
}
|
|
174
|
+
const nameLen = lfh.readUInt16LE(26);
|
|
175
|
+
const extraLen = lfh.readUInt16LE(28);
|
|
176
|
+
const dataOffset = e.localHeaderOffset + 30 + nameLen + extraLen;
|
|
177
|
+
const raw = await this.src.read(dataOffset, e.compressedSize);
|
|
178
|
+
if (e.method === METHOD_STORE)
|
|
179
|
+
return raw;
|
|
180
|
+
if (e.method === METHOD_DEFLATE)
|
|
181
|
+
return Buffer.from(await inflateRawAsync(raw));
|
|
182
|
+
throw new Error(`unsupported compression method ${e.method} for ${entryName}`);
|
|
183
|
+
}
|
|
184
|
+
async readEntryText(entryName) {
|
|
185
|
+
const b = await this.readEntryBytes(entryName);
|
|
186
|
+
return b ? b.toString("utf8") : null;
|
|
187
|
+
}
|
|
188
|
+
/** True if any entry sits under `<rel>/` — i.e. rel names a directory. */
|
|
189
|
+
hasPrefix(rel) {
|
|
190
|
+
const prefix = rel.endsWith("/") ? rel : `${rel}/`;
|
|
191
|
+
return this.names.some((n) => n.startsWith(prefix));
|
|
192
|
+
}
|
|
193
|
+
async readManifest() {
|
|
194
|
+
return this.readEntryText("run.yaml");
|
|
195
|
+
}
|
|
196
|
+
async listTestIds() {
|
|
197
|
+
const ids = new Set();
|
|
198
|
+
for (const n of this.names) {
|
|
199
|
+
const m = n.match(/^tests\/([^/]+)\//);
|
|
200
|
+
if (m)
|
|
201
|
+
ids.add(m[1]);
|
|
202
|
+
}
|
|
203
|
+
return [...ids].sort();
|
|
204
|
+
}
|
|
205
|
+
async readResult(testId) {
|
|
206
|
+
return this.readEntryText(`tests/${testId}/result.yaml`);
|
|
207
|
+
}
|
|
208
|
+
async fileExists(testId, relPath) {
|
|
209
|
+
return this.byName.has(`tests/${testId}/${relPath}`);
|
|
210
|
+
}
|
|
211
|
+
async readBytes(testId, relPath) {
|
|
212
|
+
return this.readEntryBytes(`tests/${testId}/${relPath}`);
|
|
213
|
+
}
|
|
214
|
+
async exists(rel) {
|
|
215
|
+
return this.byName.has(rel) || this.hasPrefix(rel);
|
|
216
|
+
}
|
|
217
|
+
async isDir(rel) {
|
|
218
|
+
return this.hasPrefix(rel);
|
|
219
|
+
}
|
|
220
|
+
async listDir(rel) {
|
|
221
|
+
const prefix = rel === "" ? "" : rel.endsWith("/") ? rel : `${rel}/`;
|
|
222
|
+
const children = new Map(); // name -> isDir
|
|
223
|
+
for (const n of this.names) {
|
|
224
|
+
if (!n.startsWith(prefix))
|
|
225
|
+
continue;
|
|
226
|
+
const rest = n.slice(prefix.length);
|
|
227
|
+
if (rest === "")
|
|
228
|
+
continue;
|
|
229
|
+
const slash = rest.indexOf("/");
|
|
230
|
+
if (slash === -1) {
|
|
231
|
+
if (!children.has(rest))
|
|
232
|
+
children.set(rest, false);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
children.set(rest.slice(0, slash), true);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return [...children.entries()]
|
|
239
|
+
.map(([name, isDir]) => ({ name, isDir }))
|
|
240
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
241
|
+
}
|
|
242
|
+
async readText(rel) {
|
|
243
|
+
return this.readEntryText(rel);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
exports.RemoteZipContainer = RemoteZipContainer;
|
|
247
|
+
/**
|
|
248
|
+
* Open a sealed pack over a ranged ByteSource. Reads and caches the central
|
|
249
|
+
* directory (tail + CD only), so subsequent reads fetch just the entries asked
|
|
250
|
+
* for. `packName` is the pack's file base name (e.g. "smoke.evidence").
|
|
251
|
+
*/
|
|
252
|
+
async function openRemoteZip(src, packName) {
|
|
253
|
+
const { cdOffset, cdSize } = await readEocd(src);
|
|
254
|
+
const cd = await src.read(cdOffset, cdSize);
|
|
255
|
+
const entries = parseCentralDirectory(cd);
|
|
256
|
+
return new RemoteZipContainer(src, packName, entries);
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=remote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/pack/remote.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ValidationReport, FinalizeResult } from "../contract";
|
|
2
|
+
export interface Reporter {
|
|
3
|
+
validation(report: ValidationReport): void;
|
|
4
|
+
finalize(result: FinalizeResult): void;
|
|
5
|
+
usageError(message: string): void;
|
|
6
|
+
}
|
|
7
|
+
export declare class JsonReporter implements Reporter {
|
|
8
|
+
validation(report: ValidationReport): void;
|
|
9
|
+
finalize(result: FinalizeResult): void;
|
|
10
|
+
usageError(message: string): void;
|
|
11
|
+
}
|
|
12
|
+
export declare class HumanReporter implements Reporter {
|
|
13
|
+
private readonly isTty;
|
|
14
|
+
private readonly color;
|
|
15
|
+
constructor(isTty: boolean);
|
|
16
|
+
private sym;
|
|
17
|
+
private paint;
|
|
18
|
+
validation(report: ValidationReport): void;
|
|
19
|
+
finalize(result: FinalizeResult): void;
|
|
20
|
+
usageError(message: string): void;
|
|
21
|
+
}
|
|
22
|
+
export declare function makeReporter(json: boolean): Reporter;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.HumanReporter = exports.JsonReporter = void 0;
|
|
7
|
+
exports.makeReporter = makeReporter;
|
|
8
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
9
|
+
class JsonReporter {
|
|
10
|
+
validation(report) {
|
|
11
|
+
process.stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
12
|
+
}
|
|
13
|
+
finalize(result) {
|
|
14
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
15
|
+
}
|
|
16
|
+
usageError(message) {
|
|
17
|
+
process.stderr.write(JSON.stringify({ error: message }, null, 2) + "\n");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.JsonReporter = JsonReporter;
|
|
21
|
+
class HumanReporter {
|
|
22
|
+
isTty;
|
|
23
|
+
color;
|
|
24
|
+
constructor(isTty) {
|
|
25
|
+
this.isTty = isTty;
|
|
26
|
+
this.color = isTty && !process.env.NO_COLOR;
|
|
27
|
+
}
|
|
28
|
+
sym(m) {
|
|
29
|
+
if (this.isTty)
|
|
30
|
+
return m === "error" ? "✗" : m === "warning" ? "⚠" : "✓";
|
|
31
|
+
return m === "error" ? "x" : m === "warning" ? "!" : "ok";
|
|
32
|
+
}
|
|
33
|
+
paint(s, m) {
|
|
34
|
+
if (!this.color)
|
|
35
|
+
return s;
|
|
36
|
+
return m === "error" ? picocolors_1.default.red(s) : m === "warning" ? picocolors_1.default.yellow(s) : picocolors_1.default.green(s);
|
|
37
|
+
}
|
|
38
|
+
validation(report) {
|
|
39
|
+
const errors = report.diagnostics.filter((d) => d.severity === "error");
|
|
40
|
+
const warnings = report.diagnostics.filter((d) => d.severity === "warning");
|
|
41
|
+
for (const d of report.diagnostics) {
|
|
42
|
+
const line = `${this.sym(d.severity)} ${d.location}: ${d.message} [${d.code}]`;
|
|
43
|
+
process.stdout.write(this.paint(line, d.severity) + "\n");
|
|
44
|
+
}
|
|
45
|
+
const where = `profile ${report.profile}, evidence ${report.version}, status ${report.status ?? "unknown"}`;
|
|
46
|
+
if (report.valid) {
|
|
47
|
+
process.stdout.write(this.paint(`${this.sym("ok")} valid (${where})`, "ok") + "\n");
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
process.stdout.write(this.paint(`${this.sym("error")} invalid — ${errors.length} error(s), ${warnings.length} warning(s) (${where})`, "error") + "\n");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
finalize(result) {
|
|
54
|
+
const t = result.totals;
|
|
55
|
+
process.stdout.write(this.paint(`${this.sym("ok")} sealed ${result.sealedPath}`, "ok") + "\n");
|
|
56
|
+
process.stdout.write(` totals: tests=${t.tests} passed=${t.passed} failed=${t.failed} broken=${t.broken} skipped=${t.skipped}\n`);
|
|
57
|
+
}
|
|
58
|
+
usageError(message) {
|
|
59
|
+
process.stderr.write(this.paint(`${this.sym("error")} ${message}`, "error") + "\n");
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.HumanReporter = HumanReporter;
|
|
63
|
+
function makeReporter(json) {
|
|
64
|
+
return json ? new JsonReporter() : new HumanReporter(Boolean(process.stdout.isTTY));
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../src/report/reporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://evidence-cli.dev/schemas/0.1/L0/result.schema.json",
|
|
4
|
+
"title": "result.yaml (L0)",
|
|
5
|
+
"description": "THE RESULT for one test inside an .evidence pack (tests/<id>/result.yaml): structured, easy-to-parse per-step outcomes. The test's DEFINITION (the framework's own artifact — kane test.md, a .spec.ts, etc.) lives beside this file and is OPAQUE to evidence-cli; it is referenced by `definition`, never parsed.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["evidence", "test", "status", "steps"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"evidence": {
|
|
10
|
+
"description": "Evidence CONTRACT version this file conforms to. One contract version spans all profiles (L0–L3); only a breaking change bumps it. Const by design — a validator is pinned to its contract version. See decision 0027.",
|
|
11
|
+
"const": "0.1"
|
|
12
|
+
},
|
|
13
|
+
"test": {
|
|
14
|
+
"description": "Test identifier. MUST equal the tests/<id>/ directory name — the validator enforces this equality (a cross-check beyond JSON Schema; see decision 0031).",
|
|
15
|
+
"type": "string",
|
|
16
|
+
"minLength": 1
|
|
17
|
+
},
|
|
18
|
+
"status": {
|
|
19
|
+
"description": "Test verdict, authored by the producer. `failed` = oracle evaluated and the product was wrong. `broken` = oracle could NOT be evaluated (environment/infra/test fault). `skipped` = not executed.",
|
|
20
|
+
"enum": ["passed", "failed", "broken", "skipped"]
|
|
21
|
+
},
|
|
22
|
+
"definition": {
|
|
23
|
+
"description": "Reference to the opaque definition artifact. The framework pre-declares `path` (its own native filename); `evidence finalize` adds `sha256`. evidence-cli asserts the file at `path` exists and (when sealed) that its hash matches — it never reads the content.",
|
|
24
|
+
"type": "object",
|
|
25
|
+
"required": ["path"],
|
|
26
|
+
"properties": {
|
|
27
|
+
"path": {
|
|
28
|
+
"description": "Path to the definition file, relative to and CONTAINED WITHIN this test directory. No leading '/', no '..' segment, no URL scheme — subdirectories are allowed. The pattern below catches the obvious shapes; the validator additionally normalizes the path and rejects any escape (see decisions 0029, 0031).",
|
|
29
|
+
"type": "string",
|
|
30
|
+
"minLength": 1,
|
|
31
|
+
"pattern": "^(?!/)(?!.*(^|/)\\.\\.(/|$))(?![a-zA-Z][a-zA-Z0-9+.-]*:)[^\\\\]+$"
|
|
32
|
+
},
|
|
33
|
+
"sha256": {
|
|
34
|
+
"description": "Content hash of the definition file. Added by `evidence finalize`. Format: 'sha256:<hex>'.",
|
|
35
|
+
"type": "string",
|
|
36
|
+
"pattern": "^sha256:[0-9a-f]{64}$"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"additionalProperties": true
|
|
40
|
+
},
|
|
41
|
+
"steps": {
|
|
42
|
+
"description": "Ordered per-step outcomes. The framework decides what a 'step' is and its granularity. MAY be empty (a unit/API test may have no sub-steps).",
|
|
43
|
+
"type": "array",
|
|
44
|
+
"items": { "$ref": "#/$defs/step" }
|
|
45
|
+
},
|
|
46
|
+
"params_hash": {
|
|
47
|
+
"description": "Optional hash of the parameterization used for this test.",
|
|
48
|
+
"type": "string"
|
|
49
|
+
},
|
|
50
|
+
"external_id": {
|
|
51
|
+
"description": "Optional open map of links into external systems (e.g. a test-manager URL).",
|
|
52
|
+
"type": "object",
|
|
53
|
+
"additionalProperties": true
|
|
54
|
+
},
|
|
55
|
+
"duration_ms": { "type": "number", "minimum": 0 },
|
|
56
|
+
"attempts": {
|
|
57
|
+
"description": "Optional per-attempt outcomes for a retried test. Each attempt carries a `status` from the verdict enum; the array length is the attempt count. The test-level `status` remains the authoritative final verdict. See decision 0033.",
|
|
58
|
+
"type": "array",
|
|
59
|
+
"minItems": 1,
|
|
60
|
+
"items": {
|
|
61
|
+
"type": "object",
|
|
62
|
+
"required": ["status"],
|
|
63
|
+
"properties": {
|
|
64
|
+
"status": {
|
|
65
|
+
"description": "Outcome of this attempt — same vocabulary as the test verdict.",
|
|
66
|
+
"enum": ["passed", "failed", "broken", "skipped"]
|
|
67
|
+
},
|
|
68
|
+
"duration_ms": { "type": "number", "minimum": 0 }
|
|
69
|
+
},
|
|
70
|
+
"additionalProperties": true
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"flaky": {
|
|
74
|
+
"description": "Optional. Derived: true when the statuses in `attempts` disagree. See decision 0033.",
|
|
75
|
+
"type": "boolean"
|
|
76
|
+
},
|
|
77
|
+
"tags": { "type": "array", "items": { "type": "string" } },
|
|
78
|
+
"requirements": { "type": "array", "items": { "type": "string" } },
|
|
79
|
+
"environment": {
|
|
80
|
+
"description": "Optional per-test execution context — an OPEN map of key:value pairs, the SAME shape as run.yaml.environment (decision 0013). Records the environment a single test executed in (e.g. cross-browser, sharded, or merged evidence, where tests diverge). How this relates to the run-level environment — precedence, merge, inheritance — is left to the consumer that reads the pack; the format only carries the facts and the validator checks shape. Nothing here is required. See decision 0043.",
|
|
81
|
+
"type": "object",
|
|
82
|
+
"properties": {
|
|
83
|
+
"producer": {
|
|
84
|
+
"description": "The tool that executed this test; typically only recorded at run level, present here only if a test's producer differs.",
|
|
85
|
+
"type": "object",
|
|
86
|
+
"properties": {
|
|
87
|
+
"name": { "type": "string" },
|
|
88
|
+
"version": { "type": "string" }
|
|
89
|
+
},
|
|
90
|
+
"additionalProperties": true
|
|
91
|
+
},
|
|
92
|
+
"model": { "type": "string" },
|
|
93
|
+
"surfaces": { "type": "array", "items": { "type": "string" } },
|
|
94
|
+
"ci": {
|
|
95
|
+
"type": "object",
|
|
96
|
+
"additionalProperties": true
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"additionalProperties": true
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
"additionalProperties": true,
|
|
103
|
+
"$defs": {
|
|
104
|
+
"step": {
|
|
105
|
+
"type": "object",
|
|
106
|
+
"required": ["id", "ordinal", "status"],
|
|
107
|
+
"properties": {
|
|
108
|
+
"id": {
|
|
109
|
+
"description": "Stable identifier for the step within this test.",
|
|
110
|
+
"type": "string",
|
|
111
|
+
"minLength": 1
|
|
112
|
+
},
|
|
113
|
+
"ordinal": {
|
|
114
|
+
"description": "1-based position in the producer's step sequence (NOT an index into this array). Ordinals MUST be unique and strictly increasing in array order; gaps are allowed when a producer records only some of a longer sequence. Uniqueness/monotonicity is a validator cross-check beyond JSON Schema; see decisions 0030, 0031.",
|
|
115
|
+
"type": "integer",
|
|
116
|
+
"minimum": 1
|
|
117
|
+
},
|
|
118
|
+
"status": {
|
|
119
|
+
"description": "Step verdict, same vocabulary as the test verdict.",
|
|
120
|
+
"enum": ["passed", "failed", "broken", "skipped"]
|
|
121
|
+
},
|
|
122
|
+
"kind": {
|
|
123
|
+
"description": "OPTIONAL producer-defined step kind (open string, e.g. navigate, input, assertion, api, wait). Not required on a step; when present it must be non-empty. evidence-cli never checks the vocabulary. See decision 0009.",
|
|
124
|
+
"type": "string",
|
|
125
|
+
"minLength": 1
|
|
126
|
+
},
|
|
127
|
+
"duration_ms": { "type": "number", "minimum": 0 },
|
|
128
|
+
"durable_id": {
|
|
129
|
+
"description": "Optional stable cross-run identity for the step.",
|
|
130
|
+
"type": "string"
|
|
131
|
+
},
|
|
132
|
+
"defect": {
|
|
133
|
+
"description": "Optional defect classification for a non-passing step (e.g. Product, Infrastructure, Test).",
|
|
134
|
+
"type": "string"
|
|
135
|
+
},
|
|
136
|
+
"expected": { "type": "string" },
|
|
137
|
+
"actual": { "type": "string" },
|
|
138
|
+
"check": {
|
|
139
|
+
"description": "Optional oracle descriptor.",
|
|
140
|
+
"type": "object",
|
|
141
|
+
"properties": {
|
|
142
|
+
"kind": { "type": "string" }
|
|
143
|
+
},
|
|
144
|
+
"additionalProperties": true
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"additionalProperties": true
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|