monora-ai 1.0.0 → 1.0.1
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/README.md +109 -39
- package/dist/alerts.d.ts +40 -0
- package/dist/alerts.d.ts.map +1 -0
- package/dist/alerts.js +140 -0
- package/dist/attestation.d.ts +20 -0
- package/dist/attestation.d.ts.map +1 -0
- package/dist/attestation.js +160 -0
- package/dist/cli/diagnostics.d.ts +17 -0
- package/dist/cli/diagnostics.d.ts.map +1 -0
- package/dist/cli/diagnostics.js +278 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +442 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +71 -3
- package/dist/data_handling.d.ts +49 -0
- package/dist/data_handling.d.ts.map +1 -0
- package/dist/data_handling.js +192 -0
- package/dist/dispatcher.d.ts +4 -0
- package/dist/dispatcher.d.ts.map +1 -1
- package/dist/dispatcher.js +111 -5
- package/dist/hasher.d.ts +2 -0
- package/dist/hasher.d.ts.map +1 -1
- package/dist/hasher.js +18 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -1
- package/dist/instrumentation.d.ts +22 -0
- package/dist/instrumentation.d.ts.map +1 -0
- package/dist/instrumentation.js +88 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +20 -1
- package/dist/report.d.ts +9 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +267 -0
- package/dist/runtime.d.ts +37 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +561 -0
- package/dist/security_report.d.ts +17 -0
- package/dist/security_report.d.ts.map +1 -0
- package/dist/security_report.js +313 -0
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -21,27 +21,89 @@ npm install monora
|
|
|
21
21
|
## Quick Start
|
|
22
22
|
|
|
23
23
|
```typescript
|
|
24
|
-
import {
|
|
24
|
+
import { init, llmCall, trace } from 'monora';
|
|
25
25
|
|
|
26
|
-
//
|
|
27
|
-
|
|
26
|
+
// Initialize SDK
|
|
27
|
+
init({ configPath: './monora.yml' });
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
console.error('Policy violation:', violation.message);
|
|
36
|
-
}
|
|
29
|
+
const ask = llmCall({ purpose: 'support' })(function ask(
|
|
30
|
+
question: string,
|
|
31
|
+
model: string = 'gpt-4o-mini'
|
|
32
|
+
) {
|
|
33
|
+
return { choices: [{ message: { content: 'ok' } }] };
|
|
34
|
+
});
|
|
37
35
|
|
|
38
36
|
// Create a trace
|
|
39
37
|
trace('my-ai-task', (span) => {
|
|
40
38
|
console.log('Trace ID:', span.traceId);
|
|
41
|
-
|
|
39
|
+
ask('hello');
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Guided Setup (Wizard)
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
```bash
|
|
46
|
+
npx monora-ai init
|
|
47
|
+
# or
|
|
48
|
+
./node_modules/.bin/monora init
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This generates a `monora.yml` you can load with `loadConfig({ configPath: './monora.yml' })`.
|
|
52
|
+
|
|
53
|
+
### Reports & Security Review
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx monora-ai report --input events.jsonl --output report.json
|
|
57
|
+
npx monora-ai report --input events.jsonl --output report.md --format markdown
|
|
58
|
+
|
|
59
|
+
npx monora-ai security-review --input events.jsonl --output security.json
|
|
60
|
+
npx monora-ai security-review --input events.jsonl --output security.json --sign gpg --gpg-key "you@example.com"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Data Handling + Alerts
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { DataHandlingEngine, buildDataViolation, ViolationWebhookDispatcher } from 'monora';
|
|
67
|
+
|
|
68
|
+
const dataHandling = new DataHandlingEngine({
|
|
69
|
+
enabled: true,
|
|
70
|
+
mode: 'redact',
|
|
71
|
+
rules: [
|
|
72
|
+
{ name: 'email', pattern: '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}' }
|
|
73
|
+
]
|
|
44
74
|
});
|
|
75
|
+
|
|
76
|
+
const payload = { message: 'Contact me at person@example.com' };
|
|
77
|
+
const { value, applied } = dataHandling.sanitizePayload('request', payload, 'confidential');
|
|
78
|
+
|
|
79
|
+
const dispatcher = new ViolationWebhookDispatcher({
|
|
80
|
+
endpoint: 'https://hooks.example.com/monora',
|
|
81
|
+
headers: { Authorization: 'Bearer TOKEN' }
|
|
82
|
+
});
|
|
83
|
+
dispatcher.start();
|
|
84
|
+
dispatcher.send({ event_type: 'policy_violation', message: 'Example violation' });
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### High-level Runtime Helpers
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { init, logEvent, toolCall, agentStep, setViolationHandler } from 'monora';
|
|
91
|
+
|
|
92
|
+
init({ configPath: './monora.yml' });
|
|
93
|
+
|
|
94
|
+
setViolationHandler((violation) => {
|
|
95
|
+
console.error('Violation:', violation.message);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const fetchTool = toolCall({ toolName: 'fetch', purpose: 'integration' })(async (url: string) => {
|
|
99
|
+
return { ok: true, url };
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const plan = agentStep({ agentName: 'planner', stepType: 'planning', purpose: 'analysis' })(
|
|
103
|
+
(goal: string) => [`step for ${goal}`]
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
logEvent('custom', { message: 'hello' }, { purpose: 'manual' });
|
|
45
107
|
```
|
|
46
108
|
|
|
47
109
|
## Configuration
|
|
@@ -144,46 +206,50 @@ const gaps = detectSequenceGaps(events);
|
|
|
144
206
|
console.log('Sequence gaps:', gaps);
|
|
145
207
|
```
|
|
146
208
|
|
|
147
|
-
### Security Reports
|
|
209
|
+
### Security Reports
|
|
148
210
|
|
|
149
|
-
|
|
211
|
+
Generate JSON security review reports locally with CLI:
|
|
150
212
|
|
|
151
|
-
|
|
152
|
-
- **Auth**: `Authorization: Bearer $MONORA_API_KEY`
|
|
153
|
-
- **Request**:
|
|
154
|
-
- `events`: array of Monora events
|
|
155
|
-
- `config` (optional): policies/registry overrides
|
|
156
|
-
- **Response**: `{ overall_risk_level, risk_factors, operational_metrics, ... }`
|
|
157
|
-
- **Errors**: `401` unauthorized, `400` invalid payload, `404` endpoint unavailable
|
|
213
|
+
Auth: none (local CLI). Errors: invalid JSONL/config or GPG signing failures.
|
|
158
214
|
|
|
159
215
|
```bash
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
-H "Content-Type: application/json" \
|
|
163
|
-
-d '{"events": [{"event_type": "llm_call"}], "config": {"policies": {}}}'
|
|
216
|
+
npx monora-ai security-review --input events.jsonl --output security.json
|
|
217
|
+
npx monora-ai security-review --input events.jsonl --output security.json --config monora.yml
|
|
164
218
|
```
|
|
165
219
|
|
|
166
|
-
### Data
|
|
220
|
+
### Data Handling
|
|
167
221
|
|
|
168
|
-
|
|
222
|
+
Use the data handling engine for redaction or blocking decisions (modes: `redact`, `block`, `allow`):
|
|
169
223
|
|
|
170
|
-
|
|
171
|
-
- **Auth**: none for local processing
|
|
172
|
-
- **Errors**: `DataHandlingViolation` (block mode), invalid regex patterns
|
|
224
|
+
Auth: none. Errors: `DataHandlingViolation` in block mode or invalid regex patterns.
|
|
173
225
|
|
|
174
226
|
```typescript
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
227
|
+
import { DataHandlingEngine } from 'monora';
|
|
228
|
+
|
|
229
|
+
const engine = new DataHandlingEngine({
|
|
230
|
+
enabled: true,
|
|
231
|
+
mode: 'redact',
|
|
232
|
+
rules: [{ name: 'email', pattern: '[^@]+@[^@]+\\.[^@]+' }]
|
|
233
|
+
});
|
|
234
|
+
const { value, applied } = engine.sanitizePayload('request', payload, 'confidential');
|
|
178
235
|
```
|
|
179
236
|
|
|
180
|
-
### Webhook Alerts
|
|
237
|
+
### Webhook Alerts
|
|
181
238
|
|
|
182
|
-
|
|
239
|
+
Send policy violation payloads to a webhook:
|
|
183
240
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
241
|
+
Auth: set headers such as `Authorization`. Errors: network failures, non-2xx responses, or queue overflow.
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
import { ViolationWebhookDispatcher } from 'monora';
|
|
245
|
+
|
|
246
|
+
const dispatcher = new ViolationWebhookDispatcher({
|
|
247
|
+
endpoint: 'https://hooks.example.com/monora',
|
|
248
|
+
headers: { Authorization: 'Bearer TOKEN' }
|
|
249
|
+
});
|
|
250
|
+
dispatcher.start();
|
|
251
|
+
dispatcher.send({ event_type: 'policy_violation', message: 'Blocked model' });
|
|
252
|
+
```
|
|
187
253
|
|
|
188
254
|
```json
|
|
189
255
|
{
|
|
@@ -196,6 +262,8 @@ Planned configuration (see roadmap: https://github.com/monora/monora/issues).
|
|
|
196
262
|
|
|
197
263
|
### Event Building and Dispatching
|
|
198
264
|
|
|
265
|
+
Event builder and dispatcher classes are available in the current Node SDK.
|
|
266
|
+
|
|
199
267
|
```typescript
|
|
200
268
|
import { EventBuilder, EventDispatcher, StdoutSink, FileSink } from 'monora';
|
|
201
269
|
|
|
@@ -233,6 +301,8 @@ dispatcher.close();
|
|
|
233
301
|
|
|
234
302
|
### Sink Options
|
|
235
303
|
|
|
304
|
+
These sink implementations are exported and ready for use.
|
|
305
|
+
|
|
236
306
|
```typescript
|
|
237
307
|
// Stdout Sink
|
|
238
308
|
const stdoutSink = new StdoutSink('pretty'); // or 'json'
|
package/dist/alerts.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Violation alert dispatching.
|
|
3
|
+
*/
|
|
4
|
+
export declare class AlertError extends Error {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
export declare function buildViolationPayload(event: Record<string, any>): Record<string, any>;
|
|
8
|
+
export declare class ViolationWebhookDispatcher {
|
|
9
|
+
private endpoint;
|
|
10
|
+
private headers;
|
|
11
|
+
private timeoutSec;
|
|
12
|
+
private retries;
|
|
13
|
+
private backoffBaseSec;
|
|
14
|
+
private queue;
|
|
15
|
+
private queueSize;
|
|
16
|
+
private failureMode;
|
|
17
|
+
private queueFullMode;
|
|
18
|
+
private timer?;
|
|
19
|
+
private fatalError?;
|
|
20
|
+
private inFlight;
|
|
21
|
+
constructor(options: {
|
|
22
|
+
endpoint: string;
|
|
23
|
+
headers: Record<string, string>;
|
|
24
|
+
timeoutSec?: number;
|
|
25
|
+
retryAttempts?: number;
|
|
26
|
+
backoffBaseSec?: number;
|
|
27
|
+
queueSize?: number;
|
|
28
|
+
failureMode?: 'warn' | 'raise' | 'ignore';
|
|
29
|
+
queueFullMode?: 'warn' | 'raise' | 'ignore';
|
|
30
|
+
});
|
|
31
|
+
start(): void;
|
|
32
|
+
send(payload: Record<string, any>): void;
|
|
33
|
+
flush(): void;
|
|
34
|
+
close(): void;
|
|
35
|
+
private processQueue;
|
|
36
|
+
private sendPayload;
|
|
37
|
+
private handleQueueFull;
|
|
38
|
+
private handleFailure;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=alerts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alerts.d.ts","sourceRoot":"","sources":["../src/alerts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAiBrF;AAED,qBAAa,0BAA0B;IACrC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,KAAK,CAAC,CAAiB;IAC/B,OAAO,CAAC,UAAU,CAAC,CAAQ;IAC3B,OAAO,CAAC,QAAQ,CAAU;gBAEd,OAAO,EAAE;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;QAC1C,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;KAC7C;IAaD,KAAK,IAAI,IAAI;IASb,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAWxC,KAAK,IAAI,IAAI;IAIb,KAAK,IAAI,IAAI;YAQC,YAAY;YAqBZ,WAAW;IAmBzB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,aAAa;CAStB"}
|
package/dist/alerts.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Violation alert dispatching.
|
|
4
|
+
*/
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.ViolationWebhookDispatcher = exports.AlertError = void 0;
|
|
10
|
+
exports.buildViolationPayload = buildViolationPayload;
|
|
11
|
+
const axios_1 = __importDefault(require("axios"));
|
|
12
|
+
class AlertError extends Error {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'AlertError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.AlertError = AlertError;
|
|
19
|
+
function buildViolationPayload(event) {
|
|
20
|
+
const body = event.body || {};
|
|
21
|
+
return {
|
|
22
|
+
event_type: 'policy_violation',
|
|
23
|
+
policy_event_type: event.event_type,
|
|
24
|
+
model: body.model,
|
|
25
|
+
policy_name: body.policy_name,
|
|
26
|
+
message: body.message,
|
|
27
|
+
timestamp: event.timestamp,
|
|
28
|
+
data_classification: event.data_classification,
|
|
29
|
+
rule_names: body.rule_names,
|
|
30
|
+
trace_id: event.trace_id,
|
|
31
|
+
span_id: event.span_id,
|
|
32
|
+
parent_span_id: event.parent_span_id,
|
|
33
|
+
service_name: event.service_name,
|
|
34
|
+
environment: event.environment,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
class ViolationWebhookDispatcher {
|
|
38
|
+
constructor(options) {
|
|
39
|
+
this.endpoint = options.endpoint;
|
|
40
|
+
this.headers = options.headers || {};
|
|
41
|
+
this.timeoutSec = options.timeoutSec ?? 5.0;
|
|
42
|
+
this.retries = options.retryAttempts ?? 3;
|
|
43
|
+
this.backoffBaseSec = options.backoffBaseSec ?? 0.5;
|
|
44
|
+
this.queue = [];
|
|
45
|
+
this.queueSize = options.queueSize ?? 200;
|
|
46
|
+
this.failureMode = options.failureMode ?? 'warn';
|
|
47
|
+
this.queueFullMode = options.queueFullMode ?? 'warn';
|
|
48
|
+
this.inFlight = false;
|
|
49
|
+
}
|
|
50
|
+
start() {
|
|
51
|
+
if (this.timer) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
this.timer = setInterval(() => {
|
|
55
|
+
void this.processQueue();
|
|
56
|
+
}, 500);
|
|
57
|
+
}
|
|
58
|
+
send(payload) {
|
|
59
|
+
if (this.fatalError && this.failureMode === 'raise') {
|
|
60
|
+
throw new AlertError('Violation webhook dispatcher failed');
|
|
61
|
+
}
|
|
62
|
+
if (this.queue.length >= this.queueSize) {
|
|
63
|
+
this.handleQueueFull();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this.queue.push(payload);
|
|
67
|
+
}
|
|
68
|
+
flush() {
|
|
69
|
+
void this.processQueue(true);
|
|
70
|
+
}
|
|
71
|
+
close() {
|
|
72
|
+
if (this.timer) {
|
|
73
|
+
clearInterval(this.timer);
|
|
74
|
+
this.timer = undefined;
|
|
75
|
+
}
|
|
76
|
+
this.flush();
|
|
77
|
+
}
|
|
78
|
+
async processQueue(drain = false) {
|
|
79
|
+
if (this.inFlight) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
this.inFlight = true;
|
|
83
|
+
try {
|
|
84
|
+
while (this.queue.length > 0) {
|
|
85
|
+
const payload = this.queue.shift();
|
|
86
|
+
if (!payload) {
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
await this.sendPayload(payload);
|
|
90
|
+
if (!drain && this.queue.length === 0) {
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
this.inFlight = false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async sendPayload(payload) {
|
|
100
|
+
for (let attempt = 0; attempt < this.retries; attempt += 1) {
|
|
101
|
+
try {
|
|
102
|
+
await axios_1.default.post(this.endpoint, payload, {
|
|
103
|
+
headers: this.headers,
|
|
104
|
+
timeout: this.timeoutSec * 1000,
|
|
105
|
+
});
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
if (attempt === this.retries - 1) {
|
|
110
|
+
this.handleFailure(error instanceof Error ? error : new Error(String(error)));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const backoff = this.backoffBaseSec * Math.pow(2, attempt);
|
|
114
|
+
await delay(backoff * 1000);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
handleQueueFull() {
|
|
119
|
+
const message = 'Monora violation webhook queue full; dropping alert';
|
|
120
|
+
if (this.queueFullMode === 'raise') {
|
|
121
|
+
throw new AlertError(message);
|
|
122
|
+
}
|
|
123
|
+
if (this.queueFullMode === 'warn') {
|
|
124
|
+
console.error(message);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
handleFailure(error) {
|
|
128
|
+
if (this.failureMode === 'raise') {
|
|
129
|
+
this.fatalError = error;
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (this.failureMode === 'warn') {
|
|
133
|
+
console.error(`Monora violation webhook failed: ${error}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
exports.ViolationWebhookDispatcher = ViolationWebhookDispatcher;
|
|
138
|
+
function delay(ms) {
|
|
139
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
140
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signed attestation bundle helpers.
|
|
3
|
+
*/
|
|
4
|
+
export declare class AttestationError extends Error {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
export interface SignatureResult {
|
|
8
|
+
signature: string;
|
|
9
|
+
signature_type: string;
|
|
10
|
+
key_id?: string;
|
|
11
|
+
fingerprint?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function serializeReport(report: Record<string, any>): Buffer;
|
|
14
|
+
export declare function computeSha256(payload: Buffer): string;
|
|
15
|
+
export declare function signReportGpg(reportBytes: Buffer, options?: {
|
|
16
|
+
keyId?: string;
|
|
17
|
+
gpgHome?: string;
|
|
18
|
+
}): SignatureResult;
|
|
19
|
+
export declare function buildAttestationBundle(report: Record<string, any>, reportBytes: Buffer, signature: SignatureResult): Record<string, any>;
|
|
20
|
+
//# sourceMappingURL=attestation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attestation.d.ts","sourceRoot":"","sources":["../src/attestation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAEnE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7C,eAAe,CAsDjB;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,eAAe,GACzB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAcrB"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Signed attestation bundle helpers.
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.AttestationError = void 0;
|
|
40
|
+
exports.serializeReport = serializeReport;
|
|
41
|
+
exports.computeSha256 = computeSha256;
|
|
42
|
+
exports.signReportGpg = signReportGpg;
|
|
43
|
+
exports.buildAttestationBundle = buildAttestationBundle;
|
|
44
|
+
const crypto = __importStar(require("crypto"));
|
|
45
|
+
const fs = __importStar(require("fs"));
|
|
46
|
+
const os = __importStar(require("os"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const child_process_1 = require("child_process");
|
|
49
|
+
class AttestationError extends Error {
|
|
50
|
+
constructor(message) {
|
|
51
|
+
super(message);
|
|
52
|
+
this.name = 'AttestationError';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.AttestationError = AttestationError;
|
|
56
|
+
function serializeReport(report) {
|
|
57
|
+
return Buffer.from(JSON.stringify(report, null, 2), 'utf-8');
|
|
58
|
+
}
|
|
59
|
+
function computeSha256(payload) {
|
|
60
|
+
const digest = crypto.createHash('sha256').update(payload).digest('hex');
|
|
61
|
+
return `sha256:${digest}`;
|
|
62
|
+
}
|
|
63
|
+
function signReportGpg(reportBytes, options) {
|
|
64
|
+
const gpg = findGpg();
|
|
65
|
+
if (!gpg) {
|
|
66
|
+
throw new AttestationError('gpg not found on PATH');
|
|
67
|
+
}
|
|
68
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'monora-sign-'));
|
|
69
|
+
const reportPath = path.join(tmpDir, 'report.json');
|
|
70
|
+
const sigPath = path.join(tmpDir, 'report.json.asc');
|
|
71
|
+
try {
|
|
72
|
+
fs.writeFileSync(reportPath, reportBytes);
|
|
73
|
+
const args = ['--armor', '--detach-sign', '--output', sigPath];
|
|
74
|
+
if (options?.gpgHome) {
|
|
75
|
+
args.push('--homedir', options.gpgHome);
|
|
76
|
+
}
|
|
77
|
+
if (options?.keyId) {
|
|
78
|
+
args.push('--local-user', options.keyId);
|
|
79
|
+
}
|
|
80
|
+
args.push(reportPath);
|
|
81
|
+
const result = (0, child_process_1.spawnSync)(gpg, args, { encoding: 'utf-8' });
|
|
82
|
+
if (result.status !== 0) {
|
|
83
|
+
throw new AttestationError(result.stderr || 'gpg signing failed');
|
|
84
|
+
}
|
|
85
|
+
const signature = fs.readFileSync(sigPath, 'utf-8');
|
|
86
|
+
const fingerprint = options?.keyId
|
|
87
|
+
? getGpgFingerprint(gpg, options.keyId, options.gpgHome)
|
|
88
|
+
: undefined;
|
|
89
|
+
return {
|
|
90
|
+
signature,
|
|
91
|
+
signature_type: 'gpg',
|
|
92
|
+
key_id: options?.keyId,
|
|
93
|
+
fingerprint,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
try {
|
|
98
|
+
fs.unlinkSync(sigPath);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// ignore cleanup errors
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
fs.unlinkSync(reportPath);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// ignore cleanup errors
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// ignore cleanup errors
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function buildAttestationBundle(report, reportBytes, signature) {
|
|
118
|
+
return {
|
|
119
|
+
bundle_version: '1.0.0',
|
|
120
|
+
generated_at: new Date().toISOString(),
|
|
121
|
+
report_sha256: computeSha256(reportBytes),
|
|
122
|
+
report_json: reportBytes.toString('utf-8'),
|
|
123
|
+
signature: {
|
|
124
|
+
type: signature.signature_type,
|
|
125
|
+
value: signature.signature,
|
|
126
|
+
key_id: signature.key_id,
|
|
127
|
+
fingerprint: signature.fingerprint,
|
|
128
|
+
signed_at: new Date().toISOString(),
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function findGpg() {
|
|
133
|
+
const candidates = ['gpg', 'gpg2'];
|
|
134
|
+
for (const candidate of candidates) {
|
|
135
|
+
const result = (0, child_process_1.spawnSync)(candidate, ['--version'], { encoding: 'utf-8' });
|
|
136
|
+
if (result.status === 0) {
|
|
137
|
+
return candidate;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
function getGpgFingerprint(gpg, keyId, gpgHome) {
|
|
143
|
+
const args = ['--with-colons', '--fingerprint', keyId];
|
|
144
|
+
if (gpgHome) {
|
|
145
|
+
args.unshift('--homedir', gpgHome);
|
|
146
|
+
}
|
|
147
|
+
const result = (0, child_process_1.spawnSync)(gpg, args, { encoding: 'utf-8' });
|
|
148
|
+
if (result.status !== 0) {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
const lines = result.stdout.split(/\r?\n/);
|
|
152
|
+
for (const line of lines) {
|
|
153
|
+
if (!line.startsWith('fpr:')) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const parts = line.split(':').filter(Boolean);
|
|
157
|
+
return parts[parts.length - 1];
|
|
158
|
+
}
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration diagnostics and validation.
|
|
3
|
+
*/
|
|
4
|
+
import { MonoraConfig } from '../config';
|
|
5
|
+
interface ValidationResult {
|
|
6
|
+
errors: string[];
|
|
7
|
+
warnings: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function validateConfig(config: MonoraConfig): ValidationResult;
|
|
10
|
+
export declare function doctorChecks(config: MonoraConfig, options?: {
|
|
11
|
+
checkNetwork?: boolean;
|
|
12
|
+
}): ValidationResult;
|
|
13
|
+
export declare function emitResults(results: ValidationResult, options?: {
|
|
14
|
+
json?: boolean;
|
|
15
|
+
}): number;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=diagnostics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../src/cli/diagnostics.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAc,YAAY,EAAE,MAAM,WAAW,CAAC;AAOrD,UAAU,gBAAgB;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,gBAAgB,CAuIrE;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GACnC,gBAAgB,CAqDlB;AA+CD,wBAAgB,WAAW,CACzB,OAAO,EAAE,gBAAgB,EACzB,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAC3B,MAAM,CA2BR"}
|