@flowdot.ai/guardian-agent 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/LICENSE +40 -0
- package/README.md +281 -0
- package/ROADMAP.md +109 -0
- package/dist/audit/attestor.d.ts +102 -0
- package/dist/audit/attestor.d.ts.map +1 -0
- package/dist/audit/attestor.js +103 -0
- package/dist/audit/attestor.js.map +1 -0
- package/dist/audit/chain.d.ts +30 -0
- package/dist/audit/chain.d.ts.map +1 -0
- package/dist/audit/chain.js +65 -0
- package/dist/audit/chain.js.map +1 -0
- package/dist/audit/correlation.d.ts +114 -0
- package/dist/audit/correlation.d.ts.map +1 -0
- package/dist/audit/correlation.js +259 -0
- package/dist/audit/correlation.js.map +1 -0
- package/dist/audit/index.d.ts +13 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +8 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/reader.d.ts +30 -0
- package/dist/audit/reader.d.ts.map +1 -0
- package/dist/audit/reader.js +85 -0
- package/dist/audit/reader.js.map +1 -0
- package/dist/audit/signature.d.ts +39 -0
- package/dist/audit/signature.d.ts.map +1 -0
- package/dist/audit/signature.js +73 -0
- package/dist/audit/signature.js.map +1 -0
- package/dist/audit/stats.d.ts +106 -0
- package/dist/audit/stats.d.ts.map +1 -0
- package/dist/audit/stats.js +196 -0
- package/dist/audit/stats.js.map +1 -0
- package/dist/audit/writer.d.ts +96 -0
- package/dist/audit/writer.d.ts.map +1 -0
- package/dist/audit/writer.js +263 -0
- package/dist/audit/writer.js.map +1 -0
- package/dist/cli/guardian-baseline.d.ts +42 -0
- package/dist/cli/guardian-baseline.d.ts.map +1 -0
- package/dist/cli/guardian-baseline.js +265 -0
- package/dist/cli/guardian-baseline.js.map +1 -0
- package/dist/cli/guardian-correlator.d.ts +47 -0
- package/dist/cli/guardian-correlator.d.ts.map +1 -0
- package/dist/cli/guardian-correlator.js +217 -0
- package/dist/cli/guardian-correlator.js.map +1 -0
- package/dist/cli/guardian-verify.d.ts +30 -0
- package/dist/cli/guardian-verify.d.ts.map +1 -0
- package/dist/cli/guardian-verify.js +149 -0
- package/dist/cli/guardian-verify.js.map +1 -0
- package/dist/errors.d.ts +28 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +40 -0
- package/dist/errors.js.map +1 -0
- package/dist/estop/heartbeat.d.ts +94 -0
- package/dist/estop/heartbeat.d.ts.map +1 -0
- package/dist/estop/heartbeat.js +135 -0
- package/dist/estop/heartbeat.js.map +1 -0
- package/dist/estop/hub.d.ts +76 -0
- package/dist/estop/hub.d.ts.map +1 -0
- package/dist/estop/hub.js +167 -0
- package/dist/estop/hub.js.map +1 -0
- package/dist/estop/index.d.ts +12 -0
- package/dist/estop/index.d.ts.map +1 -0
- package/dist/estop/index.js +6 -0
- package/dist/estop/index.js.map +1 -0
- package/dist/estop/local.d.ts +31 -0
- package/dist/estop/local.d.ts.map +1 -0
- package/dist/estop/local.js +101 -0
- package/dist/estop/local.js.map +1 -0
- package/dist/estop/middleware.d.ts +36 -0
- package/dist/estop/middleware.d.ts.map +1 -0
- package/dist/estop/middleware.js +40 -0
- package/dist/estop/middleware.js.map +1 -0
- package/dist/estop/poller.d.ts +36 -0
- package/dist/estop/poller.d.ts.map +1 -0
- package/dist/estop/poller.js +85 -0
- package/dist/estop/poller.js.map +1 -0
- package/dist/estop/types.d.ts +31 -0
- package/dist/estop/types.d.ts.map +1 -0
- package/dist/estop/types.js +5 -0
- package/dist/estop/types.js.map +1 -0
- package/dist/gate/async-callback.d.ts +27 -0
- package/dist/gate/async-callback.d.ts.map +1 -0
- package/dist/gate/async-callback.js +79 -0
- package/dist/gate/async-callback.js.map +1 -0
- package/dist/gate/cli.d.ts +29 -0
- package/dist/gate/cli.d.ts.map +1 -0
- package/dist/gate/cli.js +83 -0
- package/dist/gate/cli.js.map +1 -0
- package/dist/gate/data-channel.d.ts +41 -0
- package/dist/gate/data-channel.d.ts.map +1 -0
- package/dist/gate/data-channel.js +132 -0
- package/dist/gate/data-channel.js.map +1 -0
- package/dist/gate/index.d.ts +13 -0
- package/dist/gate/index.d.ts.map +1 -0
- package/dist/gate/index.js +7 -0
- package/dist/gate/index.js.map +1 -0
- package/dist/gate/options.d.ts +90 -0
- package/dist/gate/options.d.ts.map +1 -0
- package/dist/gate/options.js +131 -0
- package/dist/gate/options.js.map +1 -0
- package/dist/gate/programmatic.d.ts +9 -0
- package/dist/gate/programmatic.d.ts.map +1 -0
- package/dist/gate/programmatic.js +20 -0
- package/dist/gate/programmatic.js.map +1 -0
- package/dist/gate/two-key.d.ts +90 -0
- package/dist/gate/two-key.d.ts.map +1 -0
- package/dist/gate/two-key.js +78 -0
- package/dist/gate/two-key.js.map +1 -0
- package/dist/gate/types.d.ts +25 -0
- package/dist/gate/types.d.ts.map +1 -0
- package/dist/gate/types.js +5 -0
- package/dist/gate/types.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/notify/console.d.ts +13 -0
- package/dist/notify/console.d.ts.map +1 -0
- package/dist/notify/console.js +27 -0
- package/dist/notify/console.js.map +1 -0
- package/dist/notify/index.d.ts +8 -0
- package/dist/notify/index.d.ts.map +1 -0
- package/dist/notify/index.js +4 -0
- package/dist/notify/index.js.map +1 -0
- package/dist/notify/multi.d.ts +14 -0
- package/dist/notify/multi.d.ts.map +1 -0
- package/dist/notify/multi.js +22 -0
- package/dist/notify/multi.js.map +1 -0
- package/dist/notify/types.d.ts +21 -0
- package/dist/notify/types.d.ts.map +1 -0
- package/dist/notify/types.js +5 -0
- package/dist/notify/types.js.map +1 -0
- package/dist/notify/webhook.d.ts +21 -0
- package/dist/notify/webhook.d.ts.map +1 -0
- package/dist/notify/webhook.js +37 -0
- package/dist/notify/webhook.js.map +1 -0
- package/dist/policy/attribution.d.ts +61 -0
- package/dist/policy/attribution.d.ts.map +1 -0
- package/dist/policy/attribution.js +116 -0
- package/dist/policy/attribution.js.map +1 -0
- package/dist/policy/evaluator.d.ts +36 -0
- package/dist/policy/evaluator.d.ts.map +1 -0
- package/dist/policy/evaluator.js +211 -0
- package/dist/policy/evaluator.js.map +1 -0
- package/dist/policy/index.d.ts +11 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +7 -0
- package/dist/policy/index.js.map +1 -0
- package/dist/policy/integrity.d.ts +17 -0
- package/dist/policy/integrity.d.ts.map +1 -0
- package/dist/policy/integrity.js +31 -0
- package/dist/policy/integrity.js.map +1 -0
- package/dist/policy/loader.d.ts +9 -0
- package/dist/policy/loader.d.ts.map +1 -0
- package/dist/policy/loader.js +124 -0
- package/dist/policy/loader.js.map +1 -0
- package/dist/policy/site-key.d.ts +22 -0
- package/dist/policy/site-key.d.ts.map +1 -0
- package/dist/policy/site-key.js +48 -0
- package/dist/policy/site-key.js.map +1 -0
- package/dist/policy/store.d.ts +45 -0
- package/dist/policy/store.d.ts.map +1 -0
- package/dist/policy/store.js +223 -0
- package/dist/policy/store.js.map +1 -0
- package/dist/policy/types.d.ts +72 -0
- package/dist/policy/types.d.ts.map +1 -0
- package/dist/policy/types.js +5 -0
- package/dist/policy/types.js.map +1 -0
- package/dist/runtime/capability.d.ts +125 -0
- package/dist/runtime/capability.d.ts.map +1 -0
- package/dist/runtime/capability.js +121 -0
- package/dist/runtime/capability.js.map +1 -0
- package/dist/runtime/honeytokens.d.ts +104 -0
- package/dist/runtime/honeytokens.d.ts.map +1 -0
- package/dist/runtime/honeytokens.js +115 -0
- package/dist/runtime/honeytokens.js.map +1 -0
- package/dist/runtime/multi-rate-limiter.d.ts +90 -0
- package/dist/runtime/multi-rate-limiter.d.ts.map +1 -0
- package/dist/runtime/multi-rate-limiter.js +133 -0
- package/dist/runtime/multi-rate-limiter.js.map +1 -0
- package/dist/runtime/runtime.d.ts +94 -0
- package/dist/runtime/runtime.d.ts.map +1 -0
- package/dist/runtime/runtime.js +276 -0
- package/dist/runtime/runtime.js.map +1 -0
- package/dist/types.d.ts +97 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit-log hash chain. SPEC §2.5.
|
|
3
|
+
*
|
|
4
|
+
* Stateless helpers; no I/O.
|
|
5
|
+
*/
|
|
6
|
+
import type { AuditRecord } from '../types.js';
|
|
7
|
+
/** The genesis hash that the first record's prev_hash points to. */
|
|
8
|
+
export declare const GENESIS_HASH = "sha256:0";
|
|
9
|
+
/**
|
|
10
|
+
* Compute the canonical hash of a record. The record's own `prev_hash` is
|
|
11
|
+
* included; the `signature` is NOT, because signatures are computed over the
|
|
12
|
+
* record with `signature: null` (so the signature itself doesn't change the
|
|
13
|
+
* record's identity in the chain).
|
|
14
|
+
*
|
|
15
|
+
* Canonical-form JSON: keys sorted lexicographically; no extra whitespace;
|
|
16
|
+
* Unicode normalized to NFC.
|
|
17
|
+
*/
|
|
18
|
+
export declare function computeRecordHash(record: AuditRecord): string;
|
|
19
|
+
/**
|
|
20
|
+
* Produce the canonical UTF-8 bytes of a record for hashing. Strips
|
|
21
|
+
* `signature` (signatures are over the unsigned record). Keys sorted.
|
|
22
|
+
*/
|
|
23
|
+
export declare function canonicalizeForHash(record: AuditRecord): Buffer;
|
|
24
|
+
/**
|
|
25
|
+
* Stable JSON.stringify: sort keys recursively. Matches Python's
|
|
26
|
+
* `json.dumps(..., sort_keys=True, separators=(',', ':'))` byte-for-byte for
|
|
27
|
+
* the field types we use (strings, numbers, booleans, null, arrays, objects).
|
|
28
|
+
*/
|
|
29
|
+
export declare function canonicalJsonStringify(value: unknown): string;
|
|
30
|
+
//# sourceMappingURL=chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../../src/audit/chain.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,oEAAoE;AACpE,eAAO,MAAM,YAAY,aAAa,CAAC;AAEvC;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAG7D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAG/D;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAyB7D"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit-log hash chain. SPEC §2.5.
|
|
3
|
+
*
|
|
4
|
+
* Stateless helpers; no I/O.
|
|
5
|
+
*/
|
|
6
|
+
import { createHash } from 'node:crypto';
|
|
7
|
+
/** The genesis hash that the first record's prev_hash points to. */
|
|
8
|
+
export const GENESIS_HASH = 'sha256:0';
|
|
9
|
+
/**
|
|
10
|
+
* Compute the canonical hash of a record. The record's own `prev_hash` is
|
|
11
|
+
* included; the `signature` is NOT, because signatures are computed over the
|
|
12
|
+
* record with `signature: null` (so the signature itself doesn't change the
|
|
13
|
+
* record's identity in the chain).
|
|
14
|
+
*
|
|
15
|
+
* Canonical-form JSON: keys sorted lexicographically; no extra whitespace;
|
|
16
|
+
* Unicode normalized to NFC.
|
|
17
|
+
*/
|
|
18
|
+
export function computeRecordHash(record) {
|
|
19
|
+
const canonical = canonicalizeForHash(record);
|
|
20
|
+
return 'sha256:' + createHash('sha256').update(canonical).digest('hex');
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Produce the canonical UTF-8 bytes of a record for hashing. Strips
|
|
24
|
+
* `signature` (signatures are over the unsigned record). Keys sorted.
|
|
25
|
+
*/
|
|
26
|
+
export function canonicalizeForHash(record) {
|
|
27
|
+
const { signature: _signature, ...rest } = record;
|
|
28
|
+
return Buffer.from(canonicalJsonStringify(rest), 'utf-8');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Stable JSON.stringify: sort keys recursively. Matches Python's
|
|
32
|
+
* `json.dumps(..., sort_keys=True, separators=(',', ':'))` byte-for-byte for
|
|
33
|
+
* the field types we use (strings, numbers, booleans, null, arrays, objects).
|
|
34
|
+
*/
|
|
35
|
+
export function canonicalJsonStringify(value) {
|
|
36
|
+
if (value === null)
|
|
37
|
+
return 'null';
|
|
38
|
+
if (typeof value === 'number') {
|
|
39
|
+
if (!Number.isFinite(value)) {
|
|
40
|
+
throw new TypeError('non-finite numbers cannot be canonicalized');
|
|
41
|
+
}
|
|
42
|
+
return JSON.stringify(value);
|
|
43
|
+
}
|
|
44
|
+
if (typeof value === 'string')
|
|
45
|
+
return JSON.stringify(value);
|
|
46
|
+
if (typeof value === 'boolean')
|
|
47
|
+
return value ? 'true' : 'false';
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
return '[' + value.map(canonicalJsonStringify).join(',') + ']';
|
|
50
|
+
}
|
|
51
|
+
if (typeof value === 'object') {
|
|
52
|
+
const obj = value;
|
|
53
|
+
const keys = Object.keys(obj).sort();
|
|
54
|
+
const parts = [];
|
|
55
|
+
for (const k of keys) {
|
|
56
|
+
const v = obj[k];
|
|
57
|
+
if (v === undefined)
|
|
58
|
+
continue;
|
|
59
|
+
parts.push(JSON.stringify(k) + ':' + canonicalJsonStringify(v));
|
|
60
|
+
}
|
|
61
|
+
return '{' + parts.join(',') + '}';
|
|
62
|
+
}
|
|
63
|
+
throw new TypeError(`cannot canonicalize value of type ${typeof value}`);
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../../src/audit/chain.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC,oEAAoE;AACpE,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC;AAEvC;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAmB;IACnD,MAAM,SAAS,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC9C,OAAO,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAmB;IACrD,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC;IAClD,OAAO,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;AAC5D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAc;IACnD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,SAAS,CAAC,4CAA4C,CAAC,CAAC;QACpE,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5D,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAChE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACjE,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,KAAgC,CAAC;QAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QACrC,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YACjB,IAAI,CAAC,KAAK,SAAS;gBAAE,SAAS;YAC9B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;QAClE,CAAC;QACD,OAAO,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACrC,CAAC;IACD,MAAM,IAAI,SAAS,CAAC,qCAAqC,OAAO,KAAK,EAAE,CAAC,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-surface correlation. SPEC §14 (v0.5.0+).
|
|
3
|
+
*
|
|
4
|
+
* Reads audit records from multiple sources (typically one per surface —
|
|
5
|
+
* `cli.jsonl`, `mcp.jsonl`, etc.) and looks for patterns that span
|
|
6
|
+
* surfaces under the same `agent_id`:
|
|
7
|
+
*
|
|
8
|
+
* - Overlapping sessions: same agent_id running concurrent sessions on
|
|
9
|
+
* two different surfaces.
|
|
10
|
+
* - Identical args: canonical-JSON-SHA256 of `tool.args` collides
|
|
11
|
+
* across surfaces within a configurable time window.
|
|
12
|
+
* - Sequence similarity: cosine similarity of per-session tool-frequency
|
|
13
|
+
* vectors above a configurable threshold.
|
|
14
|
+
*
|
|
15
|
+
* All three patterns are deterministic predicates on input. The library
|
|
16
|
+
* produces match records; the operator decides what to do with them.
|
|
17
|
+
*
|
|
18
|
+
* Read-only on source audit files. Output is written to a separate
|
|
19
|
+
* `correlations.jsonl` log so source-log integrity (hash chain,
|
|
20
|
+
* signatures) is never touched.
|
|
21
|
+
*/
|
|
22
|
+
import type { AuditRecord } from '../types.js';
|
|
23
|
+
export interface AuditSource {
|
|
24
|
+
/** Stable surface id, used in match records. Typical: `'cli'`, `'mcp'`, `'native'`. */
|
|
25
|
+
surface: string;
|
|
26
|
+
/** Records from this surface. Caller is responsible for loading. */
|
|
27
|
+
records: AuditRecord[];
|
|
28
|
+
}
|
|
29
|
+
export interface SessionSummary {
|
|
30
|
+
surface: string;
|
|
31
|
+
agent_id: string;
|
|
32
|
+
session_id: string;
|
|
33
|
+
/** Earliest record `ts` (ISO-8601). */
|
|
34
|
+
start: string;
|
|
35
|
+
/** Latest record `ts` (ISO-8601). */
|
|
36
|
+
end: string;
|
|
37
|
+
/** Wall-clock duration in ms. */
|
|
38
|
+
duration_ms: number;
|
|
39
|
+
/** Per-tool call counts. */
|
|
40
|
+
tool_frequency: Record<string, number>;
|
|
41
|
+
/** SHA-256(canonical-JSON(args)) for each tool_call record in this session, in order. */
|
|
42
|
+
args_hashes: {
|
|
43
|
+
event_id: string;
|
|
44
|
+
ts: string;
|
|
45
|
+
tool_name: string;
|
|
46
|
+
args_hash: string;
|
|
47
|
+
}[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Summarize a source's records into one entry per (agent_id, session_id).
|
|
51
|
+
*/
|
|
52
|
+
export declare function summarizeSessions(source: AuditSource): SessionSummary[];
|
|
53
|
+
/**
|
|
54
|
+
* One correlation finding. Written as a JSONL row with `kind:
|
|
55
|
+
* 'x_cross_surface_match'` to the operator's correlations log.
|
|
56
|
+
*/
|
|
57
|
+
export interface CorrelationMatch {
|
|
58
|
+
kind: 'x_cross_surface_match';
|
|
59
|
+
agent_id: string;
|
|
60
|
+
match_type: 'overlapping_sessions' | 'args_hash_collision' | 'sequence_similarity';
|
|
61
|
+
/** Always 2 surfaces (pairwise). */
|
|
62
|
+
surfaces: [string, string];
|
|
63
|
+
/** Session ids on each side, in surfaces order. */
|
|
64
|
+
session_ids: [string, string];
|
|
65
|
+
detail: Record<string, unknown>;
|
|
66
|
+
}
|
|
67
|
+
export interface CorrelationOptions {
|
|
68
|
+
/**
|
|
69
|
+
* For args-hash collisions: max ms between the two collisions to count as
|
|
70
|
+
* a match. Default 60_000 (1 min) — collisions further apart aren't
|
|
71
|
+
* load-bearing for "running in parallel."
|
|
72
|
+
*/
|
|
73
|
+
argsHashWindowMs?: number;
|
|
74
|
+
/**
|
|
75
|
+
* For sequence similarity: cosine threshold in [0,1]. Default 0.9 —
|
|
76
|
+
* very similar tool-frequency vectors across surfaces in close time.
|
|
77
|
+
*/
|
|
78
|
+
similarityThreshold?: number;
|
|
79
|
+
/**
|
|
80
|
+
* For sequence similarity: only compare sessions whose time windows are
|
|
81
|
+
* within this many ms of each other (start-to-start). Default 600_000
|
|
82
|
+
* (10 min).
|
|
83
|
+
*/
|
|
84
|
+
similarityWindowMs?: number;
|
|
85
|
+
/**
|
|
86
|
+
* For sequence similarity: minimum tool_call count per session to be
|
|
87
|
+
* considered. Vectors that are too sparse trivially correlate.
|
|
88
|
+
* Default 5.
|
|
89
|
+
*/
|
|
90
|
+
similarityMinCalls?: number;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Run all three correlators across the given sources. Returns matches in
|
|
94
|
+
* insertion order (overlap → hash → similarity).
|
|
95
|
+
*/
|
|
96
|
+
export declare function correlate(sources: readonly AuditSource[], options?: CorrelationOptions): CorrelationMatch[];
|
|
97
|
+
/**
|
|
98
|
+
* Detect pairs of sessions on different surfaces (same agent_id) whose
|
|
99
|
+
* time windows overlap. "Overlap" = [start1,end1] ∩ [start2,end2] ≠ ∅.
|
|
100
|
+
*/
|
|
101
|
+
export declare function findOverlappingSessions(sessions: SessionSummary[]): CorrelationMatch[];
|
|
102
|
+
/**
|
|
103
|
+
* Detect args-hash collisions across surfaces within a time window for the
|
|
104
|
+
* same agent_id. A collision means: identical canonical-JSON-SHA256(args)
|
|
105
|
+
* for the same `tool_name`, in two different surfaces, within `windowMs`.
|
|
106
|
+
*/
|
|
107
|
+
export declare function findArgsHashCollisions(sessions: SessionSummary[], windowMs: number): CorrelationMatch[];
|
|
108
|
+
/**
|
|
109
|
+
* Detect pairs of sessions on different surfaces (same agent_id) whose
|
|
110
|
+
* tool-frequency vectors have cosine similarity above the threshold AND
|
|
111
|
+
* whose start times are within `similarityWindowMs`.
|
|
112
|
+
*/
|
|
113
|
+
export declare function findSequenceSimilarity(sessions: SessionSummary[], options: Required<CorrelationOptions>): CorrelationMatch[];
|
|
114
|
+
//# sourceMappingURL=correlation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"correlation.d.ts","sourceRoot":"","sources":["../../src/audit/correlation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/C,MAAM,WAAW,WAAW;IAC1B,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAMD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,yFAAyF;IACzF,WAAW,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACvF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,cAAc,EAAE,CAmCvE;AAUD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,uBAAuB,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,sBAAsB,GAAG,qBAAqB,GAAG,qBAAqB,CAAC;IACnF,oCAAoC;IACpC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,mDAAmD;IACnD,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AASD;;;GAGG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,OAAO,GAAE,kBAAuB,GAC/B,gBAAgB,EAAE,CAoBpB;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,gBAAgB,EAAE,CAgCtF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,cAAc,EAAE,EAC1B,QAAQ,EAAE,MAAM,GACf,gBAAgB,EAAE,CA8CpB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,cAAc,EAAE,EAC1B,OAAO,EAAE,QAAQ,CAAC,kBAAkB,CAAC,GACpC,gBAAgB,EAAE,CAqCpB"}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-surface correlation. SPEC §14 (v0.5.0+).
|
|
3
|
+
*
|
|
4
|
+
* Reads audit records from multiple sources (typically one per surface —
|
|
5
|
+
* `cli.jsonl`, `mcp.jsonl`, etc.) and looks for patterns that span
|
|
6
|
+
* surfaces under the same `agent_id`:
|
|
7
|
+
*
|
|
8
|
+
* - Overlapping sessions: same agent_id running concurrent sessions on
|
|
9
|
+
* two different surfaces.
|
|
10
|
+
* - Identical args: canonical-JSON-SHA256 of `tool.args` collides
|
|
11
|
+
* across surfaces within a configurable time window.
|
|
12
|
+
* - Sequence similarity: cosine similarity of per-session tool-frequency
|
|
13
|
+
* vectors above a configurable threshold.
|
|
14
|
+
*
|
|
15
|
+
* All three patterns are deterministic predicates on input. The library
|
|
16
|
+
* produces match records; the operator decides what to do with them.
|
|
17
|
+
*
|
|
18
|
+
* Read-only on source audit files. Output is written to a separate
|
|
19
|
+
* `correlations.jsonl` log so source-log integrity (hash chain,
|
|
20
|
+
* signatures) is never touched.
|
|
21
|
+
*/
|
|
22
|
+
import { createHash } from 'node:crypto';
|
|
23
|
+
import { canonicalJsonStringify } from './chain.js';
|
|
24
|
+
/**
|
|
25
|
+
* Summarize a source's records into one entry per (agent_id, session_id).
|
|
26
|
+
*/
|
|
27
|
+
export function summarizeSessions(source) {
|
|
28
|
+
const map = new Map();
|
|
29
|
+
for (const r of source.records) {
|
|
30
|
+
const key = `${r.agent_id}::${r.session_id}`;
|
|
31
|
+
let s = map.get(key);
|
|
32
|
+
if (!s) {
|
|
33
|
+
s = {
|
|
34
|
+
surface: source.surface,
|
|
35
|
+
agent_id: r.agent_id,
|
|
36
|
+
session_id: r.session_id,
|
|
37
|
+
start: r.ts,
|
|
38
|
+
end: r.ts,
|
|
39
|
+
duration_ms: 0,
|
|
40
|
+
tool_frequency: {},
|
|
41
|
+
args_hashes: [],
|
|
42
|
+
};
|
|
43
|
+
map.set(key, s);
|
|
44
|
+
}
|
|
45
|
+
if (r.ts < s.start)
|
|
46
|
+
s.start = r.ts;
|
|
47
|
+
if (r.ts > s.end)
|
|
48
|
+
s.end = r.ts;
|
|
49
|
+
if (r.kind === 'tool_call' && r.tool) {
|
|
50
|
+
s.tool_frequency[r.tool.name] = (s.tool_frequency[r.tool.name] ?? 0) + 1;
|
|
51
|
+
s.args_hashes.push({
|
|
52
|
+
event_id: r.event_id,
|
|
53
|
+
ts: r.ts,
|
|
54
|
+
tool_name: r.tool.name,
|
|
55
|
+
args_hash: hashArgs(r.tool.args),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Compute duration once.
|
|
60
|
+
for (const s of map.values()) {
|
|
61
|
+
s.duration_ms = new Date(s.end).getTime() - new Date(s.start).getTime();
|
|
62
|
+
}
|
|
63
|
+
return Array.from(map.values());
|
|
64
|
+
}
|
|
65
|
+
function hashArgs(args) {
|
|
66
|
+
return 'sha256:' + createHash('sha256').update(canonicalJsonStringify(args)).digest('hex');
|
|
67
|
+
}
|
|
68
|
+
const DEFAULT_OPTS = {
|
|
69
|
+
argsHashWindowMs: 60_000,
|
|
70
|
+
similarityThreshold: 0.9,
|
|
71
|
+
similarityWindowMs: 600_000,
|
|
72
|
+
similarityMinCalls: 5,
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Run all three correlators across the given sources. Returns matches in
|
|
76
|
+
* insertion order (overlap → hash → similarity).
|
|
77
|
+
*/
|
|
78
|
+
export function correlate(sources, options = {}) {
|
|
79
|
+
const opts = { ...DEFAULT_OPTS, ...options };
|
|
80
|
+
const summaries = sources.flatMap((s) => summarizeSessions(s));
|
|
81
|
+
// Index by agent_id.
|
|
82
|
+
const byAgent = new Map();
|
|
83
|
+
for (const s of summaries) {
|
|
84
|
+
let list = byAgent.get(s.agent_id);
|
|
85
|
+
if (!list) {
|
|
86
|
+
list = [];
|
|
87
|
+
byAgent.set(s.agent_id, list);
|
|
88
|
+
}
|
|
89
|
+
list.push(s);
|
|
90
|
+
}
|
|
91
|
+
const out = [];
|
|
92
|
+
for (const sessions of byAgent.values()) {
|
|
93
|
+
out.push(...findOverlappingSessions(sessions));
|
|
94
|
+
out.push(...findArgsHashCollisions(sessions, opts.argsHashWindowMs));
|
|
95
|
+
out.push(...findSequenceSimilarity(sessions, opts));
|
|
96
|
+
}
|
|
97
|
+
return out;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Detect pairs of sessions on different surfaces (same agent_id) whose
|
|
101
|
+
* time windows overlap. "Overlap" = [start1,end1] ∩ [start2,end2] ≠ ∅.
|
|
102
|
+
*/
|
|
103
|
+
export function findOverlappingSessions(sessions) {
|
|
104
|
+
const out = [];
|
|
105
|
+
for (let i = 0; i < sessions.length; i++) {
|
|
106
|
+
for (let j = i + 1; j < sessions.length; j++) {
|
|
107
|
+
const a = sessions[i];
|
|
108
|
+
const b = sessions[j];
|
|
109
|
+
if (a.surface === b.surface)
|
|
110
|
+
continue;
|
|
111
|
+
const aStart = new Date(a.start).getTime();
|
|
112
|
+
const aEnd = new Date(a.end).getTime();
|
|
113
|
+
const bStart = new Date(b.start).getTime();
|
|
114
|
+
const bEnd = new Date(b.end).getTime();
|
|
115
|
+
if (aStart <= bEnd && bStart <= aEnd) {
|
|
116
|
+
const overlapStart = Math.max(aStart, bStart);
|
|
117
|
+
const overlapEnd = Math.min(aEnd, bEnd);
|
|
118
|
+
out.push({
|
|
119
|
+
kind: 'x_cross_surface_match',
|
|
120
|
+
agent_id: a.agent_id,
|
|
121
|
+
match_type: 'overlapping_sessions',
|
|
122
|
+
surfaces: [a.surface, b.surface],
|
|
123
|
+
session_ids: [a.session_id, b.session_id],
|
|
124
|
+
detail: {
|
|
125
|
+
overlap_start: new Date(overlapStart).toISOString(),
|
|
126
|
+
overlap_end: new Date(overlapEnd).toISOString(),
|
|
127
|
+
overlap_ms: overlapEnd - overlapStart,
|
|
128
|
+
session_a_window: [a.start, a.end],
|
|
129
|
+
session_b_window: [b.start, b.end],
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Detect args-hash collisions across surfaces within a time window for the
|
|
139
|
+
* same agent_id. A collision means: identical canonical-JSON-SHA256(args)
|
|
140
|
+
* for the same `tool_name`, in two different surfaces, within `windowMs`.
|
|
141
|
+
*/
|
|
142
|
+
export function findArgsHashCollisions(sessions, windowMs) {
|
|
143
|
+
const out = [];
|
|
144
|
+
const byKey = new Map();
|
|
145
|
+
for (const session of sessions) {
|
|
146
|
+
for (const h of session.args_hashes) {
|
|
147
|
+
const key = `${h.tool_name}::${h.args_hash}`;
|
|
148
|
+
let list = byKey.get(key);
|
|
149
|
+
if (!list) {
|
|
150
|
+
list = [];
|
|
151
|
+
byKey.set(key, list);
|
|
152
|
+
}
|
|
153
|
+
list.push({ ...h, session });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
for (const [key, entries] of byKey) {
|
|
157
|
+
if (entries.length < 2)
|
|
158
|
+
continue;
|
|
159
|
+
// Pairwise: find pairs in different surfaces within windowMs.
|
|
160
|
+
for (let i = 0; i < entries.length; i++) {
|
|
161
|
+
for (let j = i + 1; j < entries.length; j++) {
|
|
162
|
+
const a = entries[i];
|
|
163
|
+
const b = entries[j];
|
|
164
|
+
if (a.session.surface === b.session.surface)
|
|
165
|
+
continue;
|
|
166
|
+
const aT = new Date(a.ts).getTime();
|
|
167
|
+
const bT = new Date(b.ts).getTime();
|
|
168
|
+
if (Math.abs(aT - bT) > windowMs)
|
|
169
|
+
continue;
|
|
170
|
+
const [tool_name, args_hash] = key.split('::');
|
|
171
|
+
out.push({
|
|
172
|
+
kind: 'x_cross_surface_match',
|
|
173
|
+
agent_id: a.session.agent_id,
|
|
174
|
+
match_type: 'args_hash_collision',
|
|
175
|
+
surfaces: [a.session.surface, b.session.surface],
|
|
176
|
+
session_ids: [a.session.session_id, b.session.session_id],
|
|
177
|
+
detail: {
|
|
178
|
+
tool_name,
|
|
179
|
+
args_hash,
|
|
180
|
+
event_id_a: a.event_id,
|
|
181
|
+
event_id_b: b.event_id,
|
|
182
|
+
delta_ms: Math.abs(aT - bT),
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return out;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Detect pairs of sessions on different surfaces (same agent_id) whose
|
|
192
|
+
* tool-frequency vectors have cosine similarity above the threshold AND
|
|
193
|
+
* whose start times are within `similarityWindowMs`.
|
|
194
|
+
*/
|
|
195
|
+
export function findSequenceSimilarity(sessions, options) {
|
|
196
|
+
const out = [];
|
|
197
|
+
// Build vocabulary.
|
|
198
|
+
const vocab = new Set();
|
|
199
|
+
for (const s of sessions) {
|
|
200
|
+
for (const name of Object.keys(s.tool_frequency))
|
|
201
|
+
vocab.add(name);
|
|
202
|
+
}
|
|
203
|
+
const vocabList = Array.from(vocab);
|
|
204
|
+
for (let i = 0; i < sessions.length; i++) {
|
|
205
|
+
for (let j = i + 1; j < sessions.length; j++) {
|
|
206
|
+
const a = sessions[i];
|
|
207
|
+
const b = sessions[j];
|
|
208
|
+
if (a.surface === b.surface)
|
|
209
|
+
continue;
|
|
210
|
+
const aCalls = sumValues(a.tool_frequency);
|
|
211
|
+
const bCalls = sumValues(b.tool_frequency);
|
|
212
|
+
if (aCalls < options.similarityMinCalls || bCalls < options.similarityMinCalls)
|
|
213
|
+
continue;
|
|
214
|
+
const dt = Math.abs(new Date(a.start).getTime() - new Date(b.start).getTime());
|
|
215
|
+
if (dt > options.similarityWindowMs)
|
|
216
|
+
continue;
|
|
217
|
+
const sim = cosineSimilarity(a.tool_frequency, b.tool_frequency, vocabList);
|
|
218
|
+
if (sim >= options.similarityThreshold) {
|
|
219
|
+
out.push({
|
|
220
|
+
kind: 'x_cross_surface_match',
|
|
221
|
+
agent_id: a.agent_id,
|
|
222
|
+
match_type: 'sequence_similarity',
|
|
223
|
+
surfaces: [a.surface, b.surface],
|
|
224
|
+
session_ids: [a.session_id, b.session_id],
|
|
225
|
+
detail: {
|
|
226
|
+
cosine_similarity: sim,
|
|
227
|
+
window_dt_ms: dt,
|
|
228
|
+
session_a_calls: aCalls,
|
|
229
|
+
session_b_calls: bCalls,
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return out;
|
|
236
|
+
}
|
|
237
|
+
function sumValues(m) {
|
|
238
|
+
let s = 0;
|
|
239
|
+
for (const v of Object.values(m))
|
|
240
|
+
s += v;
|
|
241
|
+
return s;
|
|
242
|
+
}
|
|
243
|
+
function cosineSimilarity(a, b, vocab) {
|
|
244
|
+
let dot = 0;
|
|
245
|
+
let magA = 0;
|
|
246
|
+
let magB = 0;
|
|
247
|
+
for (const term of vocab) {
|
|
248
|
+
const va = a[term] ?? 0;
|
|
249
|
+
const vb = b[term] ?? 0;
|
|
250
|
+
dot += va * vb;
|
|
251
|
+
magA += va * va;
|
|
252
|
+
magB += vb * vb;
|
|
253
|
+
}
|
|
254
|
+
/* c8 ignore next */
|
|
255
|
+
if (magA === 0 || magB === 0)
|
|
256
|
+
return 0;
|
|
257
|
+
return dot / (Math.sqrt(magA) * Math.sqrt(magB));
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=correlation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"correlation.js","sourceRoot":"","sources":["../../src/audit/correlation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { AuditLogWriter } from './writer.js';
|
|
2
|
+
export type { AuditLogWriterOptions } from './writer.js';
|
|
3
|
+
export { AuditLogReader } from './reader.js';
|
|
4
|
+
export { GENESIS_HASH, computeRecordHash, canonicalJsonStringify, canonicalizeForHash, } from './chain.js';
|
|
5
|
+
export { generateEd25519KeyPair, loadPrivateKey, loadPublicKey, signRecord, verifyRecord, SIGNATURE_PREFIX, } from './signature.js';
|
|
6
|
+
export type { Ed25519KeyPair } from './signature.js';
|
|
7
|
+
export { httpAttestor, nullAttestor, payloadFromRecord, } from './attestor.js';
|
|
8
|
+
export type { Attestor, AttestationPayload, AttestationReceipt, HttpAttestorOptions, } from './attestor.js';
|
|
9
|
+
export { analyzeAgent, analyzeMultiAgent, compareToBaseline, mean, stddev, } from './stats.js';
|
|
10
|
+
export type { AgentProfile, Deviation, DeviationReport, CompareOptions, } from './stats.js';
|
|
11
|
+
export { correlate, summarizeSessions, findOverlappingSessions, findArgsHashCollisions, findSequenceSimilarity, } from './correlation.js';
|
|
12
|
+
export type { AuditSource, SessionSummary, CorrelationMatch, CorrelationOptions, } from './correlation.js';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,aAAa,EACb,UAAU,EACV,YAAY,EACZ,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,iBAAiB,GAClB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,QAAQ,EACR,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,IAAI,EACJ,MAAM,GACP,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,YAAY,EACZ,SAAS,EACT,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { AuditLogWriter } from './writer.js';
|
|
2
|
+
export { AuditLogReader } from './reader.js';
|
|
3
|
+
export { GENESIS_HASH, computeRecordHash, canonicalJsonStringify, canonicalizeForHash, } from './chain.js';
|
|
4
|
+
export { generateEd25519KeyPair, loadPrivateKey, loadPublicKey, signRecord, verifyRecord, SIGNATURE_PREFIX, } from './signature.js';
|
|
5
|
+
export { httpAttestor, nullAttestor, payloadFromRecord, } from './attestor.js';
|
|
6
|
+
export { analyzeAgent, analyzeMultiAgent, compareToBaseline, mean, stddev, } from './stats.js';
|
|
7
|
+
export { correlate, summarizeSessions, findOverlappingSessions, findArgsHashCollisions, findSequenceSimilarity, } from './correlation.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/audit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,aAAa,EACb,UAAU,EACV,YAAY,EACZ,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAOvB,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,IAAI,EACJ,MAAM,GACP,MAAM,YAAY,CAAC;AAOpB,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuditLogReader — iterate + verify hash chain. SPEC §2.
|
|
3
|
+
*/
|
|
4
|
+
import type { KeyObject } from 'node:crypto';
|
|
5
|
+
import type { AuditRecord } from '../types.js';
|
|
6
|
+
export declare class AuditLogReader {
|
|
7
|
+
readonly path: string;
|
|
8
|
+
private handle;
|
|
9
|
+
private constructor();
|
|
10
|
+
static open(path: string): Promise<AuditLogReader>;
|
|
11
|
+
/** Async-iterate over all records. Each call returns a fresh iterator. */
|
|
12
|
+
records(): AsyncGenerator<AuditRecord, void, void>;
|
|
13
|
+
/**
|
|
14
|
+
* Verify every record's ed25519 signature against the given public key.
|
|
15
|
+
* Throws GuardianIntegrityError on the first record with a missing or
|
|
16
|
+
* invalid signature. Returns the count of records verified.
|
|
17
|
+
*
|
|
18
|
+
* SPEC §2.6.
|
|
19
|
+
*/
|
|
20
|
+
verifySignatures(publicKey: KeyObject): Promise<number>;
|
|
21
|
+
/**
|
|
22
|
+
* Verify the full hash chain. Throws GuardianIntegrityError on first break.
|
|
23
|
+
* Returns the count of records verified on success.
|
|
24
|
+
*/
|
|
25
|
+
verifyChain(): Promise<number>;
|
|
26
|
+
/** Idempotent close. */
|
|
27
|
+
close(): Promise<void>;
|
|
28
|
+
private openLineStream;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../src/audit/reader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK/C,qBAAa,cAAc;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,OAAO,CAAC,MAAM,CAA2B;IAEzC,OAAO;WAIM,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAMxD,0EAA0E;IACnE,OAAO,IAAI,cAAc,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC;IAYzD;;;;;;OAMG;IACG,gBAAgB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IAmB7D;;;OAGG;IACG,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;IAgBpC,wBAAwB;IAClB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B,OAAO,CAAC,cAAc;CAKvB"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuditLogReader — iterate + verify hash chain. SPEC §2.
|
|
3
|
+
*/
|
|
4
|
+
import { open } from 'node:fs/promises';
|
|
5
|
+
import { createReadStream } from 'node:fs';
|
|
6
|
+
import { createInterface } from 'node:readline';
|
|
7
|
+
import { GuardianIntegrityError } from '../errors.js';
|
|
8
|
+
import { GENESIS_HASH, computeRecordHash } from './chain.js';
|
|
9
|
+
import { verifyRecord } from './signature.js';
|
|
10
|
+
export class AuditLogReader {
|
|
11
|
+
path;
|
|
12
|
+
handle = null;
|
|
13
|
+
constructor(path) {
|
|
14
|
+
this.path = path;
|
|
15
|
+
}
|
|
16
|
+
static async open(path) {
|
|
17
|
+
const reader = new AuditLogReader(path);
|
|
18
|
+
reader.handle = await open(path, 'r');
|
|
19
|
+
return reader;
|
|
20
|
+
}
|
|
21
|
+
/** Async-iterate over all records. Each call returns a fresh iterator. */
|
|
22
|
+
async *records() {
|
|
23
|
+
const lines = this.openLineStream();
|
|
24
|
+
try {
|
|
25
|
+
for await (const line of lines) {
|
|
26
|
+
if (line.length === 0)
|
|
27
|
+
continue;
|
|
28
|
+
yield JSON.parse(line);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
lines.close();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Verify every record's ed25519 signature against the given public key.
|
|
37
|
+
* Throws GuardianIntegrityError on the first record with a missing or
|
|
38
|
+
* invalid signature. Returns the count of records verified.
|
|
39
|
+
*
|
|
40
|
+
* SPEC §2.6.
|
|
41
|
+
*/
|
|
42
|
+
async verifySignatures(publicKey) {
|
|
43
|
+
let count = 0;
|
|
44
|
+
for await (const record of this.records()) {
|
|
45
|
+
if (record.signature == null) {
|
|
46
|
+
throw new GuardianIntegrityError(`audit log record ${count + 1} has no signature`);
|
|
47
|
+
}
|
|
48
|
+
if (!verifyRecord(record, publicKey)) {
|
|
49
|
+
throw new GuardianIntegrityError(`audit log signature verification failed at record ${count + 1}`, `event_id=${record.event_id}`);
|
|
50
|
+
}
|
|
51
|
+
count++;
|
|
52
|
+
}
|
|
53
|
+
return count;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Verify the full hash chain. Throws GuardianIntegrityError on first break.
|
|
57
|
+
* Returns the count of records verified on success.
|
|
58
|
+
*/
|
|
59
|
+
async verifyChain() {
|
|
60
|
+
let expectedPrev = GENESIS_HASH;
|
|
61
|
+
let count = 0;
|
|
62
|
+
for await (const record of this.records()) {
|
|
63
|
+
if (record.prev_hash !== expectedPrev) {
|
|
64
|
+
throw new GuardianIntegrityError(`audit log hash chain broken at record ${count + 1}`, `expected prev_hash=${expectedPrev}, got ${record.prev_hash}`);
|
|
65
|
+
}
|
|
66
|
+
expectedPrev = computeRecordHash(record);
|
|
67
|
+
count++;
|
|
68
|
+
}
|
|
69
|
+
return count;
|
|
70
|
+
}
|
|
71
|
+
/** Idempotent close. */
|
|
72
|
+
async close() {
|
|
73
|
+
if (this.handle) {
|
|
74
|
+
await this.handle.close();
|
|
75
|
+
this.handle = null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// ---- internal --------------------------------------------------------------
|
|
79
|
+
openLineStream() {
|
|
80
|
+
// We open a fresh read stream for each iteration so consumers can re-iterate.
|
|
81
|
+
const stream = createReadStream(this.path, { encoding: 'utf-8' });
|
|
82
|
+
return createInterface({ input: stream, crlfDelay: Infinity });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader.js","sourceRoot":"","sources":["../../src/audit/reader.ts"],"names":[],"mappings":"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"}
|