mjolnir-qa 2.0.2 → 2.1.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.
@@ -904,7 +904,7 @@ function buildEvidenceGraph(parts) {
904
904
  * scripts/sync-sarif-version.cjs and guarded by the version-consistency
905
905
  * spec. cli.ts re-exports this as CLI_VERSION.
906
906
  */
907
- const ENGINE_VERSION = "2.0.2";
907
+ const ENGINE_VERSION = "2.1.0";
908
908
  //#endregion
909
909
  //#region src/engine/contract-versions.ts
910
910
  /**
@@ -14455,13 +14455,15 @@ function applyPostScanProcessing(findings, workspace, args, hooks, scanRoot, dec
14455
14455
  for (const w of warnings) hooks.onConfigWarning?.(w);
14456
14456
  applySeverityOverrides(findings, config);
14457
14457
  const active = loadSuppressions(workspace.root).entries.filter((e) => e.status === "active");
14458
- const suppressionCount = active.length;
14458
+ hooks.onPreSuppressionFindings?.([...findings]);
14459
+ let suppressionCount = 0;
14459
14460
  if (active.length > 0) {
14460
14461
  const ruleOnly = new Set(active.filter((e) => !e.files?.length).map((e) => e.ruleId));
14461
14462
  const kept = findings.filter((f) => {
14462
14463
  if (ruleOnly.has(f.ruleId)) return false;
14463
14464
  return !active.some((e) => e.files?.length && e.ruleId === f.ruleId && e.files.some((g) => pathMatchesGlob(f.file, g)));
14464
14465
  });
14466
+ suppressionCount = findings.length - kept.length;
14465
14467
  findings.length = 0;
14466
14468
  for (const f of kept) findings.push(f);
14467
14469
  }
@@ -14780,6 +14782,7 @@ async function runScan(args, hooks = {}) {
14780
14782
  scopeUnrecognized++;
14781
14783
  }
14782
14784
  });
14785
+ hooks.onTestFilesDiscovered?.(testFiles);
14783
14786
  const analysis = await runFileAnalysisPhase(findings, testFiles, workspace, activeRules, hooks, cache, rulesDigest, deadline, truncationReasons, declarationsByFile, fileProvenance, (ruleId, file, error) => {
14784
14787
  rulesCrashed++;
14785
14788
  hooks.onRuleCrash?.(ruleId, file, error);
@@ -0,0 +1,2 @@
1
+ import { m as runScan } from "./scan-pipeline-MQGUSey3.mjs";
2
+ export { runScan };
@@ -945,7 +945,7 @@ function buildEvidenceGraph(parts) {
945
945
  * scripts/sync-sarif-version.cjs and guarded by the version-consistency
946
946
  * spec. cli.ts re-exports this as CLI_VERSION.
947
947
  */
948
- const ENGINE_VERSION = "2.0.2";
948
+ const ENGINE_VERSION = "2.1.0";
949
949
  //#endregion
950
950
  //#region src/engine/contract-versions.ts
951
951
  /**
@@ -1489,6 +1489,10 @@ function globBody(glob) {
1489
1489
  }
1490
1490
  return re;
1491
1491
  }
1492
+ /** Anchored full-path glob — the primitive the matcher builds on. */
1493
+ function globToRegExp(glob) {
1494
+ return new RegExp(`^${globBody(glob)}$`);
1495
+ }
1492
1496
  /** Defaults-only matcher for callers that have no scan context. */
1493
1497
  const DEFAULT_IGNORE_MATCHER = createMatcherFromPatterns([]);
1494
1498
  /**
@@ -11946,6 +11950,22 @@ function parseManifest(filePath) {
11946
11950
  if (filePath.endsWith("pyproject.toml")) return parsePyprojectToml(filePath);
11947
11951
  if (filePath.endsWith("pom.xml")) return parsePomXml(filePath);
11948
11952
  }
11953
+ /**
11954
+ * Given a set of starting files (e.g. test files), return all files
11955
+ * transitively reachable through the dependency graph.
11956
+ */
11957
+ function getReachableFiles(fromFiles, graph) {
11958
+ const reachable = /* @__PURE__ */ new Set();
11959
+ const stack = [...fromFiles];
11960
+ while (stack.length > 0) {
11961
+ const current = stack.pop();
11962
+ if (current === void 0) continue;
11963
+ if (reachable.has(current)) continue;
11964
+ reachable.add(current);
11965
+ for (const dep of graph.getDependencies(current)) if (!reachable.has(dep)) stack.push(dep);
11966
+ }
11967
+ return [...reachable].sort();
11968
+ }
11949
11969
  //#endregion
11950
11970
  //#region src/engine/incremental-analysis.ts
11951
11971
  /**
@@ -12521,7 +12541,7 @@ const HEADLINES = {
12521
12541
  critical: "The hammer is cracked — {n} findings break its edge.",
12522
12542
  warning: "The hammer holds — but {n} findings weigh it down.",
12523
12543
  trusted: "Held in worthy hands — {n} findings remain.",
12524
- forged: "Forged complete. Zero findings. The suite is clean.",
12544
+ forged: "Static score 100 — no findings on the analyzed surface.",
12525
12545
  unmeasured: "No tests found — the hammer cannot be weighed."
12526
12546
  };
12527
12547
  const RUNES = {
@@ -14062,12 +14082,12 @@ function loadSuppressions(root) {
14062
14082
  };
14063
14083
  }
14064
14084
  function renderSuppressions(report) {
14065
- if (report.total === 0) return "\nNo suppressed findings. Full transparency maintained.\n";
14085
+ if (report.total === 0) return "\nNo configured suppression entries.\n";
14066
14086
  const lines = [
14067
14087
  "",
14068
14088
  sectionHeader("QUALITY GOVERNANCE", ui),
14069
14089
  "",
14070
- `Suppressed findings: ${report.total}`,
14090
+ `Configured entries: ${report.total}`,
14071
14091
  `Active: ${report.active}`,
14072
14092
  `Expired: ${report.expired}`,
14073
14093
  ""
@@ -14931,13 +14951,15 @@ function applyPostScanProcessing(findings, workspace, args, hooks, scanRoot, dec
14931
14951
  for (const w of warnings) hooks.onConfigWarning?.(w);
14932
14952
  applySeverityOverrides(findings, config);
14933
14953
  const active = loadSuppressions(workspace.root).entries.filter((e) => e.status === "active");
14934
- const suppressionCount = active.length;
14954
+ hooks.onPreSuppressionFindings?.([...findings]);
14955
+ let suppressionCount = 0;
14935
14956
  if (active.length > 0) {
14936
14957
  const ruleOnly = new Set(active.filter((e) => !e.files?.length).map((e) => e.ruleId));
14937
14958
  const kept = findings.filter((f) => {
14938
14959
  if (ruleOnly.has(f.ruleId)) return false;
14939
14960
  return !active.some((e) => e.files?.length && e.ruleId === f.ruleId && e.files.some((g) => pathMatchesGlob(f.file, g)));
14940
14961
  });
14962
+ suppressionCount = findings.length - kept.length;
14941
14963
  findings.length = 0;
14942
14964
  for (const f of kept) findings.push(f);
14943
14965
  }
@@ -15256,6 +15278,7 @@ async function runScan(args, hooks = {}) {
15256
15278
  scopeUnrecognized++;
15257
15279
  }
15258
15280
  });
15281
+ hooks.onTestFilesDiscovered?.(testFiles);
15259
15282
  const analysis = await runFileAnalysisPhase(findings, testFiles, workspace, activeRules, hooks, cache, rulesDigest, deadline, truncationReasons, declarationsByFile, fileProvenance, (ruleId, file, error) => {
15260
15283
  rulesCrashed++;
15261
15284
  hooks.onRuleCrash?.(ruleId, file, error);
@@ -15306,4 +15329,4 @@ async function runScan(args, hooks = {}) {
15306
15329
  return result;
15307
15330
  }
15308
15331
  //#endregion
15309
- export { SCAN_ADAPTERS as $, box as A, headlineFor as B, buildFooter as C, plainContext as D, panel as E, scoreGauge as F, capForTier as G, EVIDENCE as H, shouldColorize as I, massCeiling as J, computeDimensions as K, shouldUseAscii as L, padTo as M, palette as N, sectionHeader as O, sanitizeData as P, resolveGitPath as Q, wrapText as R, FLAKE_GLYPH as S, isValidCategory as St, okIcon as T, TINT as U, BADGE_BAND as V, TRUST as W, RULES as X, RETIRED_RULE_IDS as Y, getRule as Z, summarizeForensicVerdicts as _, QA_IMPACT_LABELS as _t, applyPostScanProcessing as a, parseTsFile as at, renderSuppressions as b, deriveEvidenceLevel as bt, discoverAndParseRuntimeReport as c, createIgnoreMatcher as ct, isValidFindingRecord as d, loadConfig as dt, SEARCHED_FOR as et, pathMatchesGlob as f, isRecord as ft, selectAdapter as g, DEDUCTIONS as gt, scan_pipeline_exports as h, MEASURED_FP as ht, SUITE_INVALIDATING_RULE_IDS as i, computeCodeText as it, measure as j, severityIcon as k, discoverTestFilesPhase as l, isLintFixtureDir as lt, runScan as m, ENGINE_VERSION as mt, KNOWN_RULE_IDS as n, parseAzurePipeline as nt, assembleScanResult as o, detectFrameworks as ot, runFileAnalysisPhase as p, parseJsonFile as pt, deductionFor as q, OVERLAP_META_BY_RULE_ID as r, parseWorkflow as rt, buildUniversalRules as s, DEFAULT_IGNORE_MATCHER as st, EVIDENCE_OVERRIDES as t, isAzurePipelineFixture as tt, fallbackWorkspace as u, ConfigValidationError as ut, loadLocalRules as v, RULE_CATEGORIES as vt, nextStep as w, runForensics as x, isAdvisoryFinding as xt, loadSuppressions as y, SEVERITY_ORDER as yt, deriveScoreState as z };
15332
+ export { massCeiling as $, box as A, isAdvisoryFinding as At, headlineFor as B, buildFooter as C, buildEvidenceGraph as Ct, plainContext as D, RULE_CATEGORIES as Dt, panel as E, QA_IMPACT_LABELS as Et, scoreGauge as F, buildDependencyGraph as G, EVIDENCE as H, shouldColorize as I, classifyProvenance as J, getReachableFiles as K, shouldUseAscii as L, padTo as M, palette as N, sectionHeader as O, SEVERITY_ORDER as Ot, sanitizeData as P, deductionFor as Q, wrapText as R, FLAKE_GLYPH as S, ENGINE_VERSION as St, okIcon as T, DEDUCTIONS as Tt, TINT as U, BADGE_BAND as V, TRUST as W, capForTier as X, computeAgenticProfile as Y, computeDimensions as Z, summarizeForensicVerdicts as _, ConfigValidationError as _t, applyPostScanProcessing as a, SEARCHED_FOR as at, renderSuppressions as b, isRecord as bt, discoverAndParseRuntimeReport as c, parseWorkflow as ct, isValidFindingRecord as d, parseTsFile as dt, RETIRED_RULE_IDS as et, pathMatchesGlob as f, detectFrameworks as ft, selectAdapter as g, isLintFixtureDir as gt, scan_pipeline_exports as h, globToRegExp as ht, SUITE_INVALIDATING_RULE_IDS as i, SCAN_ADAPTERS as it, measure as j, isValidCategory as jt, severityIcon as k, deriveEvidenceLevel as kt, discoverTestFilesPhase as l, parseYamlGuarded as lt, runScan as m, createIgnoreMatcher as mt, KNOWN_RULE_IDS as n, getRule as nt, assembleScanResult as o, isAzurePipelineFixture as ot, runFileAnalysisPhase as p, DEFAULT_IGNORE_MATCHER as pt, correlateFindings as q, OVERLAP_META_BY_RULE_ID as r, resolveGitPath as rt, buildUniversalRules as s, parseAzurePipeline as st, EVIDENCE_OVERRIDES as t, RULES as tt, fallbackWorkspace as u, computeCodeText as ut, loadLocalRules as v, isSuppressionActive as vt, nextStep as w, MEASURED_FP as wt, runForensics as x, parseJsonFile as xt, loadSuppressions as y, loadConfig as yt, deriveScoreState as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mjolnir-qa",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "description": "Mjölnir — the Verification Trust Engine for QA. Audits test suites and CI pipelines, reports a worthiness score and prioritized findings.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -25,15 +25,18 @@
25
25
  "mcp": "node dist/mcp/stdio.mjs",
26
26
  "test": "vitest run",
27
27
  "bench:scan": "tsx scripts/bench-scan.ts .mjolnir --files 300",
28
- "test:stress": "vitest run --config vitest.stress.config.ts",
28
+ "test:stress": "vitest run --config vitest.stress.config.ts && node tests/stress/soak.mjs && node tests/stress/concurrent.mjs",
29
29
  "test:coverage": "vitest run --coverage",
30
+ "test:coverage:ci": "vitest run --coverage --no-file-parallelism --testTimeout=120000 --hookTimeout=120000",
30
31
  "coverage:ratchet": "node scripts/check-coverage-ratchet.mjs",
32
+ "audit:ci": "npm audit --audit-level=moderate",
31
33
  "test:watch": "vitest",
32
34
  "lint": "eslint . --max-warnings=0 && prettier --check .",
33
35
  "format": "prettier --write .",
34
36
  "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json && tsx scripts/typecheck-fixtures.ts",
35
- "certify": "npm run lint && npm run typecheck && npm run test && npx vitest run tests/contract/",
36
- "ci-local": "npm run certify && npm run brand:doctor && npm run brand:doctor:selftest && npm run brand:fonts:check",
37
+ "certify": "npm run build && npm run lint && npm run typecheck && npm run test && npx vitest run tests/contract/",
38
+ "certify:ci": "npm run build && npm run lint && npm run typecheck && npm run test:coverage:ci && npx vitest run tests/contract/",
39
+ "ci-local": "npm run certify:ci && npm run test:property && npm run test:fuzz && npm run coverage:ratchet && npm run audit:ci && npm run brand:doctor && npm run brand:doctor:selftest && npm run brand:fonts:check && npm run site:doctor && npm run ci-local:parity",
37
40
  "golden:update": "tsx tests/golden/gen.ts",
38
41
  "detector-hashes:update": "tsx scripts/generate-detector-hashes.ts",
39
42
  "corpus:regression": "tsx tests/corpus/audit.ts",
@@ -66,6 +69,9 @@
66
69
  "changelog:check": "tsx scripts/check-changelog.ts --expect-version $(node -p \"require('./package.json').version\")",
67
70
  "reporter:version-check": "tsx scripts/check-reporter-version.ts",
68
71
  "self-scan": "node dist/cli.mjs .",
72
+ "ci-local:parity": "node scripts/check-ci-local-parity.mjs",
73
+ "test:property": "node scripts/check-property-runs.mjs && vitest run --config vitest.property.config.ts",
74
+ "test:fuzz": "vitest run --config vitest.fuzz.config.ts",
69
75
  "prepare": "husky",
70
76
  "prepublishOnly": "npm run build",
71
77
  "docs:architecture": "tsx scripts/generate-readme-architecture.ts",
@@ -107,6 +113,8 @@
107
113
  "yaml": "^2.5.0"
108
114
  },
109
115
  "devDependencies": {
116
+ "@commitlint/cli": "^19.8.1",
117
+ "@commitlint/config-conventional": "^19.8.1",
110
118
  "@eslint/js": "^10.0.1",
111
119
  "@playwright/test": "^1.50.0",
112
120
  "@types/node": "^26.4.0",
@@ -1,2 +0,0 @@
1
- import { m as runScan } from "./scan-pipeline-D3Yk2cef.mjs";
2
- export { runScan };