@maykonpaulo/maestro-core 0.3.0-next.0 → 0.3.0-next.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/dist/index.d.ts +281 -2
- package/dist/index.js +330 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -70,6 +70,52 @@ var ConsoleLogger = class {
|
|
|
70
70
|
}
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
+
// src/logging/ConsoleStructuredLogger.ts
|
|
74
|
+
var ConsoleStructuredLogger = class {
|
|
75
|
+
constructor(minLevel = "info") {
|
|
76
|
+
this.minLevel = minLevel;
|
|
77
|
+
}
|
|
78
|
+
minLevel;
|
|
79
|
+
debug(entry) {
|
|
80
|
+
this.log("debug", entry);
|
|
81
|
+
}
|
|
82
|
+
info(entry) {
|
|
83
|
+
this.log("info", entry);
|
|
84
|
+
}
|
|
85
|
+
warn(entry) {
|
|
86
|
+
this.log("warn", entry);
|
|
87
|
+
}
|
|
88
|
+
error(entry) {
|
|
89
|
+
this.log("error", entry);
|
|
90
|
+
}
|
|
91
|
+
log(level, entry) {
|
|
92
|
+
if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[this.minLevel]) return;
|
|
93
|
+
const output = {
|
|
94
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
95
|
+
level
|
|
96
|
+
};
|
|
97
|
+
if (entry.correlationId !== void 0) output["correlationId"] = entry.correlationId;
|
|
98
|
+
if (entry.operation !== void 0) output["operation"] = entry.operation;
|
|
99
|
+
if (entry.entity !== void 0) output["entity"] = entry.entity;
|
|
100
|
+
if (entry.entityId !== void 0) output["entityId"] = entry.entityId;
|
|
101
|
+
if (entry.actor !== void 0) output["actor"] = entry.actor;
|
|
102
|
+
if (entry.durationMs !== void 0) output["durationMs"] = entry.durationMs;
|
|
103
|
+
if (entry.status !== void 0) output["status"] = entry.status;
|
|
104
|
+
if (entry.severity !== void 0) output["severity"] = entry.severity;
|
|
105
|
+
if (entry.message !== void 0) output["message"] = entry.message;
|
|
106
|
+
if (entry.metadata !== void 0) output["metadata"] = entry.metadata;
|
|
107
|
+
if (entry.error !== void 0) output["error"] = this.serializeError(entry.error);
|
|
108
|
+
const consoleFn = level === "error" ? console.error : level === "warn" ? console.warn : level === "debug" ? console.debug : console.info;
|
|
109
|
+
consoleFn(JSON.stringify(output));
|
|
110
|
+
}
|
|
111
|
+
serializeError(error) {
|
|
112
|
+
if (error instanceof Error) {
|
|
113
|
+
return { name: error.name, message: error.message };
|
|
114
|
+
}
|
|
115
|
+
return error;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
73
119
|
// src/audit/InMemoryAuditRepository.ts
|
|
74
120
|
var InMemoryAuditRepository = class {
|
|
75
121
|
store = /* @__PURE__ */ new Map();
|
|
@@ -85,6 +131,12 @@ var InMemoryAuditRepository = class {
|
|
|
85
131
|
if (filter.action !== void 0) {
|
|
86
132
|
events = events.filter((e) => e.action === filter.action);
|
|
87
133
|
}
|
|
134
|
+
if (filter.entity !== void 0) {
|
|
135
|
+
events = events.filter((e) => e.entity === filter.entity);
|
|
136
|
+
}
|
|
137
|
+
if (filter.entityId !== void 0) {
|
|
138
|
+
events = events.filter((e) => e.entityId === filter.entityId);
|
|
139
|
+
}
|
|
88
140
|
if (filter.resourceType !== void 0) {
|
|
89
141
|
events = events.filter((e) => e.resource?.type === filter.resourceType);
|
|
90
142
|
}
|
|
@@ -107,6 +159,9 @@ var InMemoryAuditRepository = class {
|
|
|
107
159
|
}
|
|
108
160
|
return events;
|
|
109
161
|
}
|
|
162
|
+
async query(filter) {
|
|
163
|
+
return this.list(filter);
|
|
164
|
+
}
|
|
110
165
|
};
|
|
111
166
|
|
|
112
167
|
// src/audit/AuditRecorder.ts
|
|
@@ -124,6 +179,8 @@ var AuditRecorder = class {
|
|
|
124
179
|
actor: input.actor,
|
|
125
180
|
level: input.level ?? "info",
|
|
126
181
|
resource: input.resource,
|
|
182
|
+
entity: input.entity,
|
|
183
|
+
entityId: input.entityId,
|
|
127
184
|
before: input.before,
|
|
128
185
|
after: input.after,
|
|
129
186
|
metadata: input.metadata,
|
|
@@ -2303,25 +2360,297 @@ var IntrospectionRuntime = class {
|
|
|
2303
2360
|
return engine.compare(previous.result, current);
|
|
2304
2361
|
}
|
|
2305
2362
|
};
|
|
2363
|
+
|
|
2364
|
+
// src/correlation/CorrelationId.ts
|
|
2365
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
2366
|
+
function generateCorrelationId() {
|
|
2367
|
+
return randomUUID4();
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
// src/risk/MetadataRiskClassifier.ts
|
|
2371
|
+
var MetadataRiskClassifier = class {
|
|
2372
|
+
constructor(operationRiskMap = {}, defaultRisk = "LOW") {
|
|
2373
|
+
this.operationRiskMap = operationRiskMap;
|
|
2374
|
+
this.defaultRisk = defaultRisk;
|
|
2375
|
+
}
|
|
2376
|
+
operationRiskMap;
|
|
2377
|
+
defaultRisk;
|
|
2378
|
+
classify(input) {
|
|
2379
|
+
const fromMetadata = input.metadata?.["riskLevel"];
|
|
2380
|
+
if (isOperationalRisk(fromMetadata)) return fromMetadata;
|
|
2381
|
+
return this.operationRiskMap[input.operation] ?? this.defaultRisk;
|
|
2382
|
+
}
|
|
2383
|
+
};
|
|
2384
|
+
var RISK_LEVELS = ["LOW", "MEDIUM", "HIGH", "CRITICAL"];
|
|
2385
|
+
function isOperationalRisk(value) {
|
|
2386
|
+
return typeof value === "string" && RISK_LEVELS.includes(value);
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
// src/authorization/ContextualAuthorizationEngine.ts
|
|
2390
|
+
var ContextualAuthorizationEngine = class {
|
|
2391
|
+
constructor(policy, criticalOperations = /* @__PURE__ */ new Set()) {
|
|
2392
|
+
this.criticalOperations = criticalOperations;
|
|
2393
|
+
this.rbac = new RbacEngine(policy);
|
|
2394
|
+
}
|
|
2395
|
+
criticalOperations;
|
|
2396
|
+
rbac;
|
|
2397
|
+
async evaluate(context) {
|
|
2398
|
+
if (!this.rbac.can(context.actor, context.operation)) {
|
|
2399
|
+
return { decision: "DENY", reason: `Actor lacks permission for operation: ${context.operation}` };
|
|
2400
|
+
}
|
|
2401
|
+
const risk = context.riskLevel ?? "LOW";
|
|
2402
|
+
if (risk === "CRITICAL" || this.criticalOperations.has(context.operation)) {
|
|
2403
|
+
return { decision: "REQUIRES_CONFIRMATION", reason: `Operation requires confirmation due to risk level: ${risk}` };
|
|
2404
|
+
}
|
|
2405
|
+
return { decision: "ALLOW" };
|
|
2406
|
+
}
|
|
2407
|
+
};
|
|
2408
|
+
|
|
2409
|
+
// src/policy/PolicyEngine.ts
|
|
2410
|
+
var DECISION_PRIORITY = {
|
|
2411
|
+
ALLOW: 0,
|
|
2412
|
+
REQUIRES_CONFIRMATION: 1,
|
|
2413
|
+
DENY: 2
|
|
2414
|
+
};
|
|
2415
|
+
var PolicyEngine = class {
|
|
2416
|
+
constructor(provider) {
|
|
2417
|
+
this.provider = provider;
|
|
2418
|
+
}
|
|
2419
|
+
provider;
|
|
2420
|
+
evaluate(context) {
|
|
2421
|
+
const violations = [];
|
|
2422
|
+
let decision = "ALLOW";
|
|
2423
|
+
let reason;
|
|
2424
|
+
for (const rule of this.provider.rules()) {
|
|
2425
|
+
const result = rule.evaluate(context);
|
|
2426
|
+
if (result === null) continue;
|
|
2427
|
+
if (DECISION_PRIORITY[result.decision] > DECISION_PRIORITY[decision]) {
|
|
2428
|
+
decision = result.decision;
|
|
2429
|
+
reason = result.reason;
|
|
2430
|
+
}
|
|
2431
|
+
if (result.decision === "DENY" || result.decision === "REQUIRES_CONFIRMATION") {
|
|
2432
|
+
violations.push({
|
|
2433
|
+
ruleId: rule.id,
|
|
2434
|
+
reason: result.reason,
|
|
2435
|
+
context,
|
|
2436
|
+
occurredAt: /* @__PURE__ */ new Date()
|
|
2437
|
+
});
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
return { decision, violations, reason };
|
|
2441
|
+
}
|
|
2442
|
+
};
|
|
2443
|
+
|
|
2444
|
+
// src/policy/InMemoryPolicyProvider.ts
|
|
2445
|
+
var InMemoryPolicyProvider = class {
|
|
2446
|
+
_rules;
|
|
2447
|
+
constructor(rules = []) {
|
|
2448
|
+
this._rules = rules;
|
|
2449
|
+
}
|
|
2450
|
+
rules() {
|
|
2451
|
+
return this._rules;
|
|
2452
|
+
}
|
|
2453
|
+
};
|
|
2454
|
+
|
|
2455
|
+
// src/confirmation/ConfirmationEngine.ts
|
|
2456
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
2457
|
+
var ConfirmationEngine = class {
|
|
2458
|
+
constructor(repository) {
|
|
2459
|
+
this.repository = repository;
|
|
2460
|
+
}
|
|
2461
|
+
repository;
|
|
2462
|
+
async request(input) {
|
|
2463
|
+
const requiredApprovals = input.requiredApprovals ?? 1;
|
|
2464
|
+
const request = {
|
|
2465
|
+
id: randomUUID5(),
|
|
2466
|
+
operation: input.operation,
|
|
2467
|
+
actor: input.actor,
|
|
2468
|
+
resource: input.resource,
|
|
2469
|
+
status: requiredApprovals > 1 ? "AWAITING_CONFIRMATION" : "REQUESTED",
|
|
2470
|
+
requiredApprovals,
|
|
2471
|
+
approvals: [],
|
|
2472
|
+
rejections: [],
|
|
2473
|
+
requestedAt: /* @__PURE__ */ new Date(),
|
|
2474
|
+
expiresAt: input.expiresAt,
|
|
2475
|
+
metadata: input.metadata,
|
|
2476
|
+
correlationId: input.correlationId
|
|
2477
|
+
};
|
|
2478
|
+
await this.repository.save(request);
|
|
2479
|
+
return request;
|
|
2480
|
+
}
|
|
2481
|
+
async approve(requestId, approver, comment) {
|
|
2482
|
+
const request = await this.findOrThrow(requestId);
|
|
2483
|
+
this.assertActive(request);
|
|
2484
|
+
const updated = {
|
|
2485
|
+
...request,
|
|
2486
|
+
approvals: [...request.approvals, { approver, approvedAt: /* @__PURE__ */ new Date(), comment }]
|
|
2487
|
+
};
|
|
2488
|
+
const fullyApproved = updated.approvals.length >= updated.requiredApprovals;
|
|
2489
|
+
updated.status = fullyApproved ? "APPROVED" : "AWAITING_CONFIRMATION";
|
|
2490
|
+
await this.repository.save(updated);
|
|
2491
|
+
return updated;
|
|
2492
|
+
}
|
|
2493
|
+
async reject(requestId, approver, comment) {
|
|
2494
|
+
const request = await this.findOrThrow(requestId);
|
|
2495
|
+
this.assertActive(request);
|
|
2496
|
+
const updated = {
|
|
2497
|
+
...request,
|
|
2498
|
+
status: "REJECTED",
|
|
2499
|
+
rejections: [...request.rejections, { approver, approvedAt: /* @__PURE__ */ new Date(), comment }]
|
|
2500
|
+
};
|
|
2501
|
+
await this.repository.save(updated);
|
|
2502
|
+
return updated;
|
|
2503
|
+
}
|
|
2504
|
+
async execute(requestId) {
|
|
2505
|
+
const request = await this.findOrThrow(requestId);
|
|
2506
|
+
if (request.status !== "APPROVED") {
|
|
2507
|
+
throw new MaestroError(
|
|
2508
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
2509
|
+
`Cannot execute confirmation request in status: ${request.status}`
|
|
2510
|
+
);
|
|
2511
|
+
}
|
|
2512
|
+
const updated = {
|
|
2513
|
+
...request,
|
|
2514
|
+
status: "EXECUTED",
|
|
2515
|
+
executedAt: /* @__PURE__ */ new Date()
|
|
2516
|
+
};
|
|
2517
|
+
await this.repository.save(updated);
|
|
2518
|
+
return updated;
|
|
2519
|
+
}
|
|
2520
|
+
async getPending() {
|
|
2521
|
+
return this.repository.listPending();
|
|
2522
|
+
}
|
|
2523
|
+
async findOrThrow(requestId) {
|
|
2524
|
+
const request = await this.repository.findById(requestId);
|
|
2525
|
+
if (!request) {
|
|
2526
|
+
throw new MaestroError(
|
|
2527
|
+
"NOT_FOUND" /* NOT_FOUND */,
|
|
2528
|
+
`Confirmation request not found: ${requestId}`
|
|
2529
|
+
);
|
|
2530
|
+
}
|
|
2531
|
+
return request;
|
|
2532
|
+
}
|
|
2533
|
+
assertActive(request) {
|
|
2534
|
+
const terminal = ["APPROVED", "REJECTED", "EXECUTED", "EXPIRED"];
|
|
2535
|
+
if (terminal.includes(request.status)) {
|
|
2536
|
+
throw new MaestroError(
|
|
2537
|
+
"VALIDATION_ERROR" /* VALIDATION_ERROR */,
|
|
2538
|
+
`Confirmation request is already in terminal status: ${request.status}`
|
|
2539
|
+
);
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
};
|
|
2543
|
+
|
|
2544
|
+
// src/confirmation/InMemoryConfirmationRepository.ts
|
|
2545
|
+
var InMemoryConfirmationRepository = class {
|
|
2546
|
+
store = /* @__PURE__ */ new Map();
|
|
2547
|
+
async save(request) {
|
|
2548
|
+
this.store.set(request.id, request);
|
|
2549
|
+
}
|
|
2550
|
+
async findById(id) {
|
|
2551
|
+
return this.store.get(id);
|
|
2552
|
+
}
|
|
2553
|
+
async listPending() {
|
|
2554
|
+
return Array.from(this.store.values()).filter(
|
|
2555
|
+
(r) => r.status === "REQUESTED" || r.status === "AWAITING_CONFIRMATION"
|
|
2556
|
+
);
|
|
2557
|
+
}
|
|
2558
|
+
};
|
|
2559
|
+
|
|
2560
|
+
// src/governance/GovernanceEventType.ts
|
|
2561
|
+
var GOVERNANCE_EVENT_TYPES = {
|
|
2562
|
+
OPERATION_EXECUTED: "governance.operation.executed",
|
|
2563
|
+
AUTHORIZATION_DENIED: "governance.authorization.denied",
|
|
2564
|
+
POLICY_TRIGGERED: "governance.policy.triggered",
|
|
2565
|
+
CONFIRMATION_REQUESTED: "governance.confirmation.requested",
|
|
2566
|
+
CONFIRMATION_APPROVED: "governance.confirmation.approved",
|
|
2567
|
+
CONFIRMATION_REJECTED: "governance.confirmation.rejected",
|
|
2568
|
+
AUDIT_RECORDED: "governance.audit.recorded"
|
|
2569
|
+
};
|
|
2570
|
+
|
|
2571
|
+
// src/governance/InMemoryGovernanceEventBus.ts
|
|
2572
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
2573
|
+
var InMemoryGovernanceEventBus = class extends InMemoryEventBus {
|
|
2574
|
+
async publishGovernance(type, payload, correlationId) {
|
|
2575
|
+
const event = {
|
|
2576
|
+
id: randomUUID6(),
|
|
2577
|
+
type,
|
|
2578
|
+
occurredAt: /* @__PURE__ */ new Date(),
|
|
2579
|
+
payload,
|
|
2580
|
+
correlationId
|
|
2581
|
+
};
|
|
2582
|
+
await this.publish(event);
|
|
2583
|
+
return event;
|
|
2584
|
+
}
|
|
2585
|
+
};
|
|
2586
|
+
|
|
2587
|
+
// src/governance/DefaultGovernanceApi.ts
|
|
2588
|
+
var DefaultGovernanceApi = class {
|
|
2589
|
+
constructor(auditRepository, confirmationRepository, violationLog = []) {
|
|
2590
|
+
this.auditRepository = auditRepository;
|
|
2591
|
+
this.confirmationRepository = confirmationRepository;
|
|
2592
|
+
this.violationLog = violationLog;
|
|
2593
|
+
}
|
|
2594
|
+
auditRepository;
|
|
2595
|
+
confirmationRepository;
|
|
2596
|
+
violationLog;
|
|
2597
|
+
async getAuditTimeline(filter) {
|
|
2598
|
+
return this.auditRepository.list(filter);
|
|
2599
|
+
}
|
|
2600
|
+
async getCorrelationTrace(correlationId) {
|
|
2601
|
+
return this.auditRepository.list({ correlationId });
|
|
2602
|
+
}
|
|
2603
|
+
async getPendingConfirmations() {
|
|
2604
|
+
return this.confirmationRepository.listPending();
|
|
2605
|
+
}
|
|
2606
|
+
async getPolicyViolations(filter) {
|
|
2607
|
+
let violations = [...this.violationLog];
|
|
2608
|
+
if (filter?.ruleId !== void 0) {
|
|
2609
|
+
violations = violations.filter((v) => v.ruleId === filter.ruleId);
|
|
2610
|
+
}
|
|
2611
|
+
if (filter?.correlationId !== void 0) {
|
|
2612
|
+
violations = violations.filter((v) => v.context.correlationId === filter.correlationId);
|
|
2613
|
+
}
|
|
2614
|
+
if (filter?.from !== void 0) {
|
|
2615
|
+
const from = filter.from;
|
|
2616
|
+
violations = violations.filter((v) => v.occurredAt >= from);
|
|
2617
|
+
}
|
|
2618
|
+
if (filter?.to !== void 0) {
|
|
2619
|
+
const to = filter.to;
|
|
2620
|
+
violations = violations.filter((v) => v.occurredAt <= to);
|
|
2621
|
+
}
|
|
2622
|
+
return violations;
|
|
2623
|
+
}
|
|
2624
|
+
};
|
|
2306
2625
|
export {
|
|
2307
2626
|
AuditRecorder,
|
|
2627
|
+
ConfirmationEngine,
|
|
2308
2628
|
ConsoleLogger,
|
|
2629
|
+
ConsoleStructuredLogger,
|
|
2630
|
+
ContextualAuthorizationEngine,
|
|
2309
2631
|
CsvExportProvider,
|
|
2310
2632
|
DEFAULT_CAPABILITIES,
|
|
2311
2633
|
DatasourceRegistry,
|
|
2634
|
+
DefaultGovernanceApi,
|
|
2312
2635
|
DiffEngine,
|
|
2313
2636
|
ErrorCode,
|
|
2637
|
+
GOVERNANCE_EVENT_TYPES,
|
|
2314
2638
|
InMemoryAuditRepository,
|
|
2315
2639
|
InMemoryConfigProvider,
|
|
2640
|
+
InMemoryConfirmationRepository,
|
|
2316
2641
|
InMemoryDatasourceProvider,
|
|
2317
2642
|
InMemoryEventBus,
|
|
2318
2643
|
InMemoryFeatureFlagProvider,
|
|
2644
|
+
InMemoryGovernanceEventBus,
|
|
2645
|
+
InMemoryPolicyProvider,
|
|
2319
2646
|
InMemorySnapshotRepository,
|
|
2320
2647
|
IntrospectionRuntime,
|
|
2321
2648
|
MaestroEngine,
|
|
2322
2649
|
MaestroError,
|
|
2323
2650
|
MetadataEngine,
|
|
2651
|
+
MetadataRiskClassifier,
|
|
2324
2652
|
OperationRegistry,
|
|
2653
|
+
PolicyEngine,
|
|
2325
2654
|
RbacEngine,
|
|
2326
2655
|
ReportGenerator,
|
|
2327
2656
|
createMaestro,
|
|
@@ -2329,6 +2658,7 @@ export {
|
|
|
2329
2658
|
createMaestroHttpHandlers,
|
|
2330
2659
|
detectDisplayField,
|
|
2331
2660
|
generateAllConfigs,
|
|
2661
|
+
generateCorrelationId,
|
|
2332
2662
|
generateEntityConfig,
|
|
2333
2663
|
generateRelationConfig,
|
|
2334
2664
|
humanizeFieldName,
|