usertrust 0.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.
- package/dist/audit/canonical.d.ts +7 -0
- package/dist/audit/canonical.d.ts.map +1 -0
- package/dist/audit/canonical.js +24 -0
- package/dist/audit/canonical.js.map +1 -0
- package/dist/audit/chain.d.ts +33 -0
- package/dist/audit/chain.d.ts.map +1 -0
- package/dist/audit/chain.js +285 -0
- package/dist/audit/chain.js.map +1 -0
- package/dist/audit/entropy.d.ts +95 -0
- package/dist/audit/entropy.d.ts.map +1 -0
- package/dist/audit/entropy.js +229 -0
- package/dist/audit/entropy.js.map +1 -0
- package/dist/audit/merkle.d.ts +87 -0
- package/dist/audit/merkle.d.ts.map +1 -0
- package/dist/audit/merkle.js +315 -0
- package/dist/audit/merkle.js.map +1 -0
- package/dist/audit/rotation.d.ts +61 -0
- package/dist/audit/rotation.d.ts.map +1 -0
- package/dist/audit/rotation.js +160 -0
- package/dist/audit/rotation.js.map +1 -0
- package/dist/audit/verify.d.ts +20 -0
- package/dist/audit/verify.d.ts.map +1 -0
- package/dist/audit/verify.js +73 -0
- package/dist/audit/verify.js.map +1 -0
- package/dist/board/board.d.ts +67 -0
- package/dist/board/board.d.ts.map +1 -0
- package/dist/board/board.js +191 -0
- package/dist/board/board.js.map +1 -0
- package/dist/board/concerns.d.ts +59 -0
- package/dist/board/concerns.d.ts.map +1 -0
- package/dist/board/concerns.js +149 -0
- package/dist/board/concerns.js.map +1 -0
- package/dist/board/director.d.ts +49 -0
- package/dist/board/director.d.ts.map +1 -0
- package/dist/board/director.js +127 -0
- package/dist/board/director.js.map +1 -0
- package/dist/cli/health.d.ts +8 -0
- package/dist/cli/health.d.ts.map +1 -0
- package/dist/cli/health.js +119 -0
- package/dist/cli/health.js.map +1 -0
- package/dist/cli/init.d.ts +8 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +67 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/inspect.d.ts +8 -0
- package/dist/cli/inspect.d.ts.map +1 -0
- package/dist/cli/inspect.js +114 -0
- package/dist/cli/inspect.js.map +1 -0
- package/dist/cli/main.d.ts +3 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +35 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/snapshot.d.ts +10 -0
- package/dist/cli/snapshot.d.ts.map +1 -0
- package/dist/cli/snapshot.js +61 -0
- package/dist/cli/snapshot.js.map +1 -0
- package/dist/cli/tb.d.ts +8 -0
- package/dist/cli/tb.d.ts.map +1 -0
- package/dist/cli/tb.js +43 -0
- package/dist/cli/tb.js.map +1 -0
- package/dist/cli/verify.d.ts +7 -0
- package/dist/cli/verify.d.ts.map +1 -0
- package/dist/cli/verify.js +32 -0
- package/dist/cli/verify.js.map +1 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +34 -0
- package/dist/config.js.map +1 -0
- package/dist/detect.d.ts +18 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +49 -0
- package/dist/detect.js.map +1 -0
- package/dist/govern.d.ts +75 -0
- package/dist/govern.d.ts.map +1 -0
- package/dist/govern.js +581 -0
- package/dist/govern.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/ledger/client.d.ts +89 -0
- package/dist/ledger/client.d.ts.map +1 -0
- package/dist/ledger/client.js +417 -0
- package/dist/ledger/client.js.map +1 -0
- package/dist/ledger/engine.d.ts +68 -0
- package/dist/ledger/engine.d.ts.map +1 -0
- package/dist/ledger/engine.js +142 -0
- package/dist/ledger/engine.js.map +1 -0
- package/dist/ledger/pricing.d.ts +35 -0
- package/dist/ledger/pricing.d.ts.map +1 -0
- package/dist/ledger/pricing.js +142 -0
- package/dist/ledger/pricing.js.map +1 -0
- package/dist/memory/patterns.d.ts +35 -0
- package/dist/memory/patterns.d.ts.map +1 -0
- package/dist/memory/patterns.js +152 -0
- package/dist/memory/patterns.js.map +1 -0
- package/dist/policy/decay.d.ts +95 -0
- package/dist/policy/decay.d.ts.map +1 -0
- package/dist/policy/decay.js +133 -0
- package/dist/policy/decay.js.map +1 -0
- package/dist/policy/default-rules.d.ts +21 -0
- package/dist/policy/default-rules.d.ts.map +1 -0
- package/dist/policy/default-rules.js +60 -0
- package/dist/policy/default-rules.js.map +1 -0
- package/dist/policy/gate.d.ts +116 -0
- package/dist/policy/gate.d.ts.map +1 -0
- package/dist/policy/gate.js +227 -0
- package/dist/policy/gate.js.map +1 -0
- package/dist/policy/pii.d.ts +28 -0
- package/dist/policy/pii.d.ts.map +1 -0
- package/dist/policy/pii.js +124 -0
- package/dist/policy/pii.js.map +1 -0
- package/dist/proxy.d.ts +33 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +36 -0
- package/dist/proxy.js.map +1 -0
- package/dist/resilience/circuit.d.ts +87 -0
- package/dist/resilience/circuit.d.ts.map +1 -0
- package/dist/resilience/circuit.js +167 -0
- package/dist/resilience/circuit.js.map +1 -0
- package/dist/resilience/scope.d.ts +97 -0
- package/dist/resilience/scope.d.ts.map +1 -0
- package/dist/resilience/scope.js +244 -0
- package/dist/resilience/scope.js.map +1 -0
- package/dist/shared/constants.d.ts +7 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +7 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/errors.d.ts +31 -0
- package/dist/shared/errors.d.ts.map +1 -0
- package/dist/shared/errors.js +61 -0
- package/dist/shared/errors.js.map +1 -0
- package/dist/shared/ids.d.ts +7 -0
- package/dist/shared/ids.d.ts.map +1 -0
- package/dist/shared/ids.js +31 -0
- package/dist/shared/ids.js.map +1 -0
- package/dist/shared/types.d.ts +162 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +41 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/snapshot/checkpoint.d.ts +22 -0
- package/dist/snapshot/checkpoint.d.ts.map +1 -0
- package/dist/snapshot/checkpoint.js +172 -0
- package/dist/snapshot/checkpoint.js.map +1 -0
- package/dist/streaming.d.ts +44 -0
- package/dist/streaming.d.ts.map +1 -0
- package/dist/streaming.js +123 -0
- package/dist/streaming.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic JSON canonicalization for hash computation.
|
|
3
|
+
* Sorts object keys alphabetically at every nesting level.
|
|
4
|
+
* Strips undefined values. Preserves null. Arrays keep order.
|
|
5
|
+
*/
|
|
6
|
+
export declare function canonicalize(value: unknown): string;
|
|
7
|
+
//# sourceMappingURL=canonical.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../../src/audit/canonical.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAcnD"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic JSON canonicalization for hash computation.
|
|
3
|
+
* Sorts object keys alphabetically at every nesting level.
|
|
4
|
+
* Strips undefined values. Preserves null. Arrays keep order.
|
|
5
|
+
*/
|
|
6
|
+
export function canonicalize(value) {
|
|
7
|
+
if (value === null || value === undefined)
|
|
8
|
+
return JSON.stringify(value);
|
|
9
|
+
if (typeof value !== "object")
|
|
10
|
+
return JSON.stringify(value);
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
return `[${value.map((v) => canonicalize(v)).join(",")}]`;
|
|
13
|
+
}
|
|
14
|
+
const obj = value;
|
|
15
|
+
const keys = Object.keys(obj).sort();
|
|
16
|
+
const parts = [];
|
|
17
|
+
for (const key of keys) {
|
|
18
|
+
if (obj[key] === undefined)
|
|
19
|
+
continue;
|
|
20
|
+
parts.push(`${JSON.stringify(key)}:${canonicalize(obj[key])}`);
|
|
21
|
+
}
|
|
22
|
+
return `{${parts.join(",")}}`;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=canonical.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../src/audit/canonical.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc;IAC1C,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACxE,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAC3D,CAAC;IACD,MAAM,GAAG,GAAG,KAAgC,CAAC;IAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACrC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS;YAAE,SAAS;QACrC,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit Chain Writer — SHA-256 hash-chained JSONL
|
|
3
|
+
*
|
|
4
|
+
* Appends audit events to a JSONL log where each event's hash covers
|
|
5
|
+
* the previous event's hash, creating a tamper-evident chain. Single-writer
|
|
6
|
+
* semantics are enforced via advisory file lock + in-process async mutex.
|
|
7
|
+
*
|
|
8
|
+
* Adapted from usertools-stealth governance/audit/writer.ts — removes
|
|
9
|
+
* SurrealDB dual-write, replaces sendAlert with console.warn, replaces
|
|
10
|
+
* writeDeadLetter with local DLQ JSONL.
|
|
11
|
+
*/
|
|
12
|
+
import type { AuditEvent } from "../shared/types.js";
|
|
13
|
+
export interface AppendEventInput {
|
|
14
|
+
kind: string;
|
|
15
|
+
actor: string;
|
|
16
|
+
data: Record<string, unknown>;
|
|
17
|
+
}
|
|
18
|
+
export interface AuditWriter {
|
|
19
|
+
appendEvent(input: AppendEventInput): Promise<AuditEvent>;
|
|
20
|
+
getWriteFailures(): number;
|
|
21
|
+
isDegraded(): boolean;
|
|
22
|
+
flush(): Promise<void>;
|
|
23
|
+
release(): void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create an audit writer instance for the given vault path.
|
|
27
|
+
*
|
|
28
|
+
* The writer appends events to `<vaultPath>/.usertools/audit/events.jsonl`.
|
|
29
|
+
* Each event's SHA-256 hash covers the previous event's hash, creating a
|
|
30
|
+
* tamper-evident chain. The first event chains from GENESIS_HASH.
|
|
31
|
+
*/
|
|
32
|
+
export declare function createAuditWriter(vaultPath: string): AuditWriter;
|
|
33
|
+
//# sourceMappingURL=chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../../src/audit/chain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAeH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAKrD,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAC3B,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1D,gBAAgB,IAAI,MAAM,CAAC;IAC3B,UAAU,IAAI,OAAO,CAAC;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,IAAI,IAAI,CAAC;CAChB;AAqMD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,CAyGhE"}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit Chain Writer — SHA-256 hash-chained JSONL
|
|
3
|
+
*
|
|
4
|
+
* Appends audit events to a JSONL log where each event's hash covers
|
|
5
|
+
* the previous event's hash, creating a tamper-evident chain. Single-writer
|
|
6
|
+
* semantics are enforced via advisory file lock + in-process async mutex.
|
|
7
|
+
*
|
|
8
|
+
* Adapted from usertools-stealth governance/audit/writer.ts — removes
|
|
9
|
+
* SurrealDB dual-write, replaces sendAlert with console.warn, replaces
|
|
10
|
+
* writeDeadLetter with local DLQ JSONL.
|
|
11
|
+
*/
|
|
12
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
13
|
+
import { closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, unlinkSync, writeSync, } from "node:fs";
|
|
14
|
+
import { dirname, join } from "node:path";
|
|
15
|
+
import { GENESIS_HASH, VAULT_DIR } from "../shared/constants.js";
|
|
16
|
+
import { canonicalize } from "./canonical.js";
|
|
17
|
+
// ── AsyncMutex ──
|
|
18
|
+
/**
|
|
19
|
+
* In-process async mutex for serializing audit writes.
|
|
20
|
+
*
|
|
21
|
+
* SINGLE-PROCESS CONSTRAINT: This mutex is process-local (in-memory).
|
|
22
|
+
* It guarantees sequential writes within a single Node.js process but
|
|
23
|
+
* provides NO protection across multiple processes.
|
|
24
|
+
*/
|
|
25
|
+
class AsyncMutex {
|
|
26
|
+
queue = Promise.resolve();
|
|
27
|
+
async acquire() {
|
|
28
|
+
let release;
|
|
29
|
+
const next = new Promise((resolve) => {
|
|
30
|
+
release = resolve;
|
|
31
|
+
});
|
|
32
|
+
const prev = this.queue;
|
|
33
|
+
this.queue = next;
|
|
34
|
+
await prev;
|
|
35
|
+
return release;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// ── Advisory Lock ──
|
|
39
|
+
function acquireProcessLock(logPath, locksByDir) {
|
|
40
|
+
const dir = dirname(logPath);
|
|
41
|
+
if (locksByDir.has(dir))
|
|
42
|
+
return;
|
|
43
|
+
const candidateLockPath = `${dir}/.audit-writer.lock`;
|
|
44
|
+
if (existsSync(candidateLockPath)) {
|
|
45
|
+
try {
|
|
46
|
+
const content = readFileSync(candidateLockPath, "utf-8");
|
|
47
|
+
const lockData = JSON.parse(content);
|
|
48
|
+
if (lockData.pid === process.pid) {
|
|
49
|
+
console.warn(`[AUDIT] Reclaiming stale same-PID lock (PID ${process.pid}). Previous process exited without releasing the lock.`);
|
|
50
|
+
unlinkSync(candidateLockPath);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
try {
|
|
54
|
+
process.kill(lockData.pid, 0);
|
|
55
|
+
throw new Error(`Audit writer lock held by PID ${lockData.pid}. Only one process may write to the audit log. Lock file: ${candidateLockPath}`);
|
|
56
|
+
}
|
|
57
|
+
catch (killErr) {
|
|
58
|
+
if (killErr instanceof Error && "code" in killErr) {
|
|
59
|
+
const code = killErr.code;
|
|
60
|
+
if (code === "ESRCH") {
|
|
61
|
+
unlinkSync(candidateLockPath);
|
|
62
|
+
}
|
|
63
|
+
else if (code === "EPERM") {
|
|
64
|
+
throw new Error(`Audit writer lock held by PID ${lockData.pid}. Only one process may write to the audit log. Lock file: ${candidateLockPath}`);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
throw killErr;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
throw killErr;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (parseErr) {
|
|
77
|
+
if (parseErr instanceof Error && parseErr.message.includes("Audit writer lock held")) {
|
|
78
|
+
throw parseErr;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
unlinkSync(candidateLockPath);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
/* best effort */
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const fd = openSync(candidateLockPath, "wx");
|
|
89
|
+
const lockContent = JSON.stringify({
|
|
90
|
+
pid: process.pid,
|
|
91
|
+
startedAt: new Date().toISOString(),
|
|
92
|
+
});
|
|
93
|
+
writeSync(fd, lockContent);
|
|
94
|
+
fsyncSync(fd);
|
|
95
|
+
locksByDir.set(dir, { fd, path: candidateLockPath });
|
|
96
|
+
}
|
|
97
|
+
function releaseLocks(locksByDir) {
|
|
98
|
+
for (const [dir, lock] of locksByDir) {
|
|
99
|
+
try {
|
|
100
|
+
closeSync(lock.fd);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
/* already closed */
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
unlinkSync(lock.path);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
/* already removed */
|
|
110
|
+
}
|
|
111
|
+
locksByDir.delete(dir);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function getLastEvent(logPath, cache) {
|
|
115
|
+
const cached = cache.get(logPath);
|
|
116
|
+
if (cached)
|
|
117
|
+
return cached;
|
|
118
|
+
if (!existsSync(logPath))
|
|
119
|
+
return null;
|
|
120
|
+
const content = readFileSync(logPath, "utf-8").trim();
|
|
121
|
+
if (!content) {
|
|
122
|
+
const metaPath = `${logPath}.meta`;
|
|
123
|
+
if (existsSync(metaPath)) {
|
|
124
|
+
try {
|
|
125
|
+
const meta = JSON.parse(readFileSync(metaPath, "utf-8"));
|
|
126
|
+
return { hash: meta.lastHash, sequence: meta.sequence };
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
/* ignore corrupt meta */
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
const lines = content.split("\n");
|
|
135
|
+
const lastLine = lines[lines.length - 1];
|
|
136
|
+
if (!lastLine)
|
|
137
|
+
return null;
|
|
138
|
+
try {
|
|
139
|
+
const event = JSON.parse(lastLine);
|
|
140
|
+
const sequence = typeof event.sequence === "number" ? event.sequence : lines.length;
|
|
141
|
+
const tail = { hash: event.hash, sequence };
|
|
142
|
+
cache.set(logPath, tail);
|
|
143
|
+
return tail;
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
const metaPath = `${logPath}.meta`;
|
|
147
|
+
if (existsSync(metaPath)) {
|
|
148
|
+
try {
|
|
149
|
+
const meta = JSON.parse(readFileSync(metaPath, "utf-8"));
|
|
150
|
+
return { hash: meta.lastHash, sequence: meta.sequence };
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
/* ignore corrupt meta */
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// ── DLQ Writer ──
|
|
160
|
+
function writeDeadLetter(vaultPath, entry) {
|
|
161
|
+
try {
|
|
162
|
+
const dlqDir = join(vaultPath, VAULT_DIR, "dlq");
|
|
163
|
+
if (!existsSync(dlqDir)) {
|
|
164
|
+
mkdirSync(dlqDir, { recursive: true });
|
|
165
|
+
}
|
|
166
|
+
const dlqPath = join(dlqDir, "dead-letters.jsonl");
|
|
167
|
+
const fd = openSync(dlqPath, "a");
|
|
168
|
+
try {
|
|
169
|
+
writeSync(fd, `${JSON.stringify(entry)}\n`);
|
|
170
|
+
fsyncSync(fd);
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
closeSync(fd);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
// DLQ write failure — last resort, cannot do anything else
|
|
178
|
+
console.error("[AUDIT] Dead-letter write failed", entry);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// ── Factory ──
|
|
182
|
+
/**
|
|
183
|
+
* Create an audit writer instance for the given vault path.
|
|
184
|
+
*
|
|
185
|
+
* The writer appends events to `<vaultPath>/.usertools/audit/events.jsonl`.
|
|
186
|
+
* Each event's SHA-256 hash covers the previous event's hash, creating a
|
|
187
|
+
* tamper-evident chain. The first event chains from GENESIS_HASH.
|
|
188
|
+
*/
|
|
189
|
+
export function createAuditWriter(vaultPath) {
|
|
190
|
+
const auditDir = join(vaultPath, VAULT_DIR, "audit");
|
|
191
|
+
if (!existsSync(auditDir)) {
|
|
192
|
+
mkdirSync(auditDir, { recursive: true });
|
|
193
|
+
}
|
|
194
|
+
const logPath = join(auditDir, "events.jsonl");
|
|
195
|
+
const mutex = new AsyncMutex();
|
|
196
|
+
const lastEventCache = new Map();
|
|
197
|
+
const locksByDir = new Map();
|
|
198
|
+
let degraded = false;
|
|
199
|
+
let writeFailures = 0;
|
|
200
|
+
async function appendEvent(input) {
|
|
201
|
+
const release = await mutex.acquire();
|
|
202
|
+
try {
|
|
203
|
+
acquireProcessLock(logPath, locksByDir);
|
|
204
|
+
const last = getLastEvent(logPath, lastEventCache);
|
|
205
|
+
const previousHash = last?.hash ?? GENESIS_HASH;
|
|
206
|
+
const sequence = (last?.sequence ?? 0) + 1;
|
|
207
|
+
const event = {
|
|
208
|
+
id: randomUUID(),
|
|
209
|
+
timestamp: new Date().toISOString(),
|
|
210
|
+
previousHash,
|
|
211
|
+
kind: input.kind,
|
|
212
|
+
actor: input.actor,
|
|
213
|
+
data: input.data,
|
|
214
|
+
sequence,
|
|
215
|
+
};
|
|
216
|
+
const canonical = canonicalize(event);
|
|
217
|
+
const hash = createHash("sha256").update(canonical).digest("hex");
|
|
218
|
+
const fullEvent = {
|
|
219
|
+
...event,
|
|
220
|
+
hash,
|
|
221
|
+
};
|
|
222
|
+
const fd = openSync(logPath, "a");
|
|
223
|
+
try {
|
|
224
|
+
writeSync(fd, `${JSON.stringify(fullEvent)}\n`);
|
|
225
|
+
fsyncSync(fd);
|
|
226
|
+
}
|
|
227
|
+
finally {
|
|
228
|
+
closeSync(fd);
|
|
229
|
+
}
|
|
230
|
+
lastEventCache.set(logPath, { hash, sequence });
|
|
231
|
+
// Persist last hash to sidecar for cross-segment chain continuity
|
|
232
|
+
const metaPath = `${logPath}.meta`;
|
|
233
|
+
const metaFd = openSync(metaPath, "w");
|
|
234
|
+
try {
|
|
235
|
+
writeSync(metaFd, JSON.stringify({ lastHash: hash, sequence }));
|
|
236
|
+
fsyncSync(metaFd);
|
|
237
|
+
}
|
|
238
|
+
finally {
|
|
239
|
+
closeSync(metaFd);
|
|
240
|
+
}
|
|
241
|
+
return fullEvent;
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
degraded = true;
|
|
245
|
+
writeFailures++;
|
|
246
|
+
console.warn("[AUDIT] Audit trail degraded — write failed", {
|
|
247
|
+
error: err instanceof Error ? err.message : String(err),
|
|
248
|
+
});
|
|
249
|
+
writeDeadLetter(vaultPath, {
|
|
250
|
+
source: "audit.chain.appendEvent",
|
|
251
|
+
payload: input,
|
|
252
|
+
error: err instanceof Error ? err.message : String(err),
|
|
253
|
+
timestamp: new Date().toISOString(),
|
|
254
|
+
});
|
|
255
|
+
throw err;
|
|
256
|
+
}
|
|
257
|
+
finally {
|
|
258
|
+
release();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
function getWriteFailures() {
|
|
262
|
+
return writeFailures;
|
|
263
|
+
}
|
|
264
|
+
function isDegradedFn() {
|
|
265
|
+
return degraded;
|
|
266
|
+
}
|
|
267
|
+
async function flush() {
|
|
268
|
+
const release = await mutex.acquire();
|
|
269
|
+
release();
|
|
270
|
+
}
|
|
271
|
+
function releaseWriter() {
|
|
272
|
+
lastEventCache.clear();
|
|
273
|
+
releaseLocks(locksByDir);
|
|
274
|
+
degraded = false;
|
|
275
|
+
writeFailures = 0;
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
appendEvent,
|
|
279
|
+
getWriteFailures,
|
|
280
|
+
isDegraded: isDegradedFn,
|
|
281
|
+
flush,
|
|
282
|
+
release: releaseWriter,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../../src/audit/chain.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entropy Diagnostics — Governance Health Signal
|
|
3
|
+
*
|
|
4
|
+
* Derives 6 entropy signals from audit event data to assess governance
|
|
5
|
+
* health. Entropy is a diagnostic signal, not a runtime gate.
|
|
6
|
+
*
|
|
7
|
+
* Signals:
|
|
8
|
+
* 1. Policy violations
|
|
9
|
+
* 2. Budget utilization
|
|
10
|
+
* 3. Chain integrity
|
|
11
|
+
* 4. PII detections
|
|
12
|
+
* 5. Circuit breaker trips
|
|
13
|
+
* 6. Pattern memory hits
|
|
14
|
+
*
|
|
15
|
+
* Returns a composite score 0–100 (0 = healthy, 100 = maximum entropy).
|
|
16
|
+
*
|
|
17
|
+
* Adapted from Field Project fermion/neutrino/entropy.ts — signals
|
|
18
|
+
* remapped to SDK vault structure.
|
|
19
|
+
*/
|
|
20
|
+
export interface EntropyEventInput {
|
|
21
|
+
kind: string;
|
|
22
|
+
data: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
export interface EntropySignal {
|
|
25
|
+
/** Machine-readable condition identifier */
|
|
26
|
+
condition: string;
|
|
27
|
+
/** Human-readable label */
|
|
28
|
+
label: string;
|
|
29
|
+
/** Signal value 0–1 (0 = no entropy, 1 = full entropy) */
|
|
30
|
+
value: number;
|
|
31
|
+
/** Number of events exhibiting this condition */
|
|
32
|
+
hits: number;
|
|
33
|
+
/** Total relevant events evaluated */
|
|
34
|
+
total: number;
|
|
35
|
+
}
|
|
36
|
+
export type EntropyLevel = "low" | "elevated" | "critical";
|
|
37
|
+
export interface EntropyReport {
|
|
38
|
+
/** Composite score 0–100 (weighted average of all signals, scaled) */
|
|
39
|
+
score: number;
|
|
40
|
+
/** Human-readable level derived from score */
|
|
41
|
+
level: EntropyLevel;
|
|
42
|
+
/** Per-signal breakdown */
|
|
43
|
+
signals: EntropySignal[];
|
|
44
|
+
/** ISO-8601 timestamp when the report was computed */
|
|
45
|
+
computedAt: string;
|
|
46
|
+
/** Number of events analyzed */
|
|
47
|
+
eventCount: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Signal 1: Policy violations
|
|
51
|
+
*
|
|
52
|
+
* Events where kind contains "policy" and data indicates a deny/block decision.
|
|
53
|
+
*/
|
|
54
|
+
export declare function extractPolicyViolations(events: EntropyEventInput[]): EntropySignal;
|
|
55
|
+
/**
|
|
56
|
+
* Signal 2: Budget utilization
|
|
57
|
+
*
|
|
58
|
+
* Events with budget data where utilization exceeds 80%.
|
|
59
|
+
*/
|
|
60
|
+
export declare function extractBudgetUtilization(events: EntropyEventInput[]): EntropySignal;
|
|
61
|
+
/**
|
|
62
|
+
* Signal 3: Chain integrity
|
|
63
|
+
*
|
|
64
|
+
* Events indicating hash chain verification failures or audit degradation.
|
|
65
|
+
*/
|
|
66
|
+
export declare function extractChainIntegrity(events: EntropyEventInput[]): EntropySignal;
|
|
67
|
+
/**
|
|
68
|
+
* Signal 4: PII detections
|
|
69
|
+
*
|
|
70
|
+
* Events where PII was detected in the data flow.
|
|
71
|
+
*/
|
|
72
|
+
export declare function extractPiiDetections(events: EntropyEventInput[]): EntropySignal;
|
|
73
|
+
/**
|
|
74
|
+
* Signal 5: Circuit breaker trips
|
|
75
|
+
*
|
|
76
|
+
* Events where circuit breakers were triggered.
|
|
77
|
+
*/
|
|
78
|
+
export declare function extractCircuitBreakerTrips(events: EntropyEventInput[]): EntropySignal;
|
|
79
|
+
/**
|
|
80
|
+
* Signal 6: Pattern memory hits
|
|
81
|
+
*
|
|
82
|
+
* Events where pattern memory detected recurring issues or anomalies.
|
|
83
|
+
*/
|
|
84
|
+
export declare function extractPatternMemoryHits(events: EntropyEventInput[]): EntropySignal;
|
|
85
|
+
/**
|
|
86
|
+
* Compute the composite entropy report from audit events.
|
|
87
|
+
*
|
|
88
|
+
* Each of the 6 signals contributes equally (weight = 1/6).
|
|
89
|
+
* The composite score is 0–100.
|
|
90
|
+
*
|
|
91
|
+
* @param events - Array of audit events to analyze
|
|
92
|
+
* @returns Entropy report with composite score and per-signal breakdown
|
|
93
|
+
*/
|
|
94
|
+
export declare function computeEntropyScore(events: EntropyEventInput[]): EntropyReport;
|
|
95
|
+
//# sourceMappingURL=entropy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entropy.d.ts","sourceRoot":"","sources":["../../src/audit/entropy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC7B,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,UAAU,GAAG,UAAU,CAAC;AAE3D,MAAM,WAAW,aAAa;IAC7B,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,KAAK,EAAE,YAAY,CAAC;IACpB,2BAA2B;IAC3B,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;CACnB;AAID;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,aAAa,CAmBlF;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,aAAa,CAkCnF;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,aAAa,CAwBhF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,aAAa,CA0B/E;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,aAAa,CA2BrF;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,aAAa,CA4BnF;AAmBD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,aAAa,CAc9E"}
|