@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,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single-writer append-only JSONL audit log with hash chain. SPEC §2.
|
|
3
|
+
*/
|
|
4
|
+
import { open } from 'node:fs/promises';
|
|
5
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
6
|
+
import { ulid } from 'ulidx';
|
|
7
|
+
import { SPEC_VERSION } from '../types.js';
|
|
8
|
+
import { GENESIS_HASH, computeRecordHash, canonicalJsonStringify } from './chain.js';
|
|
9
|
+
import { signRecord } from './signature.js';
|
|
10
|
+
import { payloadFromRecord } from './attestor.js';
|
|
11
|
+
/**
|
|
12
|
+
* Append-only writer. Internal queue ensures the hash chain is strictly
|
|
13
|
+
* ordered even when callers `append` concurrently.
|
|
14
|
+
*/
|
|
15
|
+
export class AuditLogWriter {
|
|
16
|
+
path;
|
|
17
|
+
agentId;
|
|
18
|
+
sessionId;
|
|
19
|
+
fileMode;
|
|
20
|
+
handle = null;
|
|
21
|
+
openPromise = null;
|
|
22
|
+
closed = false;
|
|
23
|
+
_tipHash = GENESIS_HASH;
|
|
24
|
+
queue = Promise.resolve();
|
|
25
|
+
signWith;
|
|
26
|
+
onTipRecovered;
|
|
27
|
+
attestor;
|
|
28
|
+
attestEvery;
|
|
29
|
+
attestOnClose;
|
|
30
|
+
// Running count of records appended in THIS process. Reset to 0 on open()
|
|
31
|
+
// and incremented on each writeOne. Used to fire attestation at fixed
|
|
32
|
+
// intervals.
|
|
33
|
+
appendedCount = 0;
|
|
34
|
+
// Set true while emitting an attestation-related audit row, so the
|
|
35
|
+
// attestation hook does NOT re-trigger on its own audit rows. Prevents
|
|
36
|
+
// unbounded recursion: an attestation row would otherwise be the next
|
|
37
|
+
// record to attest.
|
|
38
|
+
attestationInFlight = false;
|
|
39
|
+
constructor(options) {
|
|
40
|
+
this.path = options.path;
|
|
41
|
+
this.agentId = options.agentId;
|
|
42
|
+
this.sessionId = options.sessionId;
|
|
43
|
+
this.fileMode = options.fileMode ?? 0o600;
|
|
44
|
+
this.signWith = options.signWith;
|
|
45
|
+
this.onTipRecovered = options.onTipRecovered;
|
|
46
|
+
this.attestor = options.attestor;
|
|
47
|
+
this.attestEvery = options.attestEvery ?? 100;
|
|
48
|
+
this.attestOnClose = options.attestOnClose ?? true;
|
|
49
|
+
if (this.attestEvery <= 0) {
|
|
50
|
+
throw new Error('attestEvery must be > 0');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Tip of the hash chain (the last appended record's hash). */
|
|
54
|
+
get tipHash() {
|
|
55
|
+
return this._tipHash;
|
|
56
|
+
}
|
|
57
|
+
/** Open the underlying file (idempotent + single-flight). Recovers tip hash if file exists. */
|
|
58
|
+
async open() {
|
|
59
|
+
if (this.openPromise)
|
|
60
|
+
return this.openPromise;
|
|
61
|
+
this.openPromise = (async () => {
|
|
62
|
+
let recoveredTip = null;
|
|
63
|
+
if (existsSync(this.path)) {
|
|
64
|
+
const recovered = await this.recoverTipRecord();
|
|
65
|
+
if (recovered !== null) {
|
|
66
|
+
this._tipHash = computeRecordHash(recovered);
|
|
67
|
+
recoveredTip = recovered;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Open for append; create if absent. Mode applies on creation only.
|
|
71
|
+
this.handle = await open(this.path, 'a', this.fileMode);
|
|
72
|
+
// Fire the recovery callback AFTER the handle is open so the callback
|
|
73
|
+
// can use append() if it wants to record a session_recovered event.
|
|
74
|
+
if (recoveredTip !== null && this.onTipRecovered) {
|
|
75
|
+
await this.onTipRecovered(recoveredTip);
|
|
76
|
+
}
|
|
77
|
+
})();
|
|
78
|
+
return this.openPromise;
|
|
79
|
+
}
|
|
80
|
+
/** Append a record. Computes hash chain; serializes via internal queue. */
|
|
81
|
+
async append(input) {
|
|
82
|
+
if (this.closed) {
|
|
83
|
+
throw new Error('AuditLogWriter is closed');
|
|
84
|
+
}
|
|
85
|
+
// Serialize via the queue: each append waits on the previous one. We chain
|
|
86
|
+
// the open() into the queue so concurrent first-appends do not race.
|
|
87
|
+
const result = this.queue.then(async () => {
|
|
88
|
+
await this.open();
|
|
89
|
+
return this.writeOne(input);
|
|
90
|
+
});
|
|
91
|
+
// Replace the queue with a swallowed-error version so one failure doesn't
|
|
92
|
+
// poison subsequent appends.
|
|
93
|
+
this.queue = result.catch(() => undefined);
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
/** Flush and close the file handle. Idempotent. */
|
|
97
|
+
async close() {
|
|
98
|
+
if (this.closed)
|
|
99
|
+
return;
|
|
100
|
+
// Final attestation BEFORE flipping `closed`, so we can still append.
|
|
101
|
+
if (this.attestor && this.attestOnClose && this.appendedCount > 0) {
|
|
102
|
+
await this.runAttestation();
|
|
103
|
+
}
|
|
104
|
+
this.closed = true;
|
|
105
|
+
// Drain the queue.
|
|
106
|
+
/* c8 ignore start */
|
|
107
|
+
try {
|
|
108
|
+
await this.queue;
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
// Defensive: queue is always re-wrapped with .catch(() => undefined)
|
|
112
|
+
// in append(), so this catch is structurally unreachable. Kept as
|
|
113
|
+
// belt-and-braces against future refactors.
|
|
114
|
+
}
|
|
115
|
+
/* c8 ignore stop */
|
|
116
|
+
if (this.handle) {
|
|
117
|
+
await this.handle.close();
|
|
118
|
+
this.handle = null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Publish the current chain head to the configured attestor and emit
|
|
123
|
+
* `x_chain_attested` (success) or `x_chain_attestation_failed` (error).
|
|
124
|
+
* Idempotent on no-attestor or in-flight: callers can fire-and-forget.
|
|
125
|
+
*
|
|
126
|
+
* Exposed publicly so consumers can force a flush (e.g., on a
|
|
127
|
+
* manually-triggered checkpoint).
|
|
128
|
+
*/
|
|
129
|
+
async runAttestation() {
|
|
130
|
+
if (!this.attestor || this.attestationInFlight || this.closed)
|
|
131
|
+
return;
|
|
132
|
+
this.attestationInFlight = true;
|
|
133
|
+
try {
|
|
134
|
+
// Build the payload from the most-recently-written record's hash. We
|
|
135
|
+
// synthesize a minimal AuditRecord wrapper for payloadFromRecord:
|
|
136
|
+
// only fields it reads are agent_id/session_id/signature, and we
|
|
137
|
+
// already have all three.
|
|
138
|
+
const head = this._tipHash;
|
|
139
|
+
// The last record's signature isn't trivially recoverable without
|
|
140
|
+
// re-reading the file; we publish with `signature: null` and let the
|
|
141
|
+
// verifier cross-check against the chain head only. The chain head is
|
|
142
|
+
// the load-bearing commitment; the signature is an auxiliary check
|
|
143
|
+
// that the verifier can run independently against the local log.
|
|
144
|
+
const synthRecord = {
|
|
145
|
+
agent_id: this.agentId,
|
|
146
|
+
session_id: this.sessionId,
|
|
147
|
+
signature: null,
|
|
148
|
+
};
|
|
149
|
+
const payload = payloadFromRecord(synthRecord, this.appendedCount, head);
|
|
150
|
+
try {
|
|
151
|
+
const receipt = await this.attestor.publish(payload);
|
|
152
|
+
await this.appendInternal({
|
|
153
|
+
kind: 'x_chain_attested',
|
|
154
|
+
status: 'approved',
|
|
155
|
+
initiator: 'system',
|
|
156
|
+
detail: {
|
|
157
|
+
chain_head: head,
|
|
158
|
+
records_in_session: this.appendedCount,
|
|
159
|
+
receipt_id: receipt.receiptId,
|
|
160
|
+
...(receipt.url ? { receipt_url: receipt.url } : {}),
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
await this.appendInternal({
|
|
166
|
+
kind: 'x_chain_attestation_failed',
|
|
167
|
+
status: 'errored',
|
|
168
|
+
initiator: 'system',
|
|
169
|
+
detail: {
|
|
170
|
+
chain_head: head,
|
|
171
|
+
records_in_session: this.appendedCount,
|
|
172
|
+
error: err instanceof Error ? err.message : String(err),
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
finally {
|
|
178
|
+
this.attestationInFlight = false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Internal-only append that bypasses the closed check (used by close() to
|
|
183
|
+
* write the final attestation row) and skips the attestation hook (to
|
|
184
|
+
* avoid recursion when writing attestation outcome rows).
|
|
185
|
+
*/
|
|
186
|
+
async appendInternal(input) {
|
|
187
|
+
const result = this.queue.then(async () => {
|
|
188
|
+
await this.open();
|
|
189
|
+
return this.writeOne(input);
|
|
190
|
+
});
|
|
191
|
+
this.queue = result.catch(() => undefined);
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
// ---- internal --------------------------------------------------------------
|
|
195
|
+
async writeOne(input) {
|
|
196
|
+
/* c8 ignore start */
|
|
197
|
+
if (!this.handle) {
|
|
198
|
+
throw new Error('AuditLogWriter not open');
|
|
199
|
+
}
|
|
200
|
+
/* c8 ignore stop */
|
|
201
|
+
const record = {
|
|
202
|
+
v: SPEC_VERSION,
|
|
203
|
+
event_id: 'evt_' + ulid(),
|
|
204
|
+
ts: new Date().toISOString(),
|
|
205
|
+
agent_id: input.agentId ?? this.agentId,
|
|
206
|
+
session_id: input.sessionId ?? this.sessionId,
|
|
207
|
+
kind: input.kind,
|
|
208
|
+
status: input.status,
|
|
209
|
+
initiator: input.initiator,
|
|
210
|
+
prev_hash: this._tipHash,
|
|
211
|
+
...(input.tool === undefined ? {} : { tool: input.tool }),
|
|
212
|
+
...(input.model === undefined ? {} : { model: input.model }),
|
|
213
|
+
...(input.detail === undefined ? {} : { detail: input.detail }),
|
|
214
|
+
};
|
|
215
|
+
// Sign or write `signature: null` per SPEC §2.6.
|
|
216
|
+
record.signature = null;
|
|
217
|
+
if (this.signWith) {
|
|
218
|
+
record.signature = signRecord(record, this.signWith);
|
|
219
|
+
}
|
|
220
|
+
const line = canonicalJsonStringify(record) + '\n';
|
|
221
|
+
await this.handle.write(line);
|
|
222
|
+
// Best-effort fsync. Errors here are not fatal; the OS will get to it.
|
|
223
|
+
try {
|
|
224
|
+
await this.handle.sync();
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
// Some platforms / filesystems disallow fsync; ignore.
|
|
228
|
+
}
|
|
229
|
+
this._tipHash = computeRecordHash(record);
|
|
230
|
+
this.appendedCount += 1;
|
|
231
|
+
// Fire attestation when we cross an attestEvery boundary. Skip if this
|
|
232
|
+
// append IS itself an attestation outcome row (set by runAttestation).
|
|
233
|
+
if (this.attestor &&
|
|
234
|
+
!this.attestationInFlight &&
|
|
235
|
+
this.appendedCount % this.attestEvery === 0) {
|
|
236
|
+
// Fire-and-forget: failures are recorded as audit rows by
|
|
237
|
+
// runAttestation itself. We don't await here so a slow attestor
|
|
238
|
+
// doesn't back up the writer queue. The internal queue still
|
|
239
|
+
// serializes the audit row writes.
|
|
240
|
+
void this.runAttestation();
|
|
241
|
+
}
|
|
242
|
+
return record;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Read the last non-empty record from the existing log. Returns null when
|
|
246
|
+
* the file is empty or contains only blank lines. Used during open() to
|
|
247
|
+
* seed the hash chain and expose the recovered record to onTipRecovered.
|
|
248
|
+
*/
|
|
249
|
+
async recoverTipRecord() {
|
|
250
|
+
const buf = readFileSync(this.path, 'utf-8');
|
|
251
|
+
if (buf.length === 0)
|
|
252
|
+
return null;
|
|
253
|
+
const lines = buf.split('\n');
|
|
254
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
255
|
+
const line = lines[i];
|
|
256
|
+
if (line === undefined || line.length === 0)
|
|
257
|
+
continue;
|
|
258
|
+
return JSON.parse(line);
|
|
259
|
+
}
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/audit/writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* guardian-baseline — offline behavioral-baseline CLI. SPEC §13 (v0.5.0+).
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* guardian-baseline <jsonl> # build profile(s), write to ~/.flowdot/audit/baselines/<agent>.json
|
|
7
|
+
* guardian-baseline <jsonl> --agent <id> # restrict to one agent_id
|
|
8
|
+
* guardian-baseline <jsonl> --out <path> # custom output path
|
|
9
|
+
* guardian-baseline <jsonl> --check # compare jsonl against existing baseline(s); report deviations
|
|
10
|
+
* guardian-baseline <jsonl> --check --sigma <N> # custom σ threshold (default 3)
|
|
11
|
+
*
|
|
12
|
+
* Exit codes:
|
|
13
|
+
* 0 — success (profile written, or --check found zero deviations)
|
|
14
|
+
* 1 — IO error / bad JSONL / --check found deviations
|
|
15
|
+
* 2 — usage error (bad args)
|
|
16
|
+
*
|
|
17
|
+
* NOT A RUNTIME TRIPWIRE. Output is for operator review. The supervisor
|
|
18
|
+
* never consults baselines in the hot path.
|
|
19
|
+
*/
|
|
20
|
+
import { type DeviationReport } from '../audit/stats.js';
|
|
21
|
+
export interface BaselineArgs {
|
|
22
|
+
path: string | undefined;
|
|
23
|
+
agent: string | undefined;
|
|
24
|
+
out: string | undefined;
|
|
25
|
+
check: boolean;
|
|
26
|
+
sigma: number;
|
|
27
|
+
}
|
|
28
|
+
/** Parse argv. Returns the parsed args or null on usage error. */
|
|
29
|
+
export declare function parseArgs(argv: readonly string[]): BaselineArgs | null;
|
|
30
|
+
/** Default baselines directory: `~/.flowdot/audit/baselines/`. */
|
|
31
|
+
export declare function defaultBaselinesDir(): string;
|
|
32
|
+
export interface BaselineRunResult {
|
|
33
|
+
exitCode: 0 | 1 | 2;
|
|
34
|
+
message: string;
|
|
35
|
+
profilesWritten: string[];
|
|
36
|
+
reports: DeviationReport[];
|
|
37
|
+
}
|
|
38
|
+
/** Programmatic entry point — useful for tests and library consumers. */
|
|
39
|
+
export declare function runBaseline(args: BaselineArgs): Promise<BaselineRunResult>;
|
|
40
|
+
/** Render a deviation report as human-readable text. */
|
|
41
|
+
export declare function formatReport(report: DeviationReport): string;
|
|
42
|
+
//# sourceMappingURL=guardian-baseline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guardian-baseline.d.ts","sourceRoot":"","sources":["../../src/cli/guardian-baseline.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;GAiBG;AAOH,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,kEAAkE;AAClE,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,YAAY,GAAG,IAAI,CAoCtE;AAED,kEAAkE;AAClE,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AASD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B;AAyBD,yEAAyE;AACzE,wBAAsB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA2GhF;AAED,wDAAwD;AACxD,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAU5D"}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* guardian-baseline — offline behavioral-baseline CLI. SPEC §13 (v0.5.0+).
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* guardian-baseline <jsonl> # build profile(s), write to ~/.flowdot/audit/baselines/<agent>.json
|
|
7
|
+
* guardian-baseline <jsonl> --agent <id> # restrict to one agent_id
|
|
8
|
+
* guardian-baseline <jsonl> --out <path> # custom output path
|
|
9
|
+
* guardian-baseline <jsonl> --check # compare jsonl against existing baseline(s); report deviations
|
|
10
|
+
* guardian-baseline <jsonl> --check --sigma <N> # custom σ threshold (default 3)
|
|
11
|
+
*
|
|
12
|
+
* Exit codes:
|
|
13
|
+
* 0 — success (profile written, or --check found zero deviations)
|
|
14
|
+
* 1 — IO error / bad JSONL / --check found deviations
|
|
15
|
+
* 2 — usage error (bad args)
|
|
16
|
+
*
|
|
17
|
+
* NOT A RUNTIME TRIPWIRE. Output is for operator review. The supervisor
|
|
18
|
+
* never consults baselines in the hot path.
|
|
19
|
+
*/
|
|
20
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
21
|
+
import { homedir } from 'node:os';
|
|
22
|
+
import { dirname, join } from 'node:path';
|
|
23
|
+
import { AuditLogReader } from '../audit/reader.js';
|
|
24
|
+
import { analyzeMultiAgent, compareToBaseline, } from '../audit/stats.js';
|
|
25
|
+
/** Parse argv. Returns the parsed args or null on usage error. */
|
|
26
|
+
export function parseArgs(argv) {
|
|
27
|
+
const args = argv.slice();
|
|
28
|
+
let path;
|
|
29
|
+
let agent;
|
|
30
|
+
let out;
|
|
31
|
+
let check = false;
|
|
32
|
+
let sigma = 3;
|
|
33
|
+
while (args.length > 0) {
|
|
34
|
+
const a = args.shift();
|
|
35
|
+
/* c8 ignore next */
|
|
36
|
+
if (a === undefined)
|
|
37
|
+
break;
|
|
38
|
+
if (a === '--agent') {
|
|
39
|
+
agent = args.shift();
|
|
40
|
+
if (agent === undefined)
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
else if (a === '--out') {
|
|
44
|
+
out = args.shift();
|
|
45
|
+
if (out === undefined)
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
else if (a === '--check') {
|
|
49
|
+
check = true;
|
|
50
|
+
}
|
|
51
|
+
else if (a === '--sigma') {
|
|
52
|
+
const v = args.shift();
|
|
53
|
+
if (v === undefined)
|
|
54
|
+
return null;
|
|
55
|
+
const n = Number(v);
|
|
56
|
+
if (!Number.isFinite(n) || n <= 0)
|
|
57
|
+
return null;
|
|
58
|
+
sigma = n;
|
|
59
|
+
}
|
|
60
|
+
else if (a.startsWith('--')) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
else if (path === undefined) {
|
|
64
|
+
path = a;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (path === undefined)
|
|
71
|
+
return null;
|
|
72
|
+
return { path, agent, out, check, sigma };
|
|
73
|
+
}
|
|
74
|
+
/** Default baselines directory: `~/.flowdot/audit/baselines/`. */
|
|
75
|
+
export function defaultBaselinesDir() {
|
|
76
|
+
return process.env.FLOWDOT_BASELINES_DIR ?? join(homedir(), '.flowdot', 'audit', 'baselines');
|
|
77
|
+
}
|
|
78
|
+
function baselinePath(agentId, baselinesDir) {
|
|
79
|
+
// ASCII-safe filename derived from agent_id. agent_id is already
|
|
80
|
+
// expected to be short + ASCII per SPEC; we sanitize defensively.
|
|
81
|
+
const safe = agentId.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
82
|
+
return join(baselinesDir, `${safe}.json`);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Read an audit JSONL file and return one record per non-empty line.
|
|
86
|
+
* Caller is responsible for filtering by agent_id.
|
|
87
|
+
*/
|
|
88
|
+
async function loadRecords(path) {
|
|
89
|
+
const reader = await AuditLogReader.open(path);
|
|
90
|
+
try {
|
|
91
|
+
return await readAll(reader);
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
await reader.close();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async function readAll(reader) {
|
|
98
|
+
const out = [];
|
|
99
|
+
for await (const r of reader.records())
|
|
100
|
+
out.push(r);
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
/** Programmatic entry point — useful for tests and library consumers. */
|
|
104
|
+
export async function runBaseline(args) {
|
|
105
|
+
if (!args.path) {
|
|
106
|
+
return { exitCode: 2, message: 'missing path', profilesWritten: [], reports: [] };
|
|
107
|
+
}
|
|
108
|
+
if (!existsSync(args.path)) {
|
|
109
|
+
return {
|
|
110
|
+
exitCode: 1,
|
|
111
|
+
message: `audit file not found: ${args.path}`,
|
|
112
|
+
profilesWritten: [],
|
|
113
|
+
reports: [],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
let records;
|
|
117
|
+
try {
|
|
118
|
+
records = await loadRecords(args.path);
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
return {
|
|
122
|
+
exitCode: 1,
|
|
123
|
+
/* c8 ignore next */
|
|
124
|
+
message: `failed to read audit file: ${err instanceof Error ? err.message : String(err)}`,
|
|
125
|
+
profilesWritten: [],
|
|
126
|
+
reports: [],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
const profiles = analyzeMultiAgent(records);
|
|
130
|
+
const filteredProfiles = args.agent
|
|
131
|
+
? new Map([...profiles].filter(([id]) => id === args.agent))
|
|
132
|
+
: profiles;
|
|
133
|
+
if (filteredProfiles.size === 0) {
|
|
134
|
+
return {
|
|
135
|
+
exitCode: 1,
|
|
136
|
+
message: args.agent
|
|
137
|
+
? `no records for agent_id ${JSON.stringify(args.agent)}`
|
|
138
|
+
: 'no records found in audit file',
|
|
139
|
+
profilesWritten: [],
|
|
140
|
+
reports: [],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
const baselinesDir = args.out ? dirname(args.out) : defaultBaselinesDir();
|
|
144
|
+
// --check path: compare each candidate profile against the existing baseline.
|
|
145
|
+
if (args.check) {
|
|
146
|
+
const reports = [];
|
|
147
|
+
for (const [agentId, profile] of filteredProfiles) {
|
|
148
|
+
const baseFile = args.out ?? baselinePath(agentId, baselinesDir);
|
|
149
|
+
if (!existsSync(baseFile)) {
|
|
150
|
+
return {
|
|
151
|
+
exitCode: 1,
|
|
152
|
+
message: `no baseline for ${agentId} at ${baseFile} — run without --check first to produce one`,
|
|
153
|
+
profilesWritten: [],
|
|
154
|
+
reports,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
let baseline;
|
|
158
|
+
try {
|
|
159
|
+
baseline = JSON.parse(readFileSync(baseFile, 'utf-8'));
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
return {
|
|
163
|
+
exitCode: 1,
|
|
164
|
+
/* c8 ignore next */
|
|
165
|
+
message: `failed to read baseline ${baseFile}: ${err instanceof Error ? err.message : String(err)}`,
|
|
166
|
+
profilesWritten: [],
|
|
167
|
+
reports,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
reports.push(compareToBaseline(profile, baseline, { sigmaThreshold: args.sigma }));
|
|
171
|
+
}
|
|
172
|
+
const totalDeviations = reports.reduce((s, r) => s + r.deviations.length, 0);
|
|
173
|
+
return {
|
|
174
|
+
exitCode: totalDeviations === 0 ? 0 : 1,
|
|
175
|
+
message: totalDeviations === 0
|
|
176
|
+
? `OK: ${reports.length} agent(s) checked, no deviations at σ=${args.sigma}`
|
|
177
|
+
: `${totalDeviations} deviation(s) across ${reports.length} agent(s) at σ=${args.sigma}`,
|
|
178
|
+
profilesWritten: [],
|
|
179
|
+
reports,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
// Write path: persist profiles to disk.
|
|
183
|
+
if (args.out && filteredProfiles.size > 1) {
|
|
184
|
+
return {
|
|
185
|
+
exitCode: 2,
|
|
186
|
+
message: '--out requires --agent when the file contains multiple agent_ids',
|
|
187
|
+
profilesWritten: [],
|
|
188
|
+
reports: [],
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
if (!existsSync(baselinesDir)) {
|
|
192
|
+
mkdirSync(baselinesDir, { recursive: true, mode: 0o700 });
|
|
193
|
+
}
|
|
194
|
+
const written = [];
|
|
195
|
+
for (const [agentId, profile] of filteredProfiles) {
|
|
196
|
+
const file = args.out ?? baselinePath(agentId, baselinesDir);
|
|
197
|
+
writeFileSync(file, JSON.stringify(profile, null, 2) + '\n', { mode: 0o600 });
|
|
198
|
+
written.push(file);
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
exitCode: 0,
|
|
202
|
+
message: `wrote ${written.length} baseline(s)`,
|
|
203
|
+
profilesWritten: written,
|
|
204
|
+
reports: [],
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
/** Render a deviation report as human-readable text. */
|
|
208
|
+
export function formatReport(report) {
|
|
209
|
+
if (report.deviations.length === 0) {
|
|
210
|
+
return `[${report.agent_id}] no deviations.`;
|
|
211
|
+
}
|
|
212
|
+
const lines = [`[${report.agent_id}] ${report.deviations.length} deviation(s):`];
|
|
213
|
+
for (const d of report.deviations) {
|
|
214
|
+
const sigmaStr = d.sigma === null ? 'σ=n/a' : `σ=${d.sigma.toFixed(2)}`;
|
|
215
|
+
lines.push(` - ${d.metric}: observed=${d.observed}, baseline=${d.baseline}, ${sigmaStr} — ${d.note}`);
|
|
216
|
+
}
|
|
217
|
+
return lines.join('\n');
|
|
218
|
+
}
|
|
219
|
+
const USAGE = `Usage:
|
|
220
|
+
guardian-baseline <jsonl> # build profile(s)
|
|
221
|
+
guardian-baseline <jsonl> --agent <id> # restrict to one agent_id
|
|
222
|
+
guardian-baseline <jsonl> --out <path> # custom output path
|
|
223
|
+
guardian-baseline <jsonl> --check # compare against existing baseline(s)
|
|
224
|
+
guardian-baseline <jsonl> --check --sigma <N> # custom σ threshold (default 3)
|
|
225
|
+
|
|
226
|
+
Exit codes:
|
|
227
|
+
0 — success (profile written, or --check found zero deviations)
|
|
228
|
+
1 — IO error / bad JSONL / --check found deviations
|
|
229
|
+
2 — usage error
|
|
230
|
+
`;
|
|
231
|
+
/* c8 ignore start */
|
|
232
|
+
async function main() {
|
|
233
|
+
const parsed = parseArgs(process.argv.slice(2));
|
|
234
|
+
if (!parsed) {
|
|
235
|
+
process.stderr.write(USAGE);
|
|
236
|
+
process.exit(2);
|
|
237
|
+
}
|
|
238
|
+
const result = await runBaseline(parsed);
|
|
239
|
+
if (parsed.check) {
|
|
240
|
+
for (const r of result.reports) {
|
|
241
|
+
process.stdout.write(formatReport(r) + '\n');
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
for (const p of result.profilesWritten) {
|
|
246
|
+
process.stdout.write(`wrote ${p}\n`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (result.exitCode !== 0) {
|
|
250
|
+
process.stderr.write(result.message + '\n');
|
|
251
|
+
}
|
|
252
|
+
process.exit(result.exitCode);
|
|
253
|
+
}
|
|
254
|
+
/* c8 ignore stop */
|
|
255
|
+
// Run as CLI when invoked directly (not when imported as a module).
|
|
256
|
+
const isMain = typeof process !== 'undefined' &&
|
|
257
|
+
typeof process.argv !== 'undefined' &&
|
|
258
|
+
process.argv[1] !== undefined &&
|
|
259
|
+
/guardian-baseline(\.js|\.ts)?$/.test(process.argv[1]);
|
|
260
|
+
/* c8 ignore start */
|
|
261
|
+
if (isMain) {
|
|
262
|
+
void main();
|
|
263
|
+
}
|
|
264
|
+
/* c8 ignore stop */
|
|
265
|
+
//# sourceMappingURL=guardian-baseline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guardian-baseline.js","sourceRoot":"","sources":["../../src/cli/guardian-baseline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* guardian-correlator — offline cross-surface correlation CLI. SPEC §14
|
|
4
|
+
* (v0.5.0+).
|
|
5
|
+
*
|
|
6
|
+
* Reads two or more audit JSONL files for the same `agent_id` and reports
|
|
7
|
+
* patterns that span surfaces: overlapping sessions, identical-args
|
|
8
|
+
* collisions, similar tool-frequency sequences. Writes findings as
|
|
9
|
+
* `x_cross_surface_match` JSONL to its own log (NEVER mutates source
|
|
10
|
+
* files).
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* guardian-correlator <file1.jsonl>:<surface1> <file2.jsonl>:<surface2> [...]
|
|
14
|
+
* guardian-correlator <file1>:<surface1> <file2>:<surface2> --out <correlations.jsonl>
|
|
15
|
+
* guardian-correlator <files...> --threshold <0..1> # cosine threshold (default 0.9)
|
|
16
|
+
* guardian-correlator <files...> --window-ms <N> # args-hash window (default 60000)
|
|
17
|
+
*
|
|
18
|
+
* Exit codes:
|
|
19
|
+
* 0 — success (matches written or none found; either way, exit 0)
|
|
20
|
+
* 1 — IO error / bad JSONL
|
|
21
|
+
* 2 — usage error
|
|
22
|
+
*
|
|
23
|
+
* Not a runtime tripwire. Output is for operator review.
|
|
24
|
+
*/
|
|
25
|
+
import { type CorrelationMatch } from '../audit/correlation.js';
|
|
26
|
+
export interface CorrelatorArgs {
|
|
27
|
+
/** Tuples of (path, surface-name). */
|
|
28
|
+
sources: {
|
|
29
|
+
path: string;
|
|
30
|
+
surface: string;
|
|
31
|
+
}[];
|
|
32
|
+
out: string | undefined;
|
|
33
|
+
threshold: number;
|
|
34
|
+
argsHashWindowMs: number;
|
|
35
|
+
similarityWindowMs: number;
|
|
36
|
+
similarityMinCalls: number;
|
|
37
|
+
}
|
|
38
|
+
export declare function parseArgs(argv: readonly string[]): CorrelatorArgs | null;
|
|
39
|
+
export declare function defaultCorrelationsPath(): string;
|
|
40
|
+
export interface CorrelatorRunResult {
|
|
41
|
+
exitCode: 0 | 1 | 2;
|
|
42
|
+
message: string;
|
|
43
|
+
matches: CorrelationMatch[];
|
|
44
|
+
outPath: string | undefined;
|
|
45
|
+
}
|
|
46
|
+
export declare function runCorrelator(args: CorrelatorArgs): Promise<CorrelatorRunResult>;
|
|
47
|
+
//# sourceMappingURL=guardian-correlator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guardian-correlator.d.ts","sourceRoot":"","sources":["../../src/cli/guardian-correlator.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAOH,OAAO,EAGL,KAAK,gBAAgB,EAEtB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC7C,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc,GAAG,IAAI,CA4DxE;AAED,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAaD,wBAAsB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAyDtF"}
|