@baselineos/govern 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1271 @@
1
+ // src/system.ts
2
+ import { randomUUID } from "crypto";
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
4
+ import { dirname } from "path";
5
+ var BaselineGovernSystem = class {
6
+ persistPath;
7
+ state = {
8
+ initialized: false,
9
+ currentPolicies: /* @__PURE__ */ new Map(),
10
+ currentEvaluations: /* @__PURE__ */ new Map(),
11
+ approvalRequests: /* @__PURE__ */ new Map(),
12
+ auditTrail: [],
13
+ currentRisks: /* @__PURE__ */ new Map(),
14
+ currentPermissions: /* @__PURE__ */ new Map(),
15
+ currentCosts: /* @__PURE__ */ new Map(),
16
+ currentCompliance: /* @__PURE__ */ new Map(),
17
+ governanceHistory: []
18
+ };
19
+ policies;
20
+ approvals;
21
+ risk;
22
+ permissions;
23
+ costs;
24
+ compliance;
25
+ constructor(options = {}) {
26
+ this.persistPath = options.persistPath ?? ".baseline/govern/audit-trail.json";
27
+ this.policies = this.initializePolicies();
28
+ this.approvals = this.initializeApprovals();
29
+ this.risk = this.initializeRisk();
30
+ this.permissions = this.initializePermissions();
31
+ this.costs = this.initializeCosts();
32
+ this.compliance = this.initializeCompliance();
33
+ this.loadAuditTrail();
34
+ this.state.initialized = true;
35
+ }
36
+ initializePolicies() {
37
+ return {
38
+ create: async (name, content, options = {}) => {
39
+ const policy = {
40
+ id: `policy-${Date.now()}`,
41
+ name,
42
+ content,
43
+ created: /* @__PURE__ */ new Date(),
44
+ version: "1.0.0",
45
+ status: "draft",
46
+ severity: this.asSeverity(options.severity) ?? "medium",
47
+ enforcement: this.asEnforcement(options.enforcement) ?? "warn",
48
+ rules: this.parseRules(options.rules),
49
+ requireApproval: Boolean(options.requireApproval),
50
+ options
51
+ };
52
+ this.state.currentPolicies.set(policy.id, policy);
53
+ this.recordAudit("policy_created", "system", { policyId: policy.id, name: policy.name });
54
+ return { success: true, policy };
55
+ },
56
+ approve: async (policyId, approver) => {
57
+ const policy = this.state.currentPolicies.get(policyId);
58
+ if (policy) {
59
+ policy.status = "approved";
60
+ policy.approved = /* @__PURE__ */ new Date();
61
+ policy.approver = approver;
62
+ this.recordAudit("policy_approved", approver, { policyId: policy.id });
63
+ return { success: true, policy };
64
+ }
65
+ return this.fail("POLICY_NOT_FOUND", "Policy not found");
66
+ },
67
+ enforce: async (policyId, context) => {
68
+ const policy = this.state.currentPolicies.get(policyId);
69
+ if (!policy) {
70
+ return this.fail("POLICY_NOT_FOUND", "Policy not found");
71
+ }
72
+ if (policy.status !== "approved") {
73
+ return this.fail("POLICY_NOT_APPROVED", "Policy not approved");
74
+ }
75
+ const evaluation = this.evaluatePolicy(policy, context);
76
+ this.state.currentEvaluations.set(evaluation.id, evaluation);
77
+ this.recordAudit("policy_evaluated", "system", {
78
+ policyId,
79
+ passed: evaluation.passed,
80
+ enforcementAction: evaluation.enforcementAction,
81
+ violationCount: evaluation.violations.length
82
+ });
83
+ const resourceId = this.getContextValue(context, "resourceId") || this.getContextValue(context, "resource") || policyId;
84
+ const requestedBy = this.getContextValue(context, "requestedBy") || "system";
85
+ if (evaluation.requiresApproval) {
86
+ const approved = this.findApprovedRequest(policyId, String(resourceId));
87
+ if (!approved) {
88
+ const approval = this.createApprovalRequest(policyId, String(resourceId), String(requestedBy), policy.options);
89
+ return {
90
+ success: false,
91
+ policy,
92
+ evaluation: { ...evaluation, enforcementAction: "approval_required", passed: false },
93
+ approval,
94
+ evidence: this.getEvidenceBundle(policyId, String(resourceId)),
95
+ error: "Approval required before enforcement",
96
+ errorCode: "APPROVAL_REQUIRED"
97
+ };
98
+ }
99
+ }
100
+ if (!evaluation.passed) {
101
+ return {
102
+ success: false,
103
+ policy,
104
+ evaluation,
105
+ evidence: this.getEvidenceBundle(policyId, String(resourceId)),
106
+ error: "Policy enforcement blocked by violations",
107
+ errorCode: "POLICY_ENFORCEMENT_BLOCKED"
108
+ };
109
+ }
110
+ policy.status = "enforced";
111
+ this.recordAudit("policy_enforced", "system", {
112
+ policyId,
113
+ resourceId,
114
+ enforcementAction: evaluation.enforcementAction
115
+ });
116
+ return {
117
+ success: true,
118
+ policy,
119
+ evaluation,
120
+ evidence: this.getEvidenceBundle(policyId, String(resourceId)),
121
+ enforcement: {
122
+ id: `enforcement-${Date.now()}`,
123
+ policyId,
124
+ context,
125
+ enforced: /* @__PURE__ */ new Date(),
126
+ result: evaluation.enforcementAction
127
+ }
128
+ };
129
+ }
130
+ };
131
+ }
132
+ initializeApprovals() {
133
+ return {
134
+ request: async (policyId, resourceId, requestedBy, options = {}) => {
135
+ const approval = this.createApprovalRequest(policyId, resourceId, requestedBy, options);
136
+ return { success: true, approval };
137
+ },
138
+ review: async (requestId, approver, decision, options = {}) => {
139
+ const request = this.state.approvalRequests.get(requestId);
140
+ if (!request) {
141
+ return this.fail("APPROVAL_NOT_FOUND", "Approval request not found");
142
+ }
143
+ if (request.status !== "pending") {
144
+ return this.fail("APPROVAL_ALREADY_RESOLVED", `Approval request already ${request.status}`);
145
+ }
146
+ const note = typeof options.note === "string" ? options.note : void 0;
147
+ const now = /* @__PURE__ */ new Date();
148
+ if (decision === "approved") {
149
+ request.approvals.push({ approver, at: now, note });
150
+ const allRequiredApproved = request.requiredApprovers.every(
151
+ (required) => request.approvals.some((approval) => approval.approver === required)
152
+ );
153
+ if (allRequiredApproved) {
154
+ request.status = "approved";
155
+ }
156
+ } else {
157
+ request.rejections.push({ approver, at: now, note });
158
+ request.status = "rejected";
159
+ }
160
+ request.updatedAt = now;
161
+ this.recordAudit("approval_reviewed", approver, {
162
+ requestId,
163
+ policyId: request.policyId,
164
+ resourceId: request.resourceId,
165
+ decision,
166
+ status: request.status
167
+ });
168
+ return { success: true, approval: request };
169
+ },
170
+ get: (requestId) => {
171
+ const approval = this.state.approvalRequests.get(requestId);
172
+ if (!approval) {
173
+ return this.fail("APPROVAL_NOT_FOUND", "Approval request not found");
174
+ }
175
+ return { success: true, approval };
176
+ },
177
+ list: (policyId) => {
178
+ let approvals = Array.from(this.state.approvalRequests.values());
179
+ if (policyId) {
180
+ approvals = approvals.filter((approval) => approval.policyId === policyId);
181
+ }
182
+ return { success: true, approvals };
183
+ }
184
+ };
185
+ }
186
+ initializeRisk() {
187
+ return {
188
+ assess: async (context) => {
189
+ const assessment = {
190
+ id: `assessment-${Date.now()}`,
191
+ context,
192
+ riskLevel: this.calculateRiskLevel(context),
193
+ factors: this.identifyRiskFactors(),
194
+ recommendations: this.generateRiskRecommendations(),
195
+ assessed: /* @__PURE__ */ new Date()
196
+ };
197
+ this.state.currentRisks.set(assessment.id, assessment);
198
+ return { success: true, assessment };
199
+ },
200
+ mitigate: async (riskId, strategy) => {
201
+ const risk = this.state.currentRisks.get(riskId);
202
+ if (risk) {
203
+ risk.mitigation = { strategy, implemented: /* @__PURE__ */ new Date(), status: "implemented" };
204
+ return { success: true, assessment: risk };
205
+ }
206
+ return this.fail("RISK_NOT_FOUND", "Risk not found");
207
+ },
208
+ monitor: async (riskId) => {
209
+ const risk = this.state.currentRisks.get(riskId);
210
+ if (risk) {
211
+ return {
212
+ success: true,
213
+ monitoring: { id: `monitoring-${Date.now()}`, riskId, status: "monitoring", started: /* @__PURE__ */ new Date() }
214
+ };
215
+ }
216
+ return this.fail("RISK_NOT_FOUND", "Risk not found");
217
+ }
218
+ };
219
+ }
220
+ initializePermissions() {
221
+ return {
222
+ grant: async (subject, resource, action, options = {}) => {
223
+ const permission = {
224
+ id: `permission-${Date.now()}`,
225
+ subject,
226
+ resource,
227
+ action,
228
+ granted: /* @__PURE__ */ new Date(),
229
+ options
230
+ };
231
+ this.state.currentPermissions.set(permission.id, permission);
232
+ this.recordAudit("permission_granted", String(options.actor ?? "system"), {
233
+ permissionId: permission.id,
234
+ subject,
235
+ resource,
236
+ action
237
+ });
238
+ return { success: true, permission };
239
+ },
240
+ check: async (subject, resource, action) => {
241
+ const permissions = Array.from(this.state.currentPermissions.values());
242
+ const hasPermission = permissions.some(
243
+ (p) => p.subject === subject && p.resource === resource && p.action === action
244
+ );
245
+ return { success: true, data: { hasPermission } };
246
+ },
247
+ revoke: async (permissionId) => {
248
+ const permission = this.state.currentPermissions.get(permissionId);
249
+ if (permission) {
250
+ permission.revoked = /* @__PURE__ */ new Date();
251
+ permission.status = "revoked";
252
+ this.recordAudit("permission_revoked", "system", { permissionId });
253
+ return { success: true, permission };
254
+ }
255
+ return this.fail("PERMISSION_NOT_FOUND", "Permission not found");
256
+ }
257
+ };
258
+ }
259
+ initializeCosts() {
260
+ return {
261
+ track: async (resource, amount, options = {}) => {
262
+ const cost = {
263
+ id: `cost-${Date.now()}`,
264
+ resource,
265
+ amount,
266
+ tracked: /* @__PURE__ */ new Date(),
267
+ options
268
+ };
269
+ this.state.currentCosts.set(cost.id, cost);
270
+ this.recordAudit("cost_tracked", String(options.actor ?? "system"), {
271
+ costId: cost.id,
272
+ resource,
273
+ amount
274
+ });
275
+ return { success: true, cost };
276
+ },
277
+ analyze: async (timeframe) => {
278
+ const costs = Array.from(this.state.currentCosts.values());
279
+ return {
280
+ success: true,
281
+ analysis: {
282
+ id: `analysis-${Date.now()}`,
283
+ timeframe,
284
+ totalCost: costs.reduce((sum, c) => sum + c.amount, 0),
285
+ costBreakdown: this.breakdownCosts(costs),
286
+ analyzed: /* @__PURE__ */ new Date()
287
+ }
288
+ };
289
+ },
290
+ optimize: async (context) => {
291
+ return {
292
+ success: true,
293
+ optimization: {
294
+ id: `optimization-${Date.now()}`,
295
+ context,
296
+ recommendations: this.generateCostRecommendations(),
297
+ optimized: /* @__PURE__ */ new Date()
298
+ }
299
+ };
300
+ }
301
+ };
302
+ }
303
+ initializeCompliance() {
304
+ return {
305
+ check: async (standard, context) => {
306
+ const violations = this.identifyViolations(context);
307
+ const compliance = {
308
+ id: `compliance-${Date.now()}`,
309
+ standard,
310
+ context,
311
+ compliant: violations.length === 0,
312
+ violations,
313
+ checked: /* @__PURE__ */ new Date()
314
+ };
315
+ this.state.currentCompliance.set(compliance.id, compliance);
316
+ this.recordAudit("compliance_checked", "system", {
317
+ complianceId: compliance.id,
318
+ standard,
319
+ compliant: compliance.compliant,
320
+ violationCount: violations.length
321
+ });
322
+ return { success: true, compliance };
323
+ },
324
+ report: async (standard) => {
325
+ return {
326
+ success: true,
327
+ report: {
328
+ id: `report-${Date.now()}`,
329
+ standard,
330
+ summary: this.generateComplianceSummary(),
331
+ details: this.generateComplianceDetails(),
332
+ generated: /* @__PURE__ */ new Date()
333
+ }
334
+ };
335
+ },
336
+ remediate: async (violationId, action) => {
337
+ return {
338
+ success: true,
339
+ remediation: {
340
+ id: `remediation-${Date.now()}`,
341
+ violationId,
342
+ action,
343
+ implemented: /* @__PURE__ */ new Date(),
344
+ status: "implemented"
345
+ }
346
+ };
347
+ }
348
+ };
349
+ }
350
+ fail(code, message) {
351
+ return { success: false, error: message, errorCode: code };
352
+ }
353
+ // ─── Helper Methods ─────────────────────────────────────────────────
354
+ asSeverity(value) {
355
+ if (value === "low" || value === "medium" || value === "high" || value === "critical") {
356
+ return value;
357
+ }
358
+ return null;
359
+ }
360
+ asEnforcement(value) {
361
+ if (value === "advisory" || value === "warn" || value === "block") {
362
+ return value;
363
+ }
364
+ return null;
365
+ }
366
+ parseRules(rulesInput) {
367
+ if (!Array.isArray(rulesInput)) {
368
+ return [];
369
+ }
370
+ const parsed = [];
371
+ for (const item of rulesInput) {
372
+ if (!item || typeof item !== "object") {
373
+ continue;
374
+ }
375
+ const raw = item;
376
+ const condition = raw.condition;
377
+ if (!condition || typeof condition.field !== "string" || condition.field.trim().length === 0) {
378
+ continue;
379
+ }
380
+ const rule = {
381
+ id: typeof raw.id === "string" && raw.id.trim().length > 0 ? raw.id : randomUUID(),
382
+ name: typeof raw.name === "string" && raw.name.trim().length > 0 ? raw.name : "Unnamed Rule",
383
+ description: typeof raw.description === "string" ? raw.description : void 0,
384
+ severity: this.asSeverity(raw.severity) ?? "medium",
385
+ enforcement: this.asEnforcement(raw.enforcement) ?? "warn",
386
+ condition,
387
+ message: typeof raw.message === "string" ? raw.message : void 0
388
+ };
389
+ parsed.push(rule);
390
+ }
391
+ return parsed;
392
+ }
393
+ evaluatePolicy(policy, context) {
394
+ const violations = [];
395
+ for (const rule of policy.rules) {
396
+ if (this.matchesCondition(context, rule.condition)) {
397
+ violations.push({
398
+ ruleId: rule.id,
399
+ ruleName: rule.name,
400
+ severity: rule.severity,
401
+ enforcement: rule.enforcement,
402
+ message: rule.message ?? `Policy rule triggered: ${rule.name}`
403
+ });
404
+ }
405
+ }
406
+ const severityScore = violations.reduce((sum, violation) => sum + this.severityToWeight(violation.severity), 0);
407
+ const score = Math.max(0, 100 - severityScore * 10);
408
+ const hasBlocking = violations.some(
409
+ (violation) => violation.enforcement === "block" || violation.severity === "critical"
410
+ );
411
+ const hasWarning = violations.some((violation) => violation.enforcement === "warn");
412
+ return {
413
+ id: `evaluation-${Date.now()}-${Math.floor(Math.random() * 1e3)}`,
414
+ policyId: policy.id,
415
+ context,
416
+ passed: !hasBlocking,
417
+ score,
418
+ violations,
419
+ enforcementAction: hasBlocking ? "block" : hasWarning ? "warn" : "allow",
420
+ requiresApproval: policy.requireApproval,
421
+ evaluatedAt: /* @__PURE__ */ new Date()
422
+ };
423
+ }
424
+ matchesCondition(context, condition) {
425
+ const value = this.getContextValue(context, condition.field);
426
+ if (typeof condition.exists === "boolean") {
427
+ const exists = value !== void 0 && value !== null;
428
+ return condition.exists ? exists : !exists;
429
+ }
430
+ if (condition.equals !== void 0) {
431
+ return value === condition.equals;
432
+ }
433
+ if (condition.notEquals !== void 0) {
434
+ return value !== condition.notEquals;
435
+ }
436
+ if (condition.includes !== void 0) {
437
+ if (typeof value === "string") {
438
+ return value.includes(String(condition.includes));
439
+ }
440
+ if (Array.isArray(value)) {
441
+ return value.includes(condition.includes);
442
+ }
443
+ return false;
444
+ }
445
+ return false;
446
+ }
447
+ getContextValue(context, field) {
448
+ if (!context || typeof context !== "object") {
449
+ return void 0;
450
+ }
451
+ const source = context;
452
+ if (!field.includes(".")) {
453
+ return source[field];
454
+ }
455
+ const segments = field.split(".");
456
+ let current = source;
457
+ for (const segment of segments) {
458
+ if (!current || typeof current !== "object") {
459
+ return void 0;
460
+ }
461
+ current = current[segment];
462
+ }
463
+ return current;
464
+ }
465
+ severityToWeight(severity) {
466
+ switch (severity) {
467
+ case "critical":
468
+ return 4;
469
+ case "high":
470
+ return 3;
471
+ case "medium":
472
+ return 2;
473
+ case "low":
474
+ default:
475
+ return 1;
476
+ }
477
+ }
478
+ createApprovalRequest(policyId, resourceId, requestedBy, options = {}) {
479
+ const existing = Array.from(this.state.approvalRequests.values()).find(
480
+ (request2) => request2.policyId === policyId && request2.resourceId === resourceId && request2.status === "pending"
481
+ );
482
+ if (existing) {
483
+ return existing;
484
+ }
485
+ const requiredApprovers = Array.isArray(options.requiredApprovers) ? options.requiredApprovers.filter((value) => typeof value === "string" && value.length > 0) : ["govern-approver"];
486
+ const request = {
487
+ id: `approval-${Date.now()}-${Math.floor(Math.random() * 1e3)}`,
488
+ policyId,
489
+ resourceId,
490
+ requestedBy,
491
+ status: "pending",
492
+ requiredApprovers,
493
+ approvals: [],
494
+ rejections: [],
495
+ createdAt: /* @__PURE__ */ new Date(),
496
+ updatedAt: /* @__PURE__ */ new Date()
497
+ };
498
+ this.state.approvalRequests.set(request.id, request);
499
+ this.recordAudit("approval_requested", requestedBy, {
500
+ requestId: request.id,
501
+ policyId,
502
+ resourceId,
503
+ requiredApprovers
504
+ });
505
+ return request;
506
+ }
507
+ findApprovedRequest(policyId, resourceId) {
508
+ return Array.from(this.state.approvalRequests.values()).find(
509
+ (request) => request.policyId === policyId && request.resourceId === resourceId && request.status === "approved"
510
+ );
511
+ }
512
+ recordAudit(type, actor, details) {
513
+ const event = {
514
+ id: `audit-${Date.now()}-${Math.floor(Math.random() * 1e3)}`,
515
+ type,
516
+ actor,
517
+ policyId: typeof details.policyId === "string" ? details.policyId : void 0,
518
+ resourceId: typeof details.resourceId === "string" ? details.resourceId : void 0,
519
+ details,
520
+ timestamp: /* @__PURE__ */ new Date()
521
+ };
522
+ this.state.auditTrail.push(event);
523
+ this.persistAuditTrail();
524
+ }
525
+ loadAuditTrail() {
526
+ if (!existsSync(this.persistPath)) {
527
+ return;
528
+ }
529
+ try {
530
+ const raw = JSON.parse(readFileSync(this.persistPath, "utf-8"));
531
+ if (!Array.isArray(raw)) {
532
+ return;
533
+ }
534
+ const entries = raw.filter((value) => value && typeof value === "object").map((value) => {
535
+ const event = value;
536
+ return {
537
+ id: String(event.id ?? `audit-${Date.now()}`),
538
+ type: String(event.type ?? "policy_created"),
539
+ actor: String(event.actor ?? "unknown"),
540
+ policyId: typeof event.policyId === "string" ? event.policyId : void 0,
541
+ resourceId: typeof event.resourceId === "string" ? event.resourceId : void 0,
542
+ details: event.details && typeof event.details === "object" ? event.details : {},
543
+ timestamp: new Date(String(event.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()))
544
+ };
545
+ });
546
+ this.state.auditTrail = entries;
547
+ } catch {
548
+ this.state.auditTrail = [];
549
+ }
550
+ }
551
+ persistAuditTrail() {
552
+ try {
553
+ const dir = dirname(this.persistPath);
554
+ if (!existsSync(dir)) {
555
+ mkdirSync(dir, { recursive: true });
556
+ }
557
+ writeFileSync(this.persistPath, JSON.stringify(this.state.auditTrail, null, 2));
558
+ } catch {
559
+ }
560
+ }
561
+ calculateRiskLevel(context) {
562
+ if (context.complexity === "high" && context.impact === "high") return "critical";
563
+ if (context.complexity === "high" || context.impact === "high") return "high";
564
+ if (context.complexity === "medium" || context.impact === "medium") return "medium";
565
+ return "low";
566
+ }
567
+ identifyRiskFactors() {
568
+ return ["complexity", "impact", "dependencies", "external_factors"];
569
+ }
570
+ generateRiskRecommendations() {
571
+ return ["Implement monitoring", "Add safeguards", "Reduce complexity"];
572
+ }
573
+ breakdownCosts(costs) {
574
+ const breakdown = {};
575
+ for (const cost of costs) {
576
+ breakdown[cost.resource] = (breakdown[cost.resource] || 0) + cost.amount;
577
+ }
578
+ return breakdown;
579
+ }
580
+ generateCostRecommendations() {
581
+ return ["Optimize resource usage", "Implement cost controls", "Monitor spending"];
582
+ }
583
+ identifyViolations(context) {
584
+ if (!context || typeof context !== "object") {
585
+ return [];
586
+ }
587
+ const source = context;
588
+ const violations = [];
589
+ if (source.documentation === "missing") {
590
+ violations.push("missing_documentation");
591
+ }
592
+ if (source.process === "incomplete") {
593
+ violations.push("incomplete_process");
594
+ }
595
+ return violations;
596
+ }
597
+ generateComplianceSummary() {
598
+ return { overall: "compliant", score: 85, areas: ["documentation", "process", "monitoring"] };
599
+ }
600
+ generateComplianceDetails() {
601
+ return {
602
+ documentation: { status: "compliant", score: 90 },
603
+ process: { status: "compliant", score: 85 },
604
+ monitoring: { status: "compliant", score: 80 }
605
+ };
606
+ }
607
+ // ─── Public Helpers ───────────────────────────────────────────────
608
+ getAuditTrail(policyId, resourceId) {
609
+ return this.state.auditTrail.filter((event) => {
610
+ const policyMatch = policyId ? event.policyId === policyId : true;
611
+ const resourceMatch = resourceId ? event.resourceId === resourceId : true;
612
+ return policyMatch && resourceMatch;
613
+ });
614
+ }
615
+ getEvidenceBundle(policyId, resourceId) {
616
+ const policy = this.state.currentPolicies.get(policyId);
617
+ const evaluations = Array.from(this.state.currentEvaluations.values()).filter((evaluation) => evaluation.policyId === policyId).sort((a, b) => b.evaluatedAt.getTime() - a.evaluatedAt.getTime());
618
+ const approvals = Array.from(this.state.approvalRequests.values()).filter((request) => {
619
+ if (request.policyId !== policyId) return false;
620
+ if (resourceId) {
621
+ return request.resourceId === resourceId;
622
+ }
623
+ return true;
624
+ });
625
+ return {
626
+ policy,
627
+ latestEvaluation: evaluations[0],
628
+ approvals,
629
+ auditTrail: this.getAuditTrail(policyId, resourceId)
630
+ };
631
+ }
632
+ async executeGovernWorkflow(options = {}) {
633
+ try {
634
+ const policyResult = await this.policies.create("default", "Default governance policy", options);
635
+ if (!policyResult.success) throw new Error(policyResult.error);
636
+ const policyId = policyResult.policy.id;
637
+ const approveResult = await this.policies.approve(policyId, String(options.approver ?? "system"));
638
+ if (!approveResult.success) throw new Error(approveResult.error);
639
+ const enforcement = await this.policies.enforce(policyId, {
640
+ resourceId: String(options.resourceId ?? "workflow-default"),
641
+ requestedBy: String(options.requestedBy ?? "system"),
642
+ ...typeof options.context === "object" && options.context ? options.context : {}
643
+ });
644
+ const riskResult = await this.risk.assess({ complexity: "medium", impact: "medium" });
645
+ if (!riskResult.success) throw new Error(riskResult.error);
646
+ const permissionResult = await this.permissions.grant("user", "resource", "read");
647
+ if (!permissionResult.success) throw new Error(permissionResult.error);
648
+ const costResult = await this.costs.track("resource", 100);
649
+ if (!costResult.success) throw new Error(costResult.error);
650
+ const complianceResult = await this.compliance.check("ISO27001", {
651
+ context: "security",
652
+ documentation: options.documentation,
653
+ process: options.process
654
+ });
655
+ if (!complianceResult.success) throw new Error(complianceResult.error);
656
+ return {
657
+ success: enforcement.success,
658
+ policy: policyResult.policy,
659
+ evaluation: enforcement.evaluation,
660
+ approval: enforcement.approval,
661
+ evidence: this.getEvidenceBundle(policyId, String(options.resourceId ?? "workflow-default")),
662
+ assessment: riskResult.assessment,
663
+ permission: permissionResult.permission,
664
+ cost: costResult.cost,
665
+ compliance: complianceResult.compliance,
666
+ error: enforcement.error
667
+ };
668
+ } catch (error) {
669
+ const msg = error instanceof Error ? error.message : String(error);
670
+ return { success: false, error: msg, errorCode: "INTERNAL_ERROR" };
671
+ }
672
+ }
673
+ getStatus() {
674
+ return {
675
+ initialized: this.state.initialized,
676
+ policies: this.state.currentPolicies.size,
677
+ evaluations: this.state.currentEvaluations.size,
678
+ approvals: this.state.approvalRequests.size,
679
+ auditTrail: this.state.auditTrail.length,
680
+ risks: this.state.currentRisks.size,
681
+ permissions: this.state.currentPermissions.size,
682
+ costs: this.state.currentCosts.size,
683
+ compliance: this.state.currentCompliance.size,
684
+ governanceHistory: this.state.governanceHistory.length
685
+ };
686
+ }
687
+ };
688
+
689
+ // src/errors.ts
690
+ var BaselineError = class extends Error {
691
+ code;
692
+ details;
693
+ timestamp;
694
+ constructor(code, message, details = {}) {
695
+ super(message);
696
+ this.name = "BaselineError";
697
+ this.code = code;
698
+ this.details = details;
699
+ this.timestamp = /* @__PURE__ */ new Date();
700
+ }
701
+ toJSON() {
702
+ return {
703
+ name: this.name,
704
+ code: this.code,
705
+ message: this.message,
706
+ details: this.details,
707
+ timestamp: this.timestamp.toISOString()
708
+ };
709
+ }
710
+ };
711
+ var GovernError = class extends BaselineError {
712
+ constructor(code, message, details = {}) {
713
+ super(code, message, details);
714
+ this.name = "GovernError";
715
+ }
716
+ };
717
+ var ComplianceError = class extends BaselineError {
718
+ standard;
719
+ constructor(standard, message, details = {}) {
720
+ super("COMPLIANCE_VIOLATION", message, { standard, ...details });
721
+ this.name = "ComplianceError";
722
+ this.standard = standard;
723
+ }
724
+ };
725
+ var ValidationError = class extends BaselineError {
726
+ constructor(message, details = {}) {
727
+ super("VALIDATION_FAILED", message, details);
728
+ this.name = "ValidationError";
729
+ }
730
+ };
731
+ var TemplateError = class extends BaselineError {
732
+ templateName;
733
+ constructor(templateName, message, details = {}) {
734
+ super("TEMPLATE_VALIDATION_FAILED", message, { templateName, ...details });
735
+ this.name = "TemplateError";
736
+ this.templateName = templateName;
737
+ }
738
+ };
739
+ function isBaselineError(error) {
740
+ return error instanceof BaselineError;
741
+ }
742
+ function toErrorResult(error) {
743
+ if (error instanceof BaselineError) {
744
+ return { code: error.code, message: error.message };
745
+ }
746
+ if (error instanceof Error) {
747
+ return { code: "INTERNAL_ERROR", message: error.message };
748
+ }
749
+ return { code: "INTERNAL_ERROR", message: String(error) };
750
+ }
751
+
752
+ // src/telemetry.ts
753
+ var GovernTelemetry = class {
754
+ hooks = [];
755
+ events = [];
756
+ maxHistory;
757
+ constructor(options = {}) {
758
+ this.maxHistory = options.maxHistory ?? 1e3;
759
+ }
760
+ addHook(hook) {
761
+ this.hooks.push(hook);
762
+ }
763
+ removeHook(hook) {
764
+ const idx = this.hooks.indexOf(hook);
765
+ if (idx >= 0) this.hooks.splice(idx, 1);
766
+ }
767
+ emit(event) {
768
+ this.events.push(event);
769
+ if (this.events.length > this.maxHistory) {
770
+ this.events.splice(0, this.events.length - this.maxHistory);
771
+ }
772
+ for (const hook of this.hooks) {
773
+ try {
774
+ hook(event);
775
+ } catch {
776
+ }
777
+ }
778
+ }
779
+ track(operation, subsystem, fn, details = {}) {
780
+ const start = performance.now();
781
+ try {
782
+ const result = fn();
783
+ const durationMs = performance.now() - start;
784
+ this.emit({
785
+ operation,
786
+ subsystem,
787
+ success: true,
788
+ durationMs,
789
+ timestamp: /* @__PURE__ */ new Date(),
790
+ details
791
+ });
792
+ return result;
793
+ } catch (error) {
794
+ const durationMs = performance.now() - start;
795
+ this.emit({
796
+ operation,
797
+ subsystem,
798
+ success: false,
799
+ durationMs,
800
+ timestamp: /* @__PURE__ */ new Date(),
801
+ details: { ...details, error: error instanceof Error ? error.message : String(error) }
802
+ });
803
+ throw error;
804
+ }
805
+ }
806
+ async trackAsync(operation, subsystem, fn, details = {}) {
807
+ const start = performance.now();
808
+ try {
809
+ const result = await fn();
810
+ const durationMs = performance.now() - start;
811
+ this.emit({
812
+ operation,
813
+ subsystem,
814
+ success: true,
815
+ durationMs,
816
+ timestamp: /* @__PURE__ */ new Date(),
817
+ details
818
+ });
819
+ return result;
820
+ } catch (error) {
821
+ const durationMs = performance.now() - start;
822
+ this.emit({
823
+ operation,
824
+ subsystem,
825
+ success: false,
826
+ durationMs,
827
+ timestamp: /* @__PURE__ */ new Date(),
828
+ details: { ...details, error: error instanceof Error ? error.message : String(error) }
829
+ });
830
+ throw error;
831
+ }
832
+ }
833
+ getEvents() {
834
+ return this.events;
835
+ }
836
+ getMetrics() {
837
+ const bySubsystem = /* @__PURE__ */ new Map();
838
+ for (const event of this.events) {
839
+ const key = event.subsystem;
840
+ const entry = bySubsystem.get(key) ?? { count: 0, totalMs: 0, failures: 0 };
841
+ entry.count++;
842
+ entry.totalMs += event.durationMs;
843
+ if (!event.success) entry.failures++;
844
+ bySubsystem.set(key, entry);
845
+ }
846
+ const subsystems = {};
847
+ for (const [key, entry] of bySubsystem) {
848
+ subsystems[key] = {
849
+ operations: entry.count,
850
+ avgDurationMs: entry.count > 0 ? entry.totalMs / entry.count : 0,
851
+ failureRate: entry.count > 0 ? entry.failures / entry.count : 0
852
+ };
853
+ }
854
+ const totalOps = this.events.length;
855
+ const totalMs = this.events.reduce((sum, e) => sum + e.durationMs, 0);
856
+ const totalFailures = this.events.filter((e) => !e.success).length;
857
+ return {
858
+ totalOperations: totalOps,
859
+ avgDurationMs: totalOps > 0 ? totalMs / totalOps : 0,
860
+ failureRate: totalOps > 0 ? totalFailures / totalOps : 0,
861
+ subsystems,
862
+ since: this.events[0]?.timestamp ?? /* @__PURE__ */ new Date()
863
+ };
864
+ }
865
+ clear() {
866
+ this.events = [];
867
+ }
868
+ };
869
+
870
+ // src/cache.ts
871
+ var ComplianceCache = class {
872
+ cache = /* @__PURE__ */ new Map();
873
+ maxSize;
874
+ ttlMs;
875
+ totalHits = 0;
876
+ totalMisses = 0;
877
+ constructor(options = {}) {
878
+ this.maxSize = options.maxSize ?? 256;
879
+ this.ttlMs = options.ttlMs ?? 6e4;
880
+ }
881
+ get(key) {
882
+ const entry = this.cache.get(key);
883
+ if (!entry) {
884
+ this.totalMisses++;
885
+ return void 0;
886
+ }
887
+ if (Date.now() - entry.cachedAt > this.ttlMs) {
888
+ this.cache.delete(key);
889
+ this.totalMisses++;
890
+ return void 0;
891
+ }
892
+ this.cache.delete(key);
893
+ entry.hits++;
894
+ this.cache.set(key, entry);
895
+ this.totalHits++;
896
+ return entry.value;
897
+ }
898
+ set(key, value) {
899
+ if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
900
+ const firstKey = this.cache.keys().next().value;
901
+ if (firstKey !== void 0) {
902
+ this.cache.delete(firstKey);
903
+ }
904
+ }
905
+ this.cache.set(key, {
906
+ value,
907
+ cachedAt: Date.now(),
908
+ hits: 0
909
+ });
910
+ }
911
+ has(key) {
912
+ const entry = this.cache.get(key);
913
+ if (!entry) return false;
914
+ if (Date.now() - entry.cachedAt > this.ttlMs) {
915
+ this.cache.delete(key);
916
+ return false;
917
+ }
918
+ return true;
919
+ }
920
+ clear() {
921
+ this.cache.clear();
922
+ this.totalHits = 0;
923
+ this.totalMisses = 0;
924
+ }
925
+ get size() {
926
+ return this.cache.size;
927
+ }
928
+ get hitRate() {
929
+ const total = this.totalHits + this.totalMisses;
930
+ return total > 0 ? this.totalHits / total : 0;
931
+ }
932
+ getStats() {
933
+ return {
934
+ size: this.cache.size,
935
+ maxSize: this.maxSize,
936
+ ttlMs: this.ttlMs,
937
+ hits: this.totalHits,
938
+ misses: this.totalMisses,
939
+ hitRate: this.hitRate
940
+ };
941
+ }
942
+ static hashKey(standard, context) {
943
+ const contextStr = JSON.stringify(context, Object.keys(
944
+ context && typeof context === "object" ? context : {}
945
+ ).sort());
946
+ return `${standard}:${contextStr}`;
947
+ }
948
+ };
949
+
950
+ // src/templates/cocobod.ts
951
+ function assessCocobodGrade(context) {
952
+ const violations = [];
953
+ if (context.moisturePercentage > 7.5) {
954
+ violations.push(`Moisture ${context.moisturePercentage}% exceeds 7.5% maximum`);
955
+ }
956
+ if (!context.hasOriginCertificate) {
957
+ violations.push("Missing origin traceability certificate");
958
+ }
959
+ if (!context.hasQualityCertificate) {
960
+ violations.push("Missing quality inspection certificate");
961
+ }
962
+ let grade;
963
+ if (context.defectivePercentage <= 3) {
964
+ grade = "I";
965
+ } else if (context.defectivePercentage <= 5) {
966
+ grade = "II";
967
+ } else {
968
+ grade = "substandard";
969
+ violations.push(`Defective rate ${context.defectivePercentage}% exceeds 5% maximum`);
970
+ }
971
+ const exportEligible = grade !== "substandard" && violations.length === 0;
972
+ return { grade, exportEligible, violations };
973
+ }
974
+ var COCOBOD_TEMPLATE = {
975
+ name: "COCOBOD-GRADING",
976
+ description: "Ghana Cocoa Board commodity grading and export compliance",
977
+ version: "1.0.0",
978
+ jurisdiction: "GH",
979
+ rules: [
980
+ {
981
+ id: "cocobod-moisture",
982
+ name: "Moisture Content Limit",
983
+ description: "Cocoa beans must not exceed 7.5% moisture content",
984
+ severity: "critical",
985
+ enforcement: "block",
986
+ condition: { field: "moisturePercentage", greaterThan: 7.5 },
987
+ message: "Moisture content exceeds COCOBOD 7.5% limit"
988
+ },
989
+ {
990
+ id: "cocobod-defective",
991
+ name: "Defective Bean Rate",
992
+ description: "Defective bean rate must not exceed 5% for export",
993
+ severity: "high",
994
+ enforcement: "block",
995
+ condition: { field: "defectivePercentage", greaterThan: 5 },
996
+ message: "Defective rate exceeds COCOBOD 5% export threshold"
997
+ },
998
+ {
999
+ id: "cocobod-origin",
1000
+ name: "Origin Certificate Required",
1001
+ description: "All shipments require origin traceability documentation",
1002
+ severity: "critical",
1003
+ enforcement: "block",
1004
+ condition: { field: "hasOriginCertificate", equals: false },
1005
+ message: "Missing COCOBOD origin traceability certificate"
1006
+ },
1007
+ {
1008
+ id: "cocobod-quality",
1009
+ name: "Quality Certificate Required",
1010
+ description: "Quality inspection certificate required for export",
1011
+ severity: "high",
1012
+ enforcement: "block",
1013
+ condition: { field: "hasQualityCertificate", equals: false },
1014
+ message: "Missing COCOBOD quality inspection certificate"
1015
+ }
1016
+ ]
1017
+ };
1018
+
1019
+ // src/templates/fic-aml.ts
1020
+ var STR_THRESHOLD_GHS = 2e4;
1021
+ var CTR_THRESHOLD_GHS = 5e4;
1022
+ var MIN_RETENTION_YEARS = 5;
1023
+ function assessFicAml(context) {
1024
+ const violations = [];
1025
+ const amountGHS = context.currency === "GHS" ? context.transactionAmount : context.transactionAmount;
1026
+ const requiresSTR = amountGHS >= STR_THRESHOLD_GHS;
1027
+ const requiresCTR = amountGHS >= CTR_THRESHOLD_GHS;
1028
+ const requiresEDD = context.isPEP || context.riskRating === "high";
1029
+ if (!context.hasKYC) {
1030
+ violations.push("Customer Due Diligence (KYC) not completed");
1031
+ }
1032
+ if (requiresEDD && !context.hasEDD) {
1033
+ violations.push("Enhanced Due Diligence required for high-risk/PEP customer");
1034
+ }
1035
+ if (!context.sanctionsScreened) {
1036
+ violations.push("Sanctions screening not performed");
1037
+ } else if (!context.sanctionsCleared) {
1038
+ violations.push("Customer failed sanctions screening \u2014 transaction blocked");
1039
+ }
1040
+ if (context.recordRetentionYears !== void 0 && context.recordRetentionYears < MIN_RETENTION_YEARS) {
1041
+ violations.push(`Record retention ${context.recordRetentionYears} years below ${MIN_RETENTION_YEARS}-year minimum`);
1042
+ }
1043
+ if (requiresCTR && !context.sourceOfFunds) {
1044
+ violations.push("Source of funds declaration required for transactions >= GHS 50,000");
1045
+ }
1046
+ return {
1047
+ compliant: violations.length === 0,
1048
+ requiresSTR,
1049
+ requiresCTR,
1050
+ requiresEDD,
1051
+ violations
1052
+ };
1053
+ }
1054
+ var FIC_AML_TEMPLATE = {
1055
+ name: "FIC-AML-1044",
1056
+ description: "Ghana FIC Anti-Money Laundering Act 1044 compliance",
1057
+ version: "1.0.0",
1058
+ jurisdiction: "GH",
1059
+ rules: [
1060
+ {
1061
+ id: "fic-kyc",
1062
+ name: "Customer Due Diligence",
1063
+ description: "KYC verification required for all transactions",
1064
+ severity: "critical",
1065
+ enforcement: "block",
1066
+ condition: { field: "hasKYC", equals: false },
1067
+ message: "FIC Act 1044: Customer Due Diligence not completed"
1068
+ },
1069
+ {
1070
+ id: "fic-sanctions",
1071
+ name: "Sanctions Screening",
1072
+ description: "All customers must be screened against sanctions lists",
1073
+ severity: "critical",
1074
+ enforcement: "block",
1075
+ condition: { field: "sanctionsScreened", equals: false },
1076
+ message: "FIC Act 1044: Sanctions screening not performed"
1077
+ },
1078
+ {
1079
+ id: "fic-edd",
1080
+ name: "Enhanced Due Diligence",
1081
+ description: "EDD required for PEPs and high-risk customers",
1082
+ severity: "high",
1083
+ enforcement: "block",
1084
+ condition: { field: "isPEP", equals: true },
1085
+ message: "FIC Act 1044: Enhanced Due Diligence required for PEP"
1086
+ },
1087
+ {
1088
+ id: "fic-source-of-funds",
1089
+ name: "Source of Funds",
1090
+ description: "Source of funds required for large transactions",
1091
+ severity: "high",
1092
+ enforcement: "block",
1093
+ condition: { field: "sourceOfFunds", exists: false },
1094
+ message: "FIC Act 1044: Source of funds declaration required"
1095
+ }
1096
+ ]
1097
+ };
1098
+
1099
+ // src/templates/afcfta.ts
1100
+ var AFCFTA_STATE_PARTIES = /* @__PURE__ */ new Set([
1101
+ "DZ",
1102
+ "AO",
1103
+ "BJ",
1104
+ "BW",
1105
+ "BF",
1106
+ "BI",
1107
+ "CV",
1108
+ "CM",
1109
+ "CF",
1110
+ "TD",
1111
+ "KM",
1112
+ "CG",
1113
+ "CD",
1114
+ "CI",
1115
+ "DJ",
1116
+ "EG",
1117
+ "GQ",
1118
+ "ER",
1119
+ "SZ",
1120
+ "ET",
1121
+ "GA",
1122
+ "GM",
1123
+ "GH",
1124
+ "GN",
1125
+ "GW",
1126
+ "KE",
1127
+ "LS",
1128
+ "LR",
1129
+ "LY",
1130
+ "MG",
1131
+ "MW",
1132
+ "ML",
1133
+ "MR",
1134
+ "MU",
1135
+ "MA",
1136
+ "MZ",
1137
+ "NA",
1138
+ "NE",
1139
+ "NG",
1140
+ "RW",
1141
+ "ST",
1142
+ "SN",
1143
+ "SC",
1144
+ "SL",
1145
+ "SO",
1146
+ "ZA",
1147
+ "SS",
1148
+ "SD",
1149
+ "TZ",
1150
+ "TG",
1151
+ "TN",
1152
+ "UG",
1153
+ "ZM",
1154
+ "ZW"
1155
+ ]);
1156
+ var MIN_LOCAL_VALUE_PERCENTAGE = 40;
1157
+ function isAfcftaStateParty(countryCode) {
1158
+ return AFCFTA_STATE_PARTIES.has(countryCode.toUpperCase());
1159
+ }
1160
+ function assessAfcfta(context) {
1161
+ const violations = [];
1162
+ if (!isAfcftaStateParty(context.originCountry)) {
1163
+ violations.push(`Origin country ${context.originCountry} is not an AfCFTA state party`);
1164
+ }
1165
+ if (!isAfcftaStateParty(context.destinationCountry)) {
1166
+ violations.push(`Destination country ${context.destinationCountry} is not an AfCFTA state party`);
1167
+ }
1168
+ if (!context.hasCertificateOfOrigin) {
1169
+ violations.push("Certificate of Origin not provided");
1170
+ }
1171
+ const originSatisfied = context.isWhollyObtained || context.tariffClassificationChanged || context.localValuePercentage >= MIN_LOCAL_VALUE_PERCENTAGE;
1172
+ if (!originSatisfied) {
1173
+ violations.push(
1174
+ `Rules of Origin not met: local value ${context.localValuePercentage}% below ${MIN_LOCAL_VALUE_PERCENTAGE}% minimum, no tariff classification change, and product is not wholly obtained`
1175
+ );
1176
+ }
1177
+ if (!context.isDirectShipment) {
1178
+ const hasUnapprovedTransit = (context.transitCountries ?? []).some(
1179
+ (c) => !isAfcftaStateParty(c)
1180
+ );
1181
+ if (hasUnapprovedTransit) {
1182
+ violations.push("Shipment transits through non-AfCFTA state party without approved exemption");
1183
+ }
1184
+ }
1185
+ const preferentialTariffEligible = originSatisfied && violations.length === 0;
1186
+ return {
1187
+ compliant: violations.length === 0,
1188
+ originSatisfied,
1189
+ preferentialTariffEligible,
1190
+ violations
1191
+ };
1192
+ }
1193
+ var AFCFTA_TEMPLATE = {
1194
+ name: "AFCFTA-ROO",
1195
+ description: "AfCFTA Rules of Origin for intra-African preferential trade",
1196
+ version: "1.0.0",
1197
+ jurisdiction: "AU",
1198
+ rules: [
1199
+ {
1200
+ id: "afcfta-certificate",
1201
+ name: "Certificate of Origin",
1202
+ description: "Valid Certificate of Origin from authorized body required",
1203
+ severity: "critical",
1204
+ enforcement: "block",
1205
+ condition: { field: "hasCertificateOfOrigin", equals: false },
1206
+ message: "AfCFTA: Certificate of Origin not provided"
1207
+ },
1208
+ {
1209
+ id: "afcfta-origin",
1210
+ name: "Rules of Origin",
1211
+ description: "Product must satisfy wholly obtained, CTC, or 40% value-added criterion",
1212
+ severity: "critical",
1213
+ enforcement: "block",
1214
+ condition: { field: "localValuePercentage", lessThan: 40 },
1215
+ message: "AfCFTA: Rules of Origin not satisfied"
1216
+ },
1217
+ {
1218
+ id: "afcfta-state-party",
1219
+ name: "State Party Requirement",
1220
+ description: "Both origin and destination must be AfCFTA state parties",
1221
+ severity: "critical",
1222
+ enforcement: "block",
1223
+ condition: { field: "originCountry", notAfcftaParty: true },
1224
+ message: "AfCFTA: Origin country is not a state party"
1225
+ },
1226
+ {
1227
+ id: "afcfta-direct-shipment",
1228
+ name: "Direct Shipment",
1229
+ description: "Goods must be shipped directly or through approved transit",
1230
+ severity: "high",
1231
+ enforcement: "block",
1232
+ condition: { field: "isDirectShipment", equals: false },
1233
+ message: "AfCFTA: Direct shipment rule not met"
1234
+ }
1235
+ ]
1236
+ };
1237
+
1238
+ // src/templates/index.ts
1239
+ var GHANA_TEMPLATES = {
1240
+ "COCOBOD-GRADING": "cocobod",
1241
+ "FIC-AML-1044": "fic-aml",
1242
+ "AFCFTA-ROO": "afcfta"
1243
+ };
1244
+ export {
1245
+ AFCFTA_TEMPLATE,
1246
+ BaselineError,
1247
+ BaselineGovernSystem,
1248
+ COCOBOD_TEMPLATE,
1249
+ ComplianceCache,
1250
+ ComplianceError,
1251
+ FIC_AML_TEMPLATE,
1252
+ GHANA_TEMPLATES,
1253
+ GovernError,
1254
+ GovernTelemetry,
1255
+ TemplateError,
1256
+ ValidationError,
1257
+ assessAfcfta,
1258
+ assessCocobodGrade,
1259
+ assessFicAml,
1260
+ isAfcftaStateParty,
1261
+ isBaselineError,
1262
+ toErrorResult
1263
+ };
1264
+ /**
1265
+ * Baseline Govern System
1266
+ *
1267
+ * Enterprise governance layer of the Baseline Protocol providing
1268
+ * policy, risk, permission, cost, and compliance governance.
1269
+ *
1270
+ * @license Apache-2.0
1271
+ */