@mneme-ai/core 0.15.0 → 0.17.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.
Files changed (53) hide show
  1. package/dist/forensics/anomaly.d.ts +83 -0
  2. package/dist/forensics/anomaly.d.ts.map +1 -0
  3. package/dist/forensics/anomaly.js +218 -0
  4. package/dist/forensics/anomaly.js.map +1 -0
  5. package/dist/forensics/forensics.test.d.ts +2 -0
  6. package/dist/forensics/forensics.test.d.ts.map +1 -0
  7. package/dist/forensics/forensics.test.js +281 -0
  8. package/dist/forensics/forensics.test.js.map +1 -0
  9. package/dist/forensics/index.d.ts +5 -0
  10. package/dist/forensics/index.d.ts.map +1 -0
  11. package/dist/forensics/index.js +5 -0
  12. package/dist/forensics/index.js.map +1 -0
  13. package/dist/forensics/likelihood.d.ts +120 -0
  14. package/dist/forensics/likelihood.d.ts.map +1 -0
  15. package/dist/forensics/likelihood.js +161 -0
  16. package/dist/forensics/likelihood.js.map +1 -0
  17. package/dist/forensics/loci.d.ts +54 -0
  18. package/dist/forensics/loci.d.ts.map +1 -0
  19. package/dist/forensics/loci.js +164 -0
  20. package/dist/forensics/loci.js.map +1 -0
  21. package/dist/forensics/vulnhunt.d.ts +62 -0
  22. package/dist/forensics/vulnhunt.d.ts.map +1 -0
  23. package/dist/forensics/vulnhunt.js +217 -0
  24. package/dist/forensics/vulnhunt.js.map +1 -0
  25. package/dist/guardian/guardian.d.ts +93 -0
  26. package/dist/guardian/guardian.d.ts.map +1 -0
  27. package/dist/guardian/guardian.js +170 -0
  28. package/dist/guardian/guardian.js.map +1 -0
  29. package/dist/guardian/guardian.test.d.ts +2 -0
  30. package/dist/guardian/guardian.test.d.ts.map +1 -0
  31. package/dist/guardian/guardian.test.js +154 -0
  32. package/dist/guardian/guardian.test.js.map +1 -0
  33. package/dist/guardian/index.d.ts +2 -0
  34. package/dist/guardian/index.d.ts.map +1 -0
  35. package/dist/guardian/index.js +2 -0
  36. package/dist/guardian/index.js.map +1 -0
  37. package/dist/index.d.ts +2 -0
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +2 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/retrieve/index.d.ts +1 -0
  42. package/dist/retrieve/index.d.ts.map +1 -1
  43. package/dist/retrieve/index.js +1 -0
  44. package/dist/retrieve/index.js.map +1 -1
  45. package/dist/retrieve/novel-scoring.d.ts +146 -0
  46. package/dist/retrieve/novel-scoring.d.ts.map +1 -0
  47. package/dist/retrieve/novel-scoring.js +256 -0
  48. package/dist/retrieve/novel-scoring.js.map +1 -0
  49. package/dist/retrieve/novel-scoring.test.d.ts +2 -0
  50. package/dist/retrieve/novel-scoring.test.d.ts.map +1 -0
  51. package/dist/retrieve/novel-scoring.test.js +221 -0
  52. package/dist/retrieve/novel-scoring.test.js.map +1 -0
  53. package/package.json +1 -1
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Insider-threat anomaly detection — flag commits that deviate from an
3
+ * author's baseline profile far enough that "compromised credentials"
4
+ * or "rogue contributor" become plausible explanations.
5
+ *
6
+ * Method: build a per-author baseline from their entire history (the
7
+ * "normal Alice"), then for each new commit measure deviation across
8
+ * four independent axes:
9
+ *
10
+ * • TIME — distance from author's UTC peak window
11
+ * • FILES — fraction of touched files the author has never
12
+ * touched before (out-of-domain signal)
13
+ * • STYLE — leading-verb novelty + commit-size deviation
14
+ * • SIZE — z-score of insertions+deletions vs author's median
15
+ *
16
+ * Each axis emits a normalized 0..1 deviation. The composite score is
17
+ * a weighted sum (not a vector norm — independent contribution is
18
+ * easier to explain to a security analyst).
19
+ *
20
+ * This is the bank/finance scenario. Use case: a credential is stolen,
21
+ * the attacker pushes a commit at 03:47 UTC touching auth code with
22
+ * verbs Alice never uses — Mneme flags it before review, with a
23
+ * specific explanation per axis.
24
+ *
25
+ * Pure data extraction. No external services. No false promise of 100%
26
+ * accuracy — anomaly detection is fundamentally probabilistic. We
27
+ * surface candidates with explanations; humans decide.
28
+ */
29
+ import type { Commit, FileChange } from "../types.js";
30
+ export interface AuthorBaseline {
31
+ author: string;
32
+ commitCount: number;
33
+ /** UTC peak hour (start of 4-hour window). */
34
+ peakHour: number;
35
+ /** Histogram of commits by UTC hour, normalized. */
36
+ hourHistogram: number[];
37
+ /** Files this author has ever touched (set). */
38
+ knownFiles: Set<string>;
39
+ /** Set of leading-verb tokens seen in subject lines. */
40
+ knownVerbs: Set<string>;
41
+ /** Median insertions+deletions per commit. */
42
+ medianChurn: number;
43
+ /** Median absolute deviation of churn (robust σ analog). */
44
+ churnMad: number;
45
+ }
46
+ export interface AnomalyDeviation {
47
+ axis: "time" | "files" | "style" | "size";
48
+ /** 0..1 — bigger is more anomalous. */
49
+ score: number;
50
+ /** Free-form note for rendering. */
51
+ note: string;
52
+ }
53
+ export interface AnomalyFinding {
54
+ commit: Commit;
55
+ /** Composite score in [0, 4]. */
56
+ totalDeviation: number;
57
+ /** Approximate σ from baseline (0.5 deviation ≈ 1σ heuristic). */
58
+ approxSigma: number;
59
+ axes: AnomalyDeviation[];
60
+ severity: "low" | "medium" | "high" | "critical";
61
+ /** Recommended next step. */
62
+ recommendation: string;
63
+ }
64
+ /**
65
+ * Build a baseline profile per author from all their historical commits.
66
+ *
67
+ * The caller passes commits AND file-changes; if file-changes are
68
+ * unavailable we fall back to commit.files (which carries paths only —
69
+ * still useful for the "files novelty" signal).
70
+ */
71
+ export declare function buildBaselines(commits: Commit[], fileChanges?: FileChange[]): Map<string, AuthorBaseline>;
72
+ /**
73
+ * Score a single commit against its author's baseline. Returns axis
74
+ * deviations + composite score.
75
+ */
76
+ export declare function scoreAnomaly(commit: Commit, baseline: AuthorBaseline, fileChanges?: FileChange[]): AnomalyFinding;
77
+ /**
78
+ * Score every commit in `commits` against the corresponding author
79
+ * baseline. Returns only findings whose composite score exceeds
80
+ * `threshold` (default 0.9 = ~"medium" severity).
81
+ */
82
+ export declare function detectAnomalies(commits: Commit[], baselines: Map<string, AuthorBaseline>, fileChanges?: FileChange[], threshold?: number): AnomalyFinding[];
83
+ //# sourceMappingURL=anomaly.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anomaly.d.ts","sourceRoot":"","sources":["../../src/forensics/anomaly.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gDAAgD;IAChD,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,wDAAwD;IACxD,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;IAC1C,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,gBAAgB,EAAE,CAAC;IACzB,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IACjD,6BAA6B;IAC7B,cAAc,EAAE,MAAM,CAAC;CACxB;AASD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EAAE,EACjB,WAAW,GAAE,UAAU,EAAO,GAC7B,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CA2E7B;AAQD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,cAAc,EACxB,WAAW,GAAE,UAAU,EAAO,GAC7B,cAAc,CAqGhB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,EACtC,WAAW,GAAE,UAAU,EAAO,EAC9B,SAAS,SAAM,GACd,cAAc,EAAE,CAUlB"}
@@ -0,0 +1,218 @@
1
+ const AXIS_WEIGHTS = {
2
+ time: 1.0,
3
+ files: 1.0,
4
+ style: 0.7,
5
+ size: 0.8,
6
+ };
7
+ /**
8
+ * Build a baseline profile per author from all their historical commits.
9
+ *
10
+ * The caller passes commits AND file-changes; if file-changes are
11
+ * unavailable we fall back to commit.files (which carries paths only —
12
+ * still useful for the "files novelty" signal).
13
+ */
14
+ export function buildBaselines(commits, fileChanges = []) {
15
+ const byAuthor = new Map();
16
+ for (const c of commits) {
17
+ const a = c.authorEmail.toLowerCase() || c.authorName.toLowerCase();
18
+ const arr = byAuthor.get(a);
19
+ if (arr)
20
+ arr.push(c);
21
+ else
22
+ byAuthor.set(a, [c]);
23
+ }
24
+ const fcByCommit = new Map();
25
+ for (const fc of fileChanges) {
26
+ const arr = fcByCommit.get(fc.commitHash);
27
+ if (arr)
28
+ arr.push(fc);
29
+ else
30
+ fcByCommit.set(fc.commitHash, [fc]);
31
+ }
32
+ const out = new Map();
33
+ for (const [author, list] of byAuthor) {
34
+ const hourHistogram = new Array(24).fill(0);
35
+ const knownFiles = new Set();
36
+ const knownVerbs = new Set();
37
+ const churnSamples = [];
38
+ for (const c of list) {
39
+ const t = new Date(c.authorDate).getTime();
40
+ if (!Number.isNaN(t)) {
41
+ const h = new Date(t).getUTCHours();
42
+ hourHistogram[h] = (hourHistogram[h] ?? 0) + 1;
43
+ }
44
+ for (const f of c.files ?? [])
45
+ knownFiles.add(f);
46
+ const subj = (c.subject || "").trim();
47
+ const w = (subj.match(/^[A-Za-z]+/)?.[0] || "").toLowerCase();
48
+ if (w)
49
+ knownVerbs.add(w);
50
+ const fcs = fcByCommit.get(c.hash) ?? [];
51
+ const churn = fcs.reduce((s, x) => s + x.insertions + x.deletions, 0);
52
+ churnSamples.push(churn);
53
+ }
54
+ // Normalize histogram
55
+ const total = list.length;
56
+ for (let i = 0; i < 24; i++)
57
+ hourHistogram[i] /= Math.max(1, total);
58
+ // Peak hour (4-hour band)
59
+ let peakHour = 0;
60
+ let bestSum = -1;
61
+ for (let i = 0; i < 24; i++) {
62
+ let s = 0;
63
+ for (let k = 0; k < 4; k++)
64
+ s += hourHistogram[(i + k) % 24];
65
+ if (s > bestSum) {
66
+ bestSum = s;
67
+ peakHour = i;
68
+ }
69
+ }
70
+ // Median + MAD churn
71
+ const sorted = [...churnSamples].sort((a, b) => a - b);
72
+ const medianChurn = median(sorted);
73
+ const deviations = churnSamples.map((x) => Math.abs(x - medianChurn));
74
+ deviations.sort((a, b) => a - b);
75
+ const churnMad = Math.max(1, median(deviations));
76
+ out.set(author, {
77
+ author,
78
+ commitCount: list.length,
79
+ peakHour,
80
+ hourHistogram,
81
+ knownFiles,
82
+ knownVerbs,
83
+ medianChurn,
84
+ churnMad,
85
+ });
86
+ }
87
+ return out;
88
+ }
89
+ function median(sorted) {
90
+ if (sorted.length === 0)
91
+ return 0;
92
+ const m = Math.floor(sorted.length / 2);
93
+ return sorted.length % 2 === 1 ? sorted[m] : (sorted[m - 1] + sorted[m]) / 2;
94
+ }
95
+ /**
96
+ * Score a single commit against its author's baseline. Returns axis
97
+ * deviations + composite score.
98
+ */
99
+ export function scoreAnomaly(commit, baseline, fileChanges = []) {
100
+ // ── TIME axis ──────────────────────────────────────────────────────
101
+ const t = new Date(commit.authorDate).getTime();
102
+ let timeScore = 0;
103
+ let timeNote = "time within author's normal window";
104
+ if (!Number.isNaN(t)) {
105
+ const h = new Date(t).getUTCHours();
106
+ // Distance to peak window (cyclic min over 4-hour window starting at peakHour)
107
+ const inWindow = (h - baseline.peakHour + 24) % 24;
108
+ const distance = Math.min(inWindow, 24 - inWindow);
109
+ if (distance >= 4) {
110
+ // Outside the 4-hour peak window — bigger distance = bigger score
111
+ timeScore = Math.min(1, (distance - 3) / 8); // 0 at edge, 1 at 11h+
112
+ timeNote = `commit hour ${pad2(h)}:00 UTC is ${distance}h from author's peak window ${pad2(baseline.peakHour)}:00–${pad2((baseline.peakHour + 4) % 24)}:00`;
113
+ }
114
+ // Hour-rarity bonus: if this hour is a near-zero in the histogram,
115
+ // bump the score even if it falls within "window"
116
+ const hourFreq = baseline.hourHistogram[h] ?? 0;
117
+ if (hourFreq < 0.01 && baseline.commitCount >= 20) {
118
+ timeScore = Math.max(timeScore, 0.7);
119
+ timeNote += ` · hour frequency ${pct(hourFreq)} in author history`;
120
+ }
121
+ }
122
+ // ── FILES axis ─────────────────────────────────────────────────────
123
+ const files = commit.files ?? [];
124
+ let unseen = 0;
125
+ const newFiles = [];
126
+ for (const f of files) {
127
+ if (!baseline.knownFiles.has(f)) {
128
+ unseen += 1;
129
+ newFiles.push(f);
130
+ }
131
+ }
132
+ const fileScore = files.length === 0 ? 0 : unseen / files.length;
133
+ const fileNote = unseen === 0
134
+ ? "all files in commit have been touched by author before"
135
+ : `${unseen}/${files.length} files are new for this author (e.g. ${newFiles.slice(0, 2).join(", ")}${newFiles.length > 2 ? "…" : ""})`;
136
+ // ── STYLE axis ─────────────────────────────────────────────────────
137
+ const subj = (commit.subject || "").trim();
138
+ const verb = (subj.match(/^[A-Za-z]+/)?.[0] || "").toLowerCase();
139
+ let styleScore = 0;
140
+ let styleNote = "verb is in author's known vocabulary";
141
+ if (verb && !baseline.knownVerbs.has(verb) && baseline.commitCount >= 10) {
142
+ styleScore = 0.6;
143
+ styleNote = `verb "${verb}" not in author's vocabulary (${baseline.knownVerbs.size} verbs across ${baseline.commitCount} commits)`;
144
+ }
145
+ // ── SIZE axis ──────────────────────────────────────────────────────
146
+ const fcs = fileChanges.filter((f) => f.commitHash === commit.hash);
147
+ const churn = fcs.reduce((s, x) => s + x.insertions + x.deletions, 0);
148
+ const robustZ = Math.abs(churn - baseline.medianChurn) / Math.max(1, baseline.churnMad);
149
+ const sizeScore = Math.min(1, robustZ / 8); // 8-MAD = score 1.0
150
+ const sizeNote = churn === 0
151
+ ? "(no churn data — file-changes not provided)"
152
+ : `+${churn} lines vs author's median ${baseline.medianChurn} (robust z = ${robustZ.toFixed(1)})`;
153
+ // ── Composite ──────────────────────────────────────────────────────
154
+ const axes = [
155
+ { axis: "time", score: timeScore, note: timeNote },
156
+ { axis: "files", score: fileScore, note: fileNote },
157
+ { axis: "style", score: styleScore, note: styleNote },
158
+ { axis: "size", score: sizeScore, note: sizeNote },
159
+ ];
160
+ const totalDeviation = AXIS_WEIGHTS.time * timeScore +
161
+ AXIS_WEIGHTS.files * fileScore +
162
+ AXIS_WEIGHTS.style * styleScore +
163
+ AXIS_WEIGHTS.size * sizeScore;
164
+ // 1 deviation point ≈ 2σ heuristic
165
+ const approxSigma = totalDeviation * 2;
166
+ let severity = "low";
167
+ if (totalDeviation >= 2.5)
168
+ severity = "critical";
169
+ else if (totalDeviation >= 1.7)
170
+ severity = "high";
171
+ else if (totalDeviation >= 0.9)
172
+ severity = "medium";
173
+ let recommendation = "no action required";
174
+ if (severity === "critical") {
175
+ recommendation =
176
+ "review immediately; verify author identity out-of-band (chat, video, in-person) before merging";
177
+ }
178
+ else if (severity === "high") {
179
+ recommendation =
180
+ "elevated review; require explicit approval from a second engineer";
181
+ }
182
+ else if (severity === "medium") {
183
+ recommendation = "include in standard PR review with attention";
184
+ }
185
+ return {
186
+ commit,
187
+ totalDeviation: Number(totalDeviation.toFixed(3)),
188
+ approxSigma: Number(approxSigma.toFixed(2)),
189
+ axes,
190
+ severity,
191
+ recommendation,
192
+ };
193
+ }
194
+ /**
195
+ * Score every commit in `commits` against the corresponding author
196
+ * baseline. Returns only findings whose composite score exceeds
197
+ * `threshold` (default 0.9 = ~"medium" severity).
198
+ */
199
+ export function detectAnomalies(commits, baselines, fileChanges = [], threshold = 0.9) {
200
+ const findings = [];
201
+ for (const c of commits) {
202
+ const a = c.authorEmail.toLowerCase() || c.authorName.toLowerCase();
203
+ const baseline = baselines.get(a);
204
+ if (!baseline || baseline.commitCount < 5)
205
+ continue; // need minimum data
206
+ const finding = scoreAnomaly(c, baseline, fileChanges);
207
+ if (finding.totalDeviation >= threshold)
208
+ findings.push(finding);
209
+ }
210
+ return findings.sort((a, b) => b.totalDeviation - a.totalDeviation);
211
+ }
212
+ function pad2(n) {
213
+ return n < 10 ? "0" + n : "" + n;
214
+ }
215
+ function pct(r) {
216
+ return `${(r * 100).toFixed(1)}%`;
217
+ }
218
+ //# sourceMappingURL=anomaly.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anomaly.js","sourceRoot":"","sources":["../../src/forensics/anomaly.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=forensics.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forensics.test.d.ts","sourceRoot":"","sources":["../../src/forensics/forensics.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,281 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { extractLoci } from "./loci.js";
3
+ import { buildPopulationStats, compareLoci, verdict, } from "./likelihood.js";
4
+ import { huntVulnerabilities } from "./vulnhunt.js";
5
+ import { buildBaselines, scoreAnomaly, detectAnomalies, } from "./anomaly.js";
6
+ function mk(p) {
7
+ return {
8
+ hash: p.hash,
9
+ shortHash: p.hash.slice(0, 7),
10
+ authorName: p.author ?? "Alice",
11
+ authorEmail: (p.author ?? "alice").toLowerCase() + "@x.com",
12
+ authorDate: p.date ?? "2024-01-01T10:00:00Z",
13
+ committerDate: p.date ?? "2024-01-01T10:00:00Z",
14
+ subject: p.subject,
15
+ body: p.body ?? "",
16
+ files: p.files ?? ["src/x.ts"],
17
+ parents: [],
18
+ prNumber: p.pr,
19
+ };
20
+ }
21
+ // ─── extractLoci ──────────────────────────────────────────────────────
22
+ describe("extractLoci", () => {
23
+ it("returns zero loci for empty input", () => {
24
+ const l = extractLoci([]);
25
+ expect(l.filesPerCommit).toBe(0);
26
+ expect(l.conventionalRatio).toBe(0);
27
+ });
28
+ it("computes conventionalRatio from feat:/fix: prefixes", () => {
29
+ const cs = [
30
+ mk({ hash: "a", subject: "feat: add caching" }),
31
+ mk({ hash: "b", subject: "fix: handle null" }),
32
+ mk({ hash: "c", subject: "random subject" }),
33
+ ];
34
+ const l = extractLoci(cs);
35
+ expect(l.conventionalRatio).toBeCloseTo(2 / 3, 2);
36
+ });
37
+ it("imperative verbs raise imperativeRatio", () => {
38
+ const cs = [
39
+ mk({ hash: "a", subject: "Add caching" }),
40
+ mk({ hash: "b", subject: "Fix typo" }),
41
+ mk({ hash: "c", subject: "Update docs" }),
42
+ ];
43
+ const l = extractLoci(cs);
44
+ expect(l.imperativeRatio).toBeGreaterThan(0.6);
45
+ });
46
+ it("peakHour reflects most-common UTC band", () => {
47
+ const cs = Array.from({ length: 5 }, (_, i) => mk({ hash: `c${i}`, subject: "x", date: `2024-01-0${i + 1}T15:00:00Z` }));
48
+ const l = extractLoci(cs);
49
+ expect(l.peakHour).toBeGreaterThanOrEqual(12);
50
+ expect(l.peakHour).toBeLessThanOrEqual(15);
51
+ });
52
+ it("verbEntropy is 0 for monoculture and > 1 for diverse vocab", () => {
53
+ const mono = Array.from({ length: 5 }, (_, i) => mk({ hash: `c${i}`, subject: "add feature " + i }));
54
+ const diverse = [
55
+ mk({ hash: "a1", subject: "add caching" }),
56
+ mk({ hash: "a2", subject: "fix typo" }),
57
+ mk({ hash: "a3", subject: "remove dead code" }),
58
+ mk({ hash: "a4", subject: "rename module" }),
59
+ mk({ hash: "a5", subject: "introduce policy" }),
60
+ ];
61
+ const lMono = extractLoci(mono);
62
+ const lDiv = extractLoci(diverse);
63
+ expect(lMono.verbEntropy).toBeLessThan(0.1);
64
+ expect(lDiv.verbEntropy).toBeGreaterThan(1);
65
+ });
66
+ });
67
+ // ─── verdict + LR ──────────────────────────────────────────────────────
68
+ describe("verdict (ENFSI)", () => {
69
+ it("maps LR 100 to moderate support", () => {
70
+ expect(verdict(100)).toBe("moderate support");
71
+ });
72
+ it("maps LR 10000 to very strong support", () => {
73
+ expect(verdict(10_000)).toBe("very strong support");
74
+ });
75
+ it("maps LR 0.001 to strong support against", () => {
76
+ expect(verdict(0.0009)).toBe("strong support against");
77
+ });
78
+ it("maps LR ~1 to uninformative", () => {
79
+ expect(verdict(0.7)).toBe("uninformative");
80
+ });
81
+ });
82
+ describe("compareLoci + buildPopulationStats", () => {
83
+ it("matches author against themselves with strong support", () => {
84
+ // Two authors with very different profiles
85
+ const aliceCommits = Array.from({ length: 30 }, (_, i) => mk({
86
+ hash: `al${i}`,
87
+ subject: `feat: add module ${i}`,
88
+ date: `2024-${String((i % 12) + 1).padStart(2, "0")}-01T15:00:00Z`,
89
+ author: "Alice",
90
+ }));
91
+ const bobCommits = Array.from({ length: 30 }, (_, i) => mk({
92
+ hash: `bo${i}`,
93
+ subject: `random thing ${i}`,
94
+ date: `2024-${String((i % 12) + 1).padStart(2, "0")}-01T03:00:00Z`,
95
+ author: "Bob",
96
+ }));
97
+ const aliceLoci = extractLoci(aliceCommits);
98
+ const bobLoci = extractLoci(bobCommits);
99
+ const pop = buildPopulationStats([aliceLoci, bobLoci]);
100
+ // Use Alice's own profile as evidence and Alice as suspect
101
+ const r = compareLoci(aliceLoci, aliceLoci, pop);
102
+ expect(r.combinedLR).toBeGreaterThan(1);
103
+ // Should be at least "moderate support" when Alice matches Alice
104
+ expect(["weak support", "moderate support", "strong support", "very strong support", "extremely strong support"]).toContain(r.verdict);
105
+ });
106
+ it("rejects clearly different authors with low LR", () => {
107
+ const aliceCommits = Array.from({ length: 30 }, (_, i) => mk({ hash: `al${i}`, subject: "feat: a", date: `2024-01-01T15:00:00Z`, author: "Alice" }));
108
+ const bobCommits = Array.from({ length: 30 }, (_, i) => mk({ hash: `bo${i}`, subject: "thing", date: `2024-01-01T03:00:00Z`, author: "Bob", files: ["legacy.py"] }));
109
+ const aliceLoci = extractLoci(aliceCommits);
110
+ const bobLoci = extractLoci(bobCommits);
111
+ const pop = buildPopulationStats([aliceLoci, bobLoci]);
112
+ // Use Alice's profile as evidence, Bob as suspect — should disfavor
113
+ const r = compareLoci(aliceLoci, bobLoci, pop);
114
+ expect(r.combinedLR).toBeLessThan(1);
115
+ });
116
+ });
117
+ // ─── VulnHunt ──────────────────────────────────────────────────────────
118
+ describe("huntVulnerabilities", () => {
119
+ it("flags MD5 usage as crypto-weakness", () => {
120
+ const r = huntVulnerabilities([
121
+ {
122
+ commit: mk({ hash: "a1", subject: "auth: hash password" }),
123
+ diff: "+ const hash = MD5(input);",
124
+ },
125
+ ]);
126
+ expect(r.hits.find((h) => h.class === "crypto-weakness")).toBeDefined();
127
+ });
128
+ it("flags Math.random in security context", () => {
129
+ const r = huntVulnerabilities([
130
+ {
131
+ commit: mk({ hash: "a1", subject: "create token" }),
132
+ diff: "+ const token = Math.random().toString();",
133
+ },
134
+ ]);
135
+ expect(r.hits.find((h) => h.class === "crypto-weakness")).toBeDefined();
136
+ });
137
+ it("flags hardcoded bearer token", () => {
138
+ const r = huntVulnerabilities([
139
+ {
140
+ commit: mk({ hash: "a1", subject: "add api client" }),
141
+ diff: "+ headers.Authorization = 'Bearer abc123def456ghi789jkl012';",
142
+ },
143
+ ]);
144
+ expect(r.hits.find((h) => h.class === "auth-flaw")).toBeDefined();
145
+ });
146
+ it("flags console.log of password", () => {
147
+ const r = huntVulnerabilities([
148
+ {
149
+ commit: mk({ hash: "a1", subject: "debug login" }),
150
+ diff: "+ console.log('pw=', password);",
151
+ },
152
+ ]);
153
+ expect(r.hits.find((h) => h.class === "info-leakage")).toBeDefined();
154
+ });
155
+ it("flags JWT decoded without verification", () => {
156
+ const r = huntVulnerabilities([
157
+ {
158
+ commit: mk({ hash: "a1", subject: "parse token" }),
159
+ diff: "+ const claims = jwt.decode(token);",
160
+ },
161
+ ]);
162
+ expect(r.hits.find((h) => h.class === "auth-flaw")).toBeDefined();
163
+ });
164
+ it("returns silent fixes when subject mentions security", () => {
165
+ const r = huntVulnerabilities([
166
+ {
167
+ commit: mk({ hash: "a1", subject: "fix CVE-2024-1234 in auth" }),
168
+ diff: "",
169
+ },
170
+ ]);
171
+ expect(r.silentFixes.length).toBe(1);
172
+ });
173
+ it("severity tally matches hits", () => {
174
+ const r = huntVulnerabilities([
175
+ { commit: mk({ hash: "a", subject: "x" }), diff: "+ MD5(x)" },
176
+ { commit: mk({ hash: "b", subject: "y" }), diff: "+ jwt.decode(t);" },
177
+ ]);
178
+ expect(r.bySeverity.high + r.bySeverity.critical).toBeGreaterThanOrEqual(2);
179
+ });
180
+ });
181
+ // ─── Anomaly ───────────────────────────────────────────────────────────
182
+ describe("buildBaselines + scoreAnomaly", () => {
183
+ function mkSeries(author, hashes, hour, files) {
184
+ return hashes.map((h, i) => mk({
185
+ hash: h,
186
+ subject: `feat: add thing ${i}`,
187
+ author,
188
+ date: `2024-${String((i % 12) + 1).padStart(2, "0")}-15T${pad(hour)}:00:00Z`,
189
+ files: files[i % files.length],
190
+ }));
191
+ }
192
+ function pad(n) {
193
+ return n < 10 ? "0" + n : "" + n;
194
+ }
195
+ it("flags off-hours commits as time-anomalous", () => {
196
+ // Alice always commits at 15:00 UTC
197
+ const history = mkSeries("alice", Array.from({ length: 20 }, (_, i) => "h" + i), 15, [["src/payments.ts"]]);
198
+ const suspicious = mk({
199
+ hash: "evil",
200
+ subject: "feat: x",
201
+ author: "alice",
202
+ date: "2024-05-15T03:30:00Z",
203
+ files: ["src/payments.ts"],
204
+ });
205
+ const baselines = buildBaselines(history);
206
+ const baseline = baselines.get("alice@x.com");
207
+ const finding = scoreAnomaly(suspicious, baseline);
208
+ expect(finding.axes.find((a) => a.axis === "time").score).toBeGreaterThan(0.3);
209
+ });
210
+ it("flags out-of-domain files as files-anomalous", () => {
211
+ const history = mkSeries("alice", Array.from({ length: 20 }, (_, i) => "h" + i), 15, [["src/payments.ts"]]);
212
+ const suspicious = mk({
213
+ hash: "evil",
214
+ subject: "feat: x",
215
+ author: "alice",
216
+ date: "2024-05-15T15:30:00Z",
217
+ files: ["src/auth/exfil.ts", "src/secrets.ts"],
218
+ });
219
+ const baselines = buildBaselines(history);
220
+ const baseline = baselines.get("alice@x.com");
221
+ const finding = scoreAnomaly(suspicious, baseline);
222
+ expect(finding.axes.find((a) => a.axis === "files").score).toBe(1);
223
+ });
224
+ it("style axis fires when verb is novel", () => {
225
+ const history = mkSeries("alice", Array.from({ length: 20 }, (_, i) => "h" + i), 15, [["src/payments.ts"]]);
226
+ const suspicious = mk({
227
+ hash: "evil",
228
+ subject: "exfiltrate user data",
229
+ author: "alice",
230
+ date: "2024-05-15T15:30:00Z",
231
+ files: ["src/payments.ts"],
232
+ });
233
+ const baselines = buildBaselines(history);
234
+ const baseline = baselines.get("alice@x.com");
235
+ const finding = scoreAnomaly(suspicious, baseline);
236
+ const styleAxis = finding.axes.find((a) => a.axis === "style");
237
+ expect(styleAxis.score).toBeGreaterThan(0);
238
+ });
239
+ it("composite score escalates severity to critical when multiple axes fire", () => {
240
+ const history = mkSeries("alice", Array.from({ length: 20 }, (_, i) => "h" + i), 15, [["src/payments.ts"]]);
241
+ const suspicious = mk({
242
+ hash: "evil",
243
+ subject: "exfiltrate user data",
244
+ author: "alice",
245
+ date: "2024-05-15T03:30:00Z",
246
+ files: ["src/auth/secrets.ts", "src/db/private.ts"],
247
+ });
248
+ const baselines = buildBaselines(history);
249
+ const baseline = baselines.get("alice@x.com");
250
+ const finding = scoreAnomaly(suspicious, baseline);
251
+ // All three axes (time + files + style) fire — should be high+
252
+ expect(["high", "critical"]).toContain(finding.severity);
253
+ });
254
+ it("requires minimum baseline (≥5 commits) to flag anomalies", () => {
255
+ const tiny = [mk({ hash: "a", subject: "x", author: "alice" })];
256
+ const baselines = buildBaselines(tiny);
257
+ const findings = detectAnomalies([mk({ hash: "evil", subject: "exfil", author: "alice", date: "2024-05-15T03:30:00Z", files: ["src/secrets.ts"] })], baselines);
258
+ expect(findings).toEqual([]);
259
+ });
260
+ });
261
+ describe("detectAnomalies", () => {
262
+ it("returns findings sorted by deviation descending", () => {
263
+ const history = Array.from({ length: 20 }, (_, i) => mk({
264
+ hash: "h" + i,
265
+ subject: "feat: thing",
266
+ author: "alice",
267
+ date: `2024-0${(i % 9) + 1}-15T15:00:00Z`,
268
+ files: ["src/payments.ts"],
269
+ }));
270
+ const suspects = [
271
+ mk({ hash: "weak", subject: "feat: thing", author: "alice", date: "2024-10-15T16:00:00Z", files: ["src/payments.ts"] }),
272
+ mk({ hash: "strong", subject: "exfil all", author: "alice", date: "2024-10-15T03:00:00Z", files: ["src/auth/secrets.ts"] }),
273
+ ];
274
+ const baselines = buildBaselines(history);
275
+ const findings = detectAnomalies(suspects, baselines, [], 0.5);
276
+ if (findings.length >= 2) {
277
+ expect(findings[0].totalDeviation).toBeGreaterThanOrEqual(findings[1].totalDeviation);
278
+ }
279
+ });
280
+ });
281
+ //# sourceMappingURL=forensics.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forensics.test.js","sourceRoot":"","sources":["../../src/forensics/forensics.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export * from "./loci.js";
2
+ export * from "./likelihood.js";
3
+ export * from "./vulnhunt.js";
4
+ export * from "./anomaly.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/forensics/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC"}