mjolnir-qa 3.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +360 -6
- package/README.ar.md +58 -29
- package/README.bn.md +58 -29
- package/README.br.md +58 -29
- package/README.bs.md +58 -29
- package/README.da.md +59 -30
- package/README.de.md +59 -30
- package/README.es.md +58 -29
- package/README.fr.md +59 -30
- package/README.gr.md +58 -29
- package/README.he.md +58 -29
- package/README.it.md +58 -29
- package/README.ja.md +58 -29
- package/README.ko.md +58 -29
- package/README.md +95 -56
- package/README.no.md +58 -29
- package/README.pl.md +58 -29
- package/README.ru.md +58 -29
- package/README.th.md +58 -29
- package/README.tr.md +58 -29
- package/README.uk.md +58 -29
- package/README.vi.md +58 -29
- package/README.zh.md +58 -29
- package/README.zht.md +58 -29
- package/dist/cli.d.mts +218 -14
- package/dist/cli.mjs +1410 -883
- package/dist/mcp/stdio.mjs +1072 -408
- package/dist/scan-pipeline-Bg-46cLS.mjs +2 -0
- package/dist/{scan-pipeline-CAH9_Qgh.mjs → scan-pipeline-CCJdEKNa.mjs} +1443 -809
- package/package.json +52 -8
- package/dist/scan-pipeline-CRe7-MQn.mjs +0 -2
package/dist/cli.d.mts
CHANGED
|
@@ -235,6 +235,68 @@ interface DimensionScore {
|
|
|
235
235
|
infos: number;
|
|
236
236
|
}
|
|
237
237
|
type AnalysisStatus = "complete" | "partial";
|
|
238
|
+
/**
|
|
239
|
+
* The normalized per-test runtime evidence record as it appears in a report
|
|
240
|
+
* (plan V5-011). Structurally the `EvidenceRecord` from
|
|
241
|
+
* `src/engine/evidence-core.ts`, restated here so the report schema does not
|
|
242
|
+
* depend on an engine module's internals — the wire shape is a contract.
|
|
243
|
+
*/
|
|
244
|
+
interface EvidenceRecordShape {
|
|
245
|
+
source: string;
|
|
246
|
+
artifact: string;
|
|
247
|
+
file: string;
|
|
248
|
+
title: string;
|
|
249
|
+
line?: number;
|
|
250
|
+
status: {
|
|
251
|
+
final: string;
|
|
252
|
+
failed: boolean;
|
|
253
|
+
retried: boolean;
|
|
254
|
+
passedOnRetry: boolean;
|
|
255
|
+
skipped: boolean;
|
|
256
|
+
timedOut: boolean;
|
|
257
|
+
};
|
|
258
|
+
attempts: number;
|
|
259
|
+
durationMs: number;
|
|
260
|
+
errors: string[];
|
|
261
|
+
attachments: string[];
|
|
262
|
+
provenance: {
|
|
263
|
+
core: string;
|
|
264
|
+
ingest: string;
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Candidate binding (plan V5-010).
|
|
269
|
+
*
|
|
270
|
+
* The immutable identity of the release candidate a run was produced against.
|
|
271
|
+
* It is what makes a claim replayable: "this verdict belongs to candidate
|
|
272
|
+
* X, built from commit Y with lockfile Z" can be re-checked; "this verdict
|
|
273
|
+
* belongs to whatever was on the machine" cannot.
|
|
274
|
+
*
|
|
275
|
+
* Every field is required. A partial binding is worse than none, because a
|
|
276
|
+
* consumer cannot tell which link is missing — so an unbound run omits the
|
|
277
|
+
* whole object rather than filling in what it has.
|
|
278
|
+
*/
|
|
279
|
+
interface CandidateBinding {
|
|
280
|
+
/** The candidate manifest's own id. */
|
|
281
|
+
manifestId: string;
|
|
282
|
+
/** WORKING_CANDIDATE | RELEASE_CANDIDATE. */
|
|
283
|
+
state: "WORKING_CANDIDATE" | "RELEASE_CANDIDATE";
|
|
284
|
+
/**
|
|
285
|
+
* The immutable commit this candidate is bound to, or null for a working
|
|
286
|
+
* candidate — which by definition has no commit yet.
|
|
287
|
+
*/
|
|
288
|
+
candidateSha: string | null;
|
|
289
|
+
/** The commit the candidate was branched from. */
|
|
290
|
+
baseSha: string;
|
|
291
|
+
/** sha256 of package.json as published for the candidate. */
|
|
292
|
+
packageSha256: string;
|
|
293
|
+
/** sha256 of the lockfile as published for the candidate. */
|
|
294
|
+
lockfileSha256: string;
|
|
295
|
+
/** Who owns the candidate. "UNASSIGNED" is a real, reportable value. */
|
|
296
|
+
owner: string;
|
|
297
|
+
/** NOT_AUTHORIZED | AUTHORIZED. Never inferred from evidence. */
|
|
298
|
+
releaseAuthorizationState: "NOT_AUTHORIZED" | "AUTHORIZED";
|
|
299
|
+
}
|
|
238
300
|
interface ScanResult {
|
|
239
301
|
schemaVersion: typeof SCHEMA_VERSION;
|
|
240
302
|
/** False when budget expired or files were skipped (§18.3). */
|
|
@@ -382,6 +444,29 @@ interface ScanResult {
|
|
|
382
444
|
scoringModelVersion?: string;
|
|
383
445
|
frameworkSupportMatrixVersion?: string;
|
|
384
446
|
commit?: string;
|
|
447
|
+
/** The worktree tree hash the run was bound to, when known. */
|
|
448
|
+
tree?: string;
|
|
449
|
+
/** The lockfile digest the run was bound to, when known. */
|
|
450
|
+
lockfile?: string;
|
|
451
|
+
/**
|
|
452
|
+
* Which identity links this run actually bound (plan V5-010). Derived, not
|
|
453
|
+
* asserted by each consumer: a claim is replayable only when every link it
|
|
454
|
+
* depends on is present.
|
|
455
|
+
*
|
|
456
|
+
* OPTIONAL on purpose. The machine contract is v1 additive-only, so a
|
|
457
|
+
* report written before this field existed has none, and a reader that
|
|
458
|
+
* required it would reject exactly the older artifacts it must tolerate.
|
|
459
|
+
* Absence means "produced by a build that did not record bindings" — never
|
|
460
|
+
* "bound to everything".
|
|
461
|
+
*/
|
|
462
|
+
boundLinks?: Array<"input" | "rules" | "config" | "engine" | "commit" | "tree" | "lockfile" | "candidate">;
|
|
463
|
+
/**
|
|
464
|
+
* The release candidate this run is bound to (plan V5-010). Absent for an
|
|
465
|
+
* ordinary scan of a working tree — a run is not a release candidate, and
|
|
466
|
+
* saying otherwise would let a local scan stand in for authorized
|
|
467
|
+
* evidence.
|
|
468
|
+
*/
|
|
469
|
+
candidate?: CandidateBinding;
|
|
385
470
|
};
|
|
386
471
|
/**
|
|
387
472
|
* Evidence Graph (R4c): the chain-law links (VERDICT ← EVIDENCE ←
|
|
@@ -401,6 +486,34 @@ interface ScanResult {
|
|
|
401
486
|
configFingerprint: string;
|
|
402
487
|
engineVersion: string;
|
|
403
488
|
};
|
|
489
|
+
/** The release candidate the verdict belongs to, when bound (V5-010). */
|
|
490
|
+
candidate?: {
|
|
491
|
+
manifestId: string;
|
|
492
|
+
candidateSha: string | null;
|
|
493
|
+
};
|
|
494
|
+
};
|
|
495
|
+
/**
|
|
496
|
+
* The normalized evidence core (plan V5-011).
|
|
497
|
+
*
|
|
498
|
+
* Present whenever the run ingested a runtime report. `records` is the
|
|
499
|
+
* canonical, deterministically-ordered set that every downstream consumer
|
|
500
|
+
* reads — before this, the core was computed and discarded inside the
|
|
501
|
+
* pipeline, so a re-derivation had to re-parse the report and could disagree
|
|
502
|
+
* with the verdict it was supposed to explain.
|
|
503
|
+
*
|
|
504
|
+
* Empty `records` with a null `artifact` means no runtime evidence was
|
|
505
|
+
* found, which is different from a run that found an empty report.
|
|
506
|
+
*/
|
|
507
|
+
evidence?: {
|
|
508
|
+
records: Array<EvidenceRecordShape>;
|
|
509
|
+
counts: {
|
|
510
|
+
total: number;
|
|
511
|
+
failed: number;
|
|
512
|
+
flaky: number;
|
|
513
|
+
skipped: number;
|
|
514
|
+
timedOut: number;
|
|
515
|
+
};
|
|
516
|
+
artifact: string | null;
|
|
404
517
|
};
|
|
405
518
|
/**
|
|
406
519
|
* Local incremental cache report (Beta-to-Stable plan, M5.2). Present
|
|
@@ -639,6 +752,9 @@ declare class DependencyGraph {
|
|
|
639
752
|
getDependents(path: string): string[];
|
|
640
753
|
get allPaths(): string[];
|
|
641
754
|
get size(): number;
|
|
755
|
+
/** Whether the graph knows this exact key. Reachability must not
|
|
756
|
+
* treat "not in the graph" as "nothing to traverse" without saying so. */
|
|
757
|
+
has(path: string): boolean;
|
|
642
758
|
}
|
|
643
759
|
//#endregion
|
|
644
760
|
//#region src/discovery/workspace.d.ts
|
|
@@ -657,9 +773,18 @@ interface Workspace {
|
|
|
657
773
|
}
|
|
658
774
|
//#endregion
|
|
659
775
|
//#region src/discovery/frameworks.d.ts
|
|
660
|
-
|
|
776
|
+
/**
|
|
777
|
+
* The catalogued frameworks whose detection is implemented today.
|
|
778
|
+
*
|
|
779
|
+
* Every entry must exist in the inventory — enforced by the parity spec, not
|
|
780
|
+
* by comment.
|
|
781
|
+
*/
|
|
782
|
+
declare const DETECTABLE_TEST_FRAMEWORKS: readonly ["jest", "vitest", "playwright"];
|
|
783
|
+
/** The detection output type, in the inventory's vocabulary. */
|
|
784
|
+
type DetectedFramework = (typeof DETECTABLE_TEST_FRAMEWORKS)[number];
|
|
661
785
|
interface FrameworkInfo$1 {
|
|
662
|
-
frameworks
|
|
786
|
+
/** Detected frameworks, as inventory ids. */
|
|
787
|
+
frameworks: DetectedFramework[];
|
|
663
788
|
/** True when no config evidence was found at all. */
|
|
664
789
|
unknown: boolean;
|
|
665
790
|
}
|
|
@@ -991,8 +1116,19 @@ interface LanguageAdapter {
|
|
|
991
1116
|
* Contract: resolve to a ParsedAst on success, `undefined` when this
|
|
992
1117
|
* adapter has no AST layer (or parsing failed — rules fall back to the
|
|
993
1118
|
* regex path either way). Never throws.
|
|
1119
|
+
*
|
|
1120
|
+
* May return the result directly as well as a promise: the ts-morph path
|
|
1121
|
+
* (plan V5-021) is synchronous, and forcing it to allocate a promise per
|
|
1122
|
+
* file would be a cost the shared seam has no business imposing. The
|
|
1123
|
+
* pipeline awaits either form.
|
|
1124
|
+
*
|
|
1125
|
+
* Declared as a PROPERTY, not a method signature. A method signature
|
|
1126
|
+
* promises a `this` binding that no adapter uses, and it makes every
|
|
1127
|
+
* consumer that reads `adapter.parseAst` trip the unbound-method rule —
|
|
1128
|
+
* which is a lint error that gets suppressed rather than a design that
|
|
1129
|
+
* gets fixed, so the shape has to say what it means.
|
|
994
1130
|
*/
|
|
995
|
-
parseAst
|
|
1131
|
+
parseAst?: (file: ParsedFile) => ParsedAst | undefined | Promise<ParsedAst | undefined>;
|
|
996
1132
|
/**
|
|
997
1133
|
* Run all rules this adapter hosts against one file. `onCrash` is
|
|
998
1134
|
* invoked when a rule throws (audit R-9) — the crash is still
|
|
@@ -1045,6 +1181,55 @@ interface UniversalRule {
|
|
|
1045
1181
|
run(file: ParsedFile): Array<Omit<Finding, "ruleId" | "category">>;
|
|
1046
1182
|
}
|
|
1047
1183
|
//#endregion
|
|
1184
|
+
//#region src/engine/evidence-core.d.ts
|
|
1185
|
+
/**
|
|
1186
|
+
* The core's own version — stamped into every record's provenance so a
|
|
1187
|
+
* consumer can tell which normalization contract produced a record.
|
|
1188
|
+
* Bump ONLY on a semantic change to the normalization itself.
|
|
1189
|
+
*/
|
|
1190
|
+
declare const EVIDENCE_CORE_VERSION = "evidence-core@1";
|
|
1191
|
+
/** Evidence source formats the core understands today (WI-17 adds trace.zip). */
|
|
1192
|
+
type EvidenceSource = ForensicsReport["source"];
|
|
1193
|
+
/** Normalized per-test runtime evidence (plan WI-2 field contract). */
|
|
1194
|
+
interface EvidenceRecord {
|
|
1195
|
+
/** Where this evidence came from (format identity). */
|
|
1196
|
+
source: EvidenceSource;
|
|
1197
|
+
/** Ingested artifact identity — the report path the records derive from. */
|
|
1198
|
+
artifact: string;
|
|
1199
|
+
/** Test identity: file + title (+ declaration line when known). */
|
|
1200
|
+
file: string;
|
|
1201
|
+
title: string;
|
|
1202
|
+
/** 1-based declaration line when the source carries one (JUnit: absent). */
|
|
1203
|
+
line?: number;
|
|
1204
|
+
/** Normalized execution status facts. */
|
|
1205
|
+
status: {
|
|
1206
|
+
/** Last attempt's outcome. */
|
|
1207
|
+
final: RunStatus;
|
|
1208
|
+
/** Failed at least once across attempts. */
|
|
1209
|
+
failed: boolean;
|
|
1210
|
+
/** Executed more than once. */
|
|
1211
|
+
retried: boolean;
|
|
1212
|
+
/** Passed only on attempt >= 2 (TRUE-FLAKE). */
|
|
1213
|
+
passedOnRetry: boolean;
|
|
1214
|
+
skipped: boolean;
|
|
1215
|
+
/** Final attempt timed out. */
|
|
1216
|
+
timedOut: boolean;
|
|
1217
|
+
};
|
|
1218
|
+
/** Number of attempts (retries = attempts − 1). */
|
|
1219
|
+
attempts: number;
|
|
1220
|
+
/** Total duration across attempts. */
|
|
1221
|
+
durationMs: number;
|
|
1222
|
+
/** Error messages, in report order. Empty: not captured by this source yet. */
|
|
1223
|
+
errors: string[];
|
|
1224
|
+
/** Attachment names/paths. Empty: not captured by this source yet (WI-17). */
|
|
1225
|
+
attachments: string[];
|
|
1226
|
+
/** Where the record came from and under which normalization contract. */
|
|
1227
|
+
provenance: {
|
|
1228
|
+
core: typeof EVIDENCE_CORE_VERSION;
|
|
1229
|
+
ingest: "mjolnir.forensics";
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
//#endregion
|
|
1048
1233
|
//#region src/engine/provenance.d.ts
|
|
1049
1234
|
type FileProvenance = "unmarked" | "generated-marked" | "codegen-like";
|
|
1050
1235
|
/** Classify one file's provenance. Pure. */
|
|
@@ -1072,7 +1257,7 @@ interface IgnoreEntry {
|
|
|
1072
1257
|
ruleId: string;
|
|
1073
1258
|
files?: string[];
|
|
1074
1259
|
reason: string;
|
|
1075
|
-
/** ISO date;
|
|
1260
|
+
/** ISO date; omitted means the suppression has no expiry. */
|
|
1076
1261
|
expires?: string;
|
|
1077
1262
|
}
|
|
1078
1263
|
interface QADoctorConfig {
|
|
@@ -1313,6 +1498,12 @@ interface PostScanResult {
|
|
|
1313
1498
|
frameworks: ReturnType<typeof detectFrameworks>;
|
|
1314
1499
|
runtimeReportPath: string | undefined;
|
|
1315
1500
|
runtimeIncomplete: boolean;
|
|
1501
|
+
/**
|
|
1502
|
+
* The normalized evidence core (V5-011). Persisted rather than discarded,
|
|
1503
|
+
* so every post-ingest projection reads records instead of re-parsing a
|
|
1504
|
+
* report that may have changed underneath it.
|
|
1505
|
+
*/
|
|
1506
|
+
evidenceRecords: EvidenceRecord[];
|
|
1316
1507
|
/** Aggregate forensic classifications from the ingested runtime report. */
|
|
1317
1508
|
forensicVerdicts: ForensicVerdictSummary | undefined;
|
|
1318
1509
|
config: ReturnType<typeof loadConfig>["config"];
|
|
@@ -1360,6 +1551,7 @@ interface AssembleScanResultInput {
|
|
|
1360
1551
|
frameworks: ReturnType<typeof detectFrameworks>;
|
|
1361
1552
|
runtimeReportPath: string | undefined;
|
|
1362
1553
|
runtimeIncomplete?: boolean;
|
|
1554
|
+
evidenceRecords?: EvidenceRecord[];
|
|
1363
1555
|
forensicVerdicts: ForensicVerdictSummary | undefined;
|
|
1364
1556
|
config: ReturnType<typeof loadConfig>["config"];
|
|
1365
1557
|
fileProvenance: Array<{
|
|
@@ -1393,7 +1585,7 @@ declare function runScan$1(args: CliArgs, hooks?: ScanHooks): Promise<ScanResult
|
|
|
1393
1585
|
* scripts/sync-sarif-version.cjs and guarded by the version-consistency
|
|
1394
1586
|
* spec. cli.ts re-exports this as CLI_VERSION.
|
|
1395
1587
|
*/
|
|
1396
|
-
declare const ENGINE_VERSION = "
|
|
1588
|
+
declare const ENGINE_VERSION = "4.0.0";
|
|
1397
1589
|
//#endregion
|
|
1398
1590
|
//#region src/cli-io.d.ts
|
|
1399
1591
|
/**
|
|
@@ -1575,11 +1767,17 @@ export declare function runReleaseTrustCommand(argv: string[], io?: {
|
|
|
1575
1767
|
* Entry point for `mjolnir business-case`.
|
|
1576
1768
|
*
|
|
1577
1769
|
* Flags:
|
|
1578
|
-
* --
|
|
1579
|
-
*
|
|
1580
|
-
*
|
|
1581
|
-
* --projected <months> Show projected savings over N months
|
|
1770
|
+
* --incident-cost <n> The cost of ONE false-green incident in your
|
|
1771
|
+
* organisation. Until you supply it, no dollar
|
|
1772
|
+
* figure is printed at all.
|
|
1582
1773
|
* --strict Include quarantine-tier findings
|
|
1774
|
+
*
|
|
1775
|
+
* `--history` and `--projected` are GONE. Both promised arithmetic this
|
|
1776
|
+
* tool cannot do: `--history` claimed to estimate from actual scan
|
|
1777
|
+
* improvements while reading no history at all, and `--projected` divided
|
|
1778
|
+
* the total by six and called the quotient a monthly rate. A flag that
|
|
1779
|
+
* does not do what its help says is worse than no flag, because the help
|
|
1780
|
+
* is the promise.
|
|
1583
1781
|
*/
|
|
1584
1782
|
export declare function runBusinessCaseCommand(argv: string[], io?: {
|
|
1585
1783
|
out: Output;
|
|
@@ -1623,7 +1821,7 @@ export declare function runPolicyCommand(argv: string[], io: {
|
|
|
1623
1821
|
export declare function runQuarantineCommand(argv: string[], io: {
|
|
1624
1822
|
out: Output;
|
|
1625
1823
|
err: Output;
|
|
1626
|
-
}):
|
|
1824
|
+
}): number;
|
|
1627
1825
|
//#endregion
|
|
1628
1826
|
//#region src/commands/analyze.d.ts
|
|
1629
1827
|
export declare function runAnalyzeCommand(argv: string[], io: {
|
|
@@ -1724,9 +1922,14 @@ export declare function parseArgsOrUsage(argv: string[], io: {
|
|
|
1724
1922
|
*/
|
|
1725
1923
|
export declare function validateScanTarget(target: string, err: Output): number | null;
|
|
1726
1924
|
/**
|
|
1727
|
-
* Exit-code decision for
|
|
1728
|
-
*
|
|
1729
|
-
*
|
|
1925
|
+
* Exit-code decision for findings only (audit H-7): the previously-dead
|
|
1926
|
+
* config.gate field selects which severities block. Advisory (E0) findings
|
|
1927
|
+
* never gate at any level.
|
|
1928
|
+
*
|
|
1929
|
+
* This is a findings-only view of the one exit matrix in `claim-evidence`.
|
|
1930
|
+
* Callers that have just finished an ANALYSIS must use `scanExitCode`
|
|
1931
|
+
* instead — this function cannot see `partial`, and a truncated scan with
|
|
1932
|
+
* zero findings is exactly the case that turns a bug into a green build.
|
|
1730
1933
|
*/
|
|
1731
1934
|
export declare function exitForFindings(findings: readonly Finding[], gate: "advisory" | "error" | "warning"): number;
|
|
1732
1935
|
/** Testable `ci install` handler. Returns the process exit code. */
|
|
@@ -1756,4 +1959,5 @@ export declare function runHelpCommand(argv: string[], io?: {
|
|
|
1756
1959
|
}): number;
|
|
1757
1960
|
export declare function isEntryPoint(): boolean;
|
|
1758
1961
|
//#endregion
|
|
1759
|
-
export { ENGINE_VERSION as CLI_VERSION, type CliArgs, type Output, type ScanHooks };
|
|
1962
|
+
export { ENGINE_VERSION as CLI_VERSION, type CliArgs, type Output, type ScanHooks };
|
|
1963
|
+
//# sourceMappingURL=cli.d.mts.map
|