@pylabmit/agent-cmdb 1.5.0 → 2.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/README.md +29 -4
- package/dist/brain.d.ts.map +1 -1
- package/dist/brain.js +119 -44
- package/dist/brain.js.map +1 -1
- package/dist/checkpoint.d.ts +6 -0
- package/dist/checkpoint.d.ts.map +1 -0
- package/dist/checkpoint.js +137 -0
- package/dist/checkpoint.js.map +1 -0
- package/dist/cli.js +162 -7
- package/dist/cli.js.map +1 -1
- package/dist/cost.d.ts +3 -0
- package/dist/cost.d.ts.map +1 -0
- package/dist/cost.js +49 -0
- package/dist/cost.js.map +1 -0
- package/dist/digest.d.ts +2 -1
- package/dist/digest.d.ts.map +1 -1
- package/dist/digest.js +18 -2
- package/dist/digest.js.map +1 -1
- package/dist/engine.d.ts +0 -2
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +0 -2
- package/dist/engine.js.map +1 -1
- package/dist/health.d.ts +9 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +222 -0
- package/dist/health.js.map +1 -0
- package/dist/interface.d.ts +15 -2
- package/dist/interface.d.ts.map +1 -1
- package/dist/interface.js +47 -3
- package/dist/interface.js.map +1 -1
- package/dist/internal.d.ts +3 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +3 -0
- package/dist/internal.js.map +1 -0
- package/dist/loader.js +54 -3
- package/dist/loader.js.map +1 -1
- package/dist/policy-engine.js +7 -7
- package/dist/policy-engine.js.map +1 -1
- package/dist/preflight.d.ts +5 -3
- package/dist/preflight.d.ts.map +1 -1
- package/dist/preflight.js +144 -20
- package/dist/preflight.js.map +1 -1
- package/dist/route-resolver.d.ts.map +1 -1
- package/dist/route-resolver.js +47 -6
- package/dist/route-resolver.js.map +1 -1
- package/dist/slo.d.ts +4 -0
- package/dist/slo.d.ts.map +1 -0
- package/dist/slo.js +147 -0
- package/dist/slo.js.map +1 -0
- package/dist/store.d.ts +10 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +165 -12
- package/dist/store.js.map +1 -1
- package/dist/types.d.ts +75 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -1
- package/dist/agent-preflight.d.ts +0 -6
- package/dist/agent-preflight.d.ts.map +0 -1
- package/dist/agent-preflight.js +0 -55
- package/dist/agent-preflight.js.map +0 -1
- package/dist/preflight-action.d.ts +0 -3
- package/dist/preflight-action.d.ts.map +0 -1
- package/dist/preflight-action.js +0 -101
- package/dist/preflight-action.js.map +0 -1
package/dist/preflight.js
CHANGED
|
@@ -1,36 +1,160 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { evaluatePolicy, normalizePolicyRequest } from './policy-engine.js';
|
|
2
|
+
import { inspectProfile, resolveSourceRoute } from './route-resolver.js';
|
|
3
|
+
import { isSourceAvailable, listSourceHealth } from './health.js';
|
|
4
|
+
import { updateSloCache } from './slo.js';
|
|
5
|
+
import { appendChange, appendEvidence } from './store.js';
|
|
6
|
+
export function evaluatePreflight(controlPlane, request, options = {}) {
|
|
7
|
+
const normalizedRequest = normalizePreflightRequest(request);
|
|
8
|
+
const decision = evaluatePolicy(controlPlane, normalizedRequest);
|
|
9
|
+
let finalDecision = decision;
|
|
10
|
+
let route;
|
|
11
|
+
const warnings = [];
|
|
12
|
+
if (normalizedRequest.intent) {
|
|
13
|
+
try {
|
|
14
|
+
route = resolveSourceRoute(controlPlane, {
|
|
15
|
+
profile: normalizedRequest.profile,
|
|
16
|
+
intent: normalizedRequest.intent,
|
|
17
|
+
freshness: normalizedRequest.freshness,
|
|
18
|
+
health: options.health
|
|
19
|
+
});
|
|
20
|
+
if (decision.effect === 'allow' && route.blockOnStale && route.staleSourceIds.length > 0) {
|
|
21
|
+
const reason = `Route contains stale sources and blockOnStale is enabled: ${route.staleSourceIds.join(', ')}.`;
|
|
22
|
+
warnings.push(reason);
|
|
23
|
+
finalDecision = denyDecision(normalizedRequest, 'stale-source-blocked', 'stale_source_blocked', reason, 'Refresh the source freshness snapshots or choose a fresh route.');
|
|
24
|
+
}
|
|
25
|
+
if (decision.effect === 'allow' && route.sources.length === 0 && route.skippedSources.length > 0) {
|
|
26
|
+
const reason = `All route sources are down: ${route.skippedSources.join(', ')}.`;
|
|
27
|
+
warnings.push(reason);
|
|
28
|
+
finalDecision = denyDecision(normalizedRequest, 'all-sources-down', 'all_sources_down', reason, 'Wait for source recovery or reset source health after manual verification.');
|
|
29
|
+
}
|
|
30
|
+
if (finalDecision.effect === 'allow'
|
|
31
|
+
&& normalizedRequest.tool
|
|
32
|
+
&& skippedSourcesIncludeTool(route.skippedSources, normalizedRequest.tool)) {
|
|
33
|
+
const reason = `Requested tool ${normalizedRequest.tool} is down.`;
|
|
34
|
+
warnings.push(reason);
|
|
35
|
+
finalDecision = denyDecision(normalizedRequest, 'requested-tool-down', 'requested_tool_down', reason, 'Use one of the returned route fallback sources instead of the down requested tool.');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
40
|
+
const reason = `Route resolution failed: ${message}`;
|
|
41
|
+
warnings.push(reason);
|
|
42
|
+
if (decision.effect === 'allow' || decision.effect === 'approval_required') {
|
|
43
|
+
finalDecision = denyDecision(normalizedRequest, 'route-resolution-failed', 'route_resolution_failed', reason, 'Fix the source route for this profile and intent before executing.');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const profile = inspectProfile(controlPlane, normalizedRequest.profile);
|
|
48
|
+
return {
|
|
49
|
+
allowed: finalDecision.effect === 'allow',
|
|
50
|
+
approvalRequired: finalDecision.effect === 'approval_required',
|
|
51
|
+
decision: finalDecision,
|
|
52
|
+
route,
|
|
53
|
+
routeExecutable: finalDecision.effect === 'allow' && Boolean(route),
|
|
54
|
+
guardrails: route?.guardrails ?? profile.guardrails,
|
|
55
|
+
warnings,
|
|
56
|
+
dryRun: Boolean(normalizedRequest.dryRun)
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export async function preflight(controlPlane, storeDir, request) {
|
|
60
|
+
await Promise.all(controlPlane.sources.map((source) => isSourceAvailable(controlPlane, storeDir, source.id)));
|
|
61
|
+
const health = await listSourceHealth(controlPlane, storeDir);
|
|
62
|
+
const result = evaluatePreflight(controlPlane, request, { health });
|
|
6
63
|
if (result.dryRun) {
|
|
7
64
|
return result;
|
|
8
65
|
}
|
|
9
|
-
if (result.
|
|
10
|
-
await
|
|
66
|
+
if (!result.allowed) {
|
|
67
|
+
await appendEvidence(storeDir, {
|
|
11
68
|
profile: result.decision.profile,
|
|
12
69
|
source: 'agent-cmdb-preflight',
|
|
13
70
|
intent: request.intent ?? result.decision.action,
|
|
14
|
-
summary: `Denied: ${result.decision.reason}`,
|
|
71
|
+
summary: `Denied by ${result.decision.ruleId}: ${result.decision.reason}`,
|
|
15
72
|
trust: 'high',
|
|
16
|
-
capturedAt:
|
|
17
|
-
|
|
73
|
+
capturedAt: new Date().toISOString(),
|
|
74
|
+
estimatedCost: estimateCost(controlPlane, result),
|
|
75
|
+
tags: ['preflight', 'deny', result.decision.ruleId]
|
|
18
76
|
});
|
|
19
77
|
}
|
|
20
|
-
await
|
|
21
|
-
target: result.decision.ruleId
|
|
78
|
+
await appendChange(storeDir, {
|
|
79
|
+
target: `policy.${result.decision.ruleId}`,
|
|
22
80
|
targetType: 'policy',
|
|
23
81
|
action: 'verify',
|
|
24
82
|
actor: 'agent-cmdb-preflight',
|
|
25
|
-
reason: `Preflight ${result.decision.effect} for ${result.decision.profile}
|
|
26
|
-
changedAt:
|
|
27
|
-
after:
|
|
28
|
-
allowed: result.allowed,
|
|
29
|
-
approvalRequired: result.approvalRequired,
|
|
30
|
-
routeExecutable: result.routeExecutable,
|
|
31
|
-
decision: result.decision
|
|
32
|
-
}
|
|
83
|
+
reason: `Preflight ${result.decision.effect} for ${result.decision.profile}:${result.decision.action}.`,
|
|
84
|
+
changedAt: new Date().toISOString(),
|
|
85
|
+
after: result
|
|
33
86
|
});
|
|
87
|
+
await updateSloCache(controlPlane, storeDir, result);
|
|
34
88
|
return result;
|
|
35
89
|
}
|
|
90
|
+
function normalizePreflightRequest(request) {
|
|
91
|
+
const normalizedPolicy = normalizePolicyRequest(request);
|
|
92
|
+
const record = requireRecord(request, 'Preflight request');
|
|
93
|
+
const intent = record.intent === undefined
|
|
94
|
+
? undefined
|
|
95
|
+
: requireNonEmptyString(record.intent, 'Preflight request intent', 'when provided');
|
|
96
|
+
const dryRun = record.dryRun === undefined ? undefined : requireBoolean(record.dryRun, 'Preflight request dryRun');
|
|
97
|
+
const freshness = normalizeFreshness(record.freshness);
|
|
98
|
+
return {
|
|
99
|
+
...normalizedPolicy,
|
|
100
|
+
intent,
|
|
101
|
+
dryRun,
|
|
102
|
+
freshness
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function denyDecision(request, ruleId, code, reason, suggestedAlternative) {
|
|
106
|
+
return {
|
|
107
|
+
effect: 'deny',
|
|
108
|
+
ruleId,
|
|
109
|
+
code,
|
|
110
|
+
reason,
|
|
111
|
+
profile: request.profile,
|
|
112
|
+
action: request.action,
|
|
113
|
+
tool: request.tool,
|
|
114
|
+
canEscalate: false,
|
|
115
|
+
suggestedAlternative
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function normalizeFreshness(value) {
|
|
119
|
+
if (value === undefined)
|
|
120
|
+
return undefined;
|
|
121
|
+
if (!Array.isArray(value)) {
|
|
122
|
+
throw new Error('Preflight request freshness must be an array.');
|
|
123
|
+
}
|
|
124
|
+
return value.map((entry) => {
|
|
125
|
+
const record = requireRecord(entry, 'Preflight freshness input');
|
|
126
|
+
return {
|
|
127
|
+
sourceId: requireNonEmptyString(record.sourceId, 'Preflight freshness sourceId'),
|
|
128
|
+
lastUpdated: requireNonEmptyString(record.lastUpdated, 'Preflight freshness lastUpdated')
|
|
129
|
+
};
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function requireBoolean(value, label) {
|
|
133
|
+
if (typeof value !== 'boolean') {
|
|
134
|
+
throw new Error(`${label} must be a boolean.`);
|
|
135
|
+
}
|
|
136
|
+
return value;
|
|
137
|
+
}
|
|
138
|
+
function requireRecord(value, label) {
|
|
139
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
140
|
+
throw new Error(`${label} must be an object.`);
|
|
141
|
+
}
|
|
142
|
+
return value;
|
|
143
|
+
}
|
|
144
|
+
function requireNonEmptyString(value, label, suffix) {
|
|
145
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
146
|
+
const suffixText = suffix ? ` ${suffix}` : '';
|
|
147
|
+
throw new Error(`${label} must be a non-empty string${suffixText}.`);
|
|
148
|
+
}
|
|
149
|
+
return value;
|
|
150
|
+
}
|
|
151
|
+
function estimateCost(controlPlane, result) {
|
|
152
|
+
const sourceId = result.decision.tool ?? result.route?.sources[0]?.id;
|
|
153
|
+
if (!sourceId)
|
|
154
|
+
return 0;
|
|
155
|
+
return controlPlane.sources.find((source) => source.id === sourceId)?.costPerCall ?? 0;
|
|
156
|
+
}
|
|
157
|
+
function skippedSourcesIncludeTool(skippedSources, tool) {
|
|
158
|
+
return skippedSources.includes(tool) || skippedSources.includes(`source.${tool}`) || skippedSources.includes(`tool.${tool}`);
|
|
159
|
+
}
|
|
36
160
|
//# sourceMappingURL=preflight.js.map
|
package/dist/preflight.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preflight.js","sourceRoot":"","sources":["../src/preflight.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"preflight.js","sourceRoot":"","sources":["../src/preflight.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-resolver.d.ts","sourceRoot":"","sources":["../src/route-resolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EAGnB,SAAS,EACT,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAEpB,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,kBAAkB,GAC1B,mBAAmB,
|
|
1
|
+
{"version":3,"file":"route-resolver.d.ts","sourceRoot":"","sources":["../src/route-resolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EAGnB,SAAS,EACT,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAEpB,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,kBAAkB,GAC1B,mBAAmB,CA+BrB;AAED,wBAAgB,cAAc,CAAC,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,iBAAiB,CAe/F;AAED,wBAAgB,aAAa,CAAC,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,CAMzF;AAED,wBAAgB,YAAY,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,CAMpF"}
|
package/dist/route-resolver.js
CHANGED
|
@@ -6,13 +6,21 @@ export function resolveSourceRoute(controlPlane, request) {
|
|
|
6
6
|
if (!route) {
|
|
7
7
|
throw new Error(`No source route configured for profile ${normalizedRequest.profile} and intent ${normalizedRequest.intent}.`);
|
|
8
8
|
}
|
|
9
|
+
const healthBySource = new Map((normalizedRequest.health ?? []).map((health) => [health.sourceId, health]));
|
|
10
|
+
const routeSources = route.sources.map((sourceId) => ensureSource(controlPlane, sourceId));
|
|
11
|
+
const sources = routeSources.filter((source) => healthBySource.get(source.id)?.status !== 'down');
|
|
12
|
+
const skippedSources = routeSources
|
|
13
|
+
.filter((source) => healthBySource.get(source.id)?.status === 'down')
|
|
14
|
+
.map((source) => source.id);
|
|
9
15
|
return {
|
|
10
16
|
profile: profile.id,
|
|
11
17
|
intent: normalizedRequest.intent,
|
|
12
|
-
sources
|
|
18
|
+
sources,
|
|
19
|
+
skippedSources,
|
|
13
20
|
guardrails: profile.guardrails,
|
|
14
21
|
notes: route.notes,
|
|
15
|
-
|
|
22
|
+
blockOnStale: Boolean(route.blockOnStale),
|
|
23
|
+
...resolveFreshness(sources, normalizedRequest.freshness)
|
|
16
24
|
};
|
|
17
25
|
}
|
|
18
26
|
export function inspectProfile(controlPlane, profileId) {
|
|
@@ -25,7 +33,8 @@ export function inspectProfile(controlPlane, profileId) {
|
|
|
25
33
|
routes: profile.routes.map((route) => ({
|
|
26
34
|
intent: route.intent,
|
|
27
35
|
sources: [...route.sources],
|
|
28
|
-
notes: route.notes
|
|
36
|
+
notes: route.notes,
|
|
37
|
+
blockOnStale: route.blockOnStale
|
|
29
38
|
}))
|
|
30
39
|
};
|
|
31
40
|
}
|
|
@@ -49,10 +58,36 @@ function normalizeSourceRouteRequest(request) {
|
|
|
49
58
|
profile: requireNonEmptyString(record.profile, 'Source route request profile'),
|
|
50
59
|
intent: requireNonEmptyString(record.intent, 'Source route request intent'),
|
|
51
60
|
freshness: normalizeFreshness(record.freshness),
|
|
52
|
-
|
|
61
|
+
health: normalizeHealth(record.health)
|
|
53
62
|
};
|
|
54
63
|
}
|
|
55
|
-
function
|
|
64
|
+
function normalizeHealth(value) {
|
|
65
|
+
if (value === undefined)
|
|
66
|
+
return undefined;
|
|
67
|
+
if (!Array.isArray(value)) {
|
|
68
|
+
throw new Error('Source route request health must be an array.');
|
|
69
|
+
}
|
|
70
|
+
return value.map((entry) => {
|
|
71
|
+
const record = requireRecord(entry, 'Source health input');
|
|
72
|
+
const status = requireNonEmptyString(record.status, 'Source health status');
|
|
73
|
+
if (!['up', 'down', 'half-open'].includes(status)) {
|
|
74
|
+
throw new Error(`Source health status must be one of: up, down, half-open.`);
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
sourceId: requireNonEmptyString(record.sourceId, 'Source health sourceId'),
|
|
78
|
+
status: status,
|
|
79
|
+
consecutiveFailures: readNonNegativeNumber(record.consecutiveFailures, 'Source health consecutiveFailures'),
|
|
80
|
+
lastChecked: requireNonEmptyString(record.lastChecked, 'Source health lastChecked'),
|
|
81
|
+
lastFailure: record.lastFailure === undefined
|
|
82
|
+
? undefined
|
|
83
|
+
: requireNonEmptyString(record.lastFailure, 'Source health lastFailure'),
|
|
84
|
+
lastSuccess: record.lastSuccess === undefined
|
|
85
|
+
? undefined
|
|
86
|
+
: requireNonEmptyString(record.lastSuccess, 'Source health lastSuccess')
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function resolveFreshness(sources, freshness) {
|
|
56
91
|
if (!freshness || freshness.length === 0) {
|
|
57
92
|
return {
|
|
58
93
|
staleSourceIds: [],
|
|
@@ -60,7 +95,7 @@ function resolveFreshness(sources, freshness, nowInput) {
|
|
|
60
95
|
};
|
|
61
96
|
}
|
|
62
97
|
const bySource = new Map(freshness.map((entry) => [entry.sourceId, entry]));
|
|
63
|
-
const now =
|
|
98
|
+
const now = Date.now();
|
|
64
99
|
const statuses = sources
|
|
65
100
|
.filter((source) => source.freshnessTtl)
|
|
66
101
|
.map((source) => {
|
|
@@ -127,4 +162,10 @@ function requireNonEmptyString(value, label) {
|
|
|
127
162
|
}
|
|
128
163
|
return value;
|
|
129
164
|
}
|
|
165
|
+
function readNonNegativeNumber(value, label) {
|
|
166
|
+
if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {
|
|
167
|
+
throw new Error(`${label} must be a non-negative number.`);
|
|
168
|
+
}
|
|
169
|
+
return value;
|
|
170
|
+
}
|
|
130
171
|
//# sourceMappingURL=route-resolver.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-resolver.js","sourceRoot":"","sources":["../src/route-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAY9C,MAAM,UAAU,kBAAkB,CAChC,YAA0B,EAC1B,OAA2B;IAE3B,MAAM,iBAAiB,GAAG,2BAA2B,CAAC,OAAO,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,aAAa,CAAC,YAAY,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACvE,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,KAAK,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAEhG,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,0CAA0C,iBAAiB,CAAC,OAAO,eAAe,iBAAiB,CAAC,MAAM,GAAG,CAC9G,CAAC;IACJ,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"route-resolver.js","sourceRoot":"","sources":["../src/route-resolver.ts"],"names":[],"mappings":"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"}
|
package/dist/slo.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ControlPlane, PreflightResult, SloResult } from './types.js';
|
|
2
|
+
export declare function updateSloCache(controlPlane: ControlPlane, storeDir: string, result: PreflightResult): Promise<void>;
|
|
3
|
+
export declare function calculateSlo(controlPlane: ControlPlane, storeDir: string, profileId: string): Promise<SloResult>;
|
|
4
|
+
//# sourceMappingURL=slo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slo.d.ts","sourceRoot":"","sources":["../src/slo.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAa,SAAS,EAAE,MAAM,YAAY,CAAC;AAiBtF,wBAAsB,cAAc,CAClC,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED,wBAAsB,YAAY,CAChC,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,SAAS,CAAC,CAwDpB"}
|
package/dist/slo.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { readJsonState, writeJsonState } from './store.js';
|
|
2
|
+
export async function updateSloCache(controlPlane, storeDir, result) {
|
|
3
|
+
const profile = controlPlane.profiles.find((candidate) => candidate.id === result.decision.profile);
|
|
4
|
+
if (!profile?.slo)
|
|
5
|
+
return;
|
|
6
|
+
const now = new Date();
|
|
7
|
+
const cache = await readSloCache(storeDir, profile.id);
|
|
8
|
+
const windowStartMs = now.getTime() - profile.slo.windowHours * 60 * 60 * 1000;
|
|
9
|
+
const bucketStart = hourBucket(now);
|
|
10
|
+
const buckets = cache.buckets.filter((bucket) => Date.parse(bucket.bucketStart) >= windowStartMs);
|
|
11
|
+
const bucket = buckets.find((candidate) => candidate.bucketStart === bucketStart);
|
|
12
|
+
const nextBucket = bucket ?? { bucketStart, total: 0, allowed: 0, denied: 0 };
|
|
13
|
+
nextBucket.total += 1;
|
|
14
|
+
if (result.allowed) {
|
|
15
|
+
nextBucket.allowed += 1;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
nextBucket.denied += 1;
|
|
19
|
+
}
|
|
20
|
+
if (!bucket)
|
|
21
|
+
buckets.push(nextBucket);
|
|
22
|
+
await writeSloCache(storeDir, {
|
|
23
|
+
profile: profile.id,
|
|
24
|
+
metric: profile.slo.metric,
|
|
25
|
+
buckets: buckets.sort((left, right) => left.bucketStart.localeCompare(right.bucketStart)),
|
|
26
|
+
lastUpdated: now.toISOString()
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export async function calculateSlo(controlPlane, storeDir, profileId) {
|
|
30
|
+
const profile = controlPlane.profiles.find((candidate) => candidate.id === profileId);
|
|
31
|
+
if (!profile) {
|
|
32
|
+
throw new Error(`Unknown profile: ${profileId}.`);
|
|
33
|
+
}
|
|
34
|
+
const config = profile.slo ?? {
|
|
35
|
+
target: 1,
|
|
36
|
+
windowHours: 24,
|
|
37
|
+
metric: 'allow_rate'
|
|
38
|
+
};
|
|
39
|
+
const now = new Date();
|
|
40
|
+
const windowStartMs = now.getTime() - config.windowHours * 60 * 60 * 1000;
|
|
41
|
+
const cache = await readSloCache(storeDir, profile.id);
|
|
42
|
+
const bucketWarnings = cache.buckets
|
|
43
|
+
.filter((bucket) => bucket.total !== bucket.allowed + bucket.denied)
|
|
44
|
+
.map((bucket) => `SLO cache bucket ${bucket.bucketStart} has inconsistent totals.`);
|
|
45
|
+
const warnings = [...(cache.warnings ?? []), ...bucketWarnings];
|
|
46
|
+
if (warnings.length > 0) {
|
|
47
|
+
return {
|
|
48
|
+
profile: profile.id,
|
|
49
|
+
target: config.target,
|
|
50
|
+
actual: 0,
|
|
51
|
+
withinBudget: false,
|
|
52
|
+
errorBudgetRemaining: 0,
|
|
53
|
+
totalDecisions: 0,
|
|
54
|
+
allowedCount: 0,
|
|
55
|
+
deniedCount: 0,
|
|
56
|
+
windowStart: new Date(windowStartMs).toISOString(),
|
|
57
|
+
windowEnd: now.toISOString(),
|
|
58
|
+
warnings
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const buckets = cache.buckets.filter((bucket) => Date.parse(bucket.bucketStart) >= windowStartMs);
|
|
62
|
+
const totalDecisions = buckets.reduce((sum, bucket) => sum + bucket.total, 0);
|
|
63
|
+
const allowedCount = buckets.reduce((sum, bucket) => sum + bucket.allowed, 0);
|
|
64
|
+
const deniedCount = buckets.reduce((sum, bucket) => sum + bucket.denied, 0);
|
|
65
|
+
const actual = totalDecisions === 0 ? 1 : allowedCount / totalDecisions;
|
|
66
|
+
const allowedErrorRate = totalDecisions === 0 ? 0 : deniedCount / totalDecisions;
|
|
67
|
+
const errorBudget = 1 - config.target;
|
|
68
|
+
const errorBudgetRemaining = Math.max(0, errorBudget - allowedErrorRate);
|
|
69
|
+
return {
|
|
70
|
+
profile: profile.id,
|
|
71
|
+
target: config.target,
|
|
72
|
+
actual,
|
|
73
|
+
withinBudget: actual >= config.target,
|
|
74
|
+
errorBudgetRemaining,
|
|
75
|
+
totalDecisions,
|
|
76
|
+
allowedCount,
|
|
77
|
+
deniedCount,
|
|
78
|
+
windowStart: new Date(windowStartMs).toISOString(),
|
|
79
|
+
windowEnd: now.toISOString()
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async function readSloCache(storeDir, profile) {
|
|
83
|
+
return readJsonState(storeDir, cachePath(profile), { profile, metric: 'allow_rate', buckets: [], lastUpdated: new Date(0).toISOString() }, parseSloCache);
|
|
84
|
+
}
|
|
85
|
+
async function writeSloCache(storeDir, cache) {
|
|
86
|
+
await writeJsonState(storeDir, cachePath(cache.profile), cache, parseSloCache);
|
|
87
|
+
}
|
|
88
|
+
function cachePath(profile) {
|
|
89
|
+
return `slo-cache/${safeSegment(profile)}.json`;
|
|
90
|
+
}
|
|
91
|
+
function hourBucket(date) {
|
|
92
|
+
const bucket = new Date(date);
|
|
93
|
+
bucket.setUTCMinutes(0, 0, 0);
|
|
94
|
+
return bucket.toISOString();
|
|
95
|
+
}
|
|
96
|
+
function safeSegment(value) {
|
|
97
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(value)) {
|
|
98
|
+
throw new Error('SLO profile must be a safe filename segment.');
|
|
99
|
+
}
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
function parseSloCache(value) {
|
|
103
|
+
const record = requireRecord(value, 'SLO cache');
|
|
104
|
+
const metric = readString(record, 'metric', 'SLO metric');
|
|
105
|
+
if (metric !== 'allow_rate') {
|
|
106
|
+
throw new Error('SLO metric must be allow_rate.');
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
profile: safeSegment(readString(record, 'profile', 'SLO profile')),
|
|
110
|
+
metric,
|
|
111
|
+
buckets: Array.isArray(record.buckets) ? record.buckets.map(parseBucket) : [],
|
|
112
|
+
lastUpdated: readString(record, 'lastUpdated', 'SLO lastUpdated'),
|
|
113
|
+
warnings: Array.isArray(record.warnings)
|
|
114
|
+
? record.warnings.filter((warning) => typeof warning === 'string')
|
|
115
|
+
: undefined
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function parseBucket(value) {
|
|
119
|
+
const record = requireRecord(value, 'SLO bucket');
|
|
120
|
+
return {
|
|
121
|
+
bucketStart: readString(record, 'bucketStart', 'SLO bucketStart'),
|
|
122
|
+
total: readNumber(record, 'total', 'SLO bucket total'),
|
|
123
|
+
allowed: readNumber(record, 'allowed', 'SLO bucket allowed'),
|
|
124
|
+
denied: readNumber(record, 'denied', 'SLO bucket denied')
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function requireRecord(value, label) {
|
|
128
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
129
|
+
throw new Error(`${label} must be an object.`);
|
|
130
|
+
}
|
|
131
|
+
return value;
|
|
132
|
+
}
|
|
133
|
+
function readString(record, key, label) {
|
|
134
|
+
const value = record[key];
|
|
135
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
136
|
+
throw new Error(`${label} must be a non-empty string.`);
|
|
137
|
+
}
|
|
138
|
+
return value;
|
|
139
|
+
}
|
|
140
|
+
function readNumber(record, key, label) {
|
|
141
|
+
const value = record[key];
|
|
142
|
+
if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {
|
|
143
|
+
throw new Error(`${label} must be a non-negative number.`);
|
|
144
|
+
}
|
|
145
|
+
return value;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=slo.js.map
|
package/dist/slo.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slo.js","sourceRoot":"","sources":["../src/slo.ts"],"names":[],"mappings":"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"}
|
package/dist/store.d.ts
CHANGED
|
@@ -9,7 +9,17 @@ export declare function appendEvidence(storeDir: string, input: EvidenceInput):
|
|
|
9
9
|
export declare function listEvidence(storeDir: string, query?: EvidenceQuery): Promise<EvidenceRecord[]>;
|
|
10
10
|
export declare function appendChange(storeDir: string, input: ChangeInput): Promise<ChangeRecord>;
|
|
11
11
|
export declare function listChanges(storeDir: string, query?: ChangeQuery): Promise<ChangeRecord[]>;
|
|
12
|
+
export declare function readJsonState<T extends object>(storeDir: string, relativePath: string, fallback: T, parse: (value: unknown) => T): Promise<T & {
|
|
13
|
+
prevHash: string;
|
|
14
|
+
warnings?: string[];
|
|
15
|
+
}>;
|
|
16
|
+
export declare function writeJsonState<T extends object>(storeDir: string, relativePath: string, payload: T, parse?: (value: unknown) => T): Promise<T & {
|
|
17
|
+
prevHash: string;
|
|
18
|
+
}>;
|
|
19
|
+
export declare function deleteJsonState(storeDir: string, relativePath: string): Promise<void>;
|
|
20
|
+
export declare function listJsonStateFiles(storeDir: string, relativeDir: string): Promise<string[]>;
|
|
12
21
|
export declare function sanitizeText(value: string, options?: {
|
|
13
22
|
preserveLineBreaks?: boolean;
|
|
14
23
|
}): string;
|
|
24
|
+
export declare function detectInjectionWarnings(value: string): string[];
|
|
15
25
|
//# sourceMappingURL=store.d.ts.map
|
package/dist/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,WAAW,EAEX,WAAW,EACX,YAAY,EACZ,aAAa,EACb,aAAa,EACb,cAAc,EAGf,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,WAAW,EAEX,WAAW,EACX,YAAY,EACZ,aAAa,EACb,aAAa,EACb,cAAc,EAGf,MAAM,YAAY,CAAC;AAYpB,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAIjE;AAED,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAI/D;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAkBpG;AAED,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,GAAE,aAAkB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAYzG;AAED,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAgB9F;AAED,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,GAAE,WAAgB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAWpG;AAED,wBAAsB,aAAa,CAAC,CAAC,SAAS,MAAM,EAClD,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,CAAC,EACX,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC,GAC3B,OAAO,CAAC,CAAC,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAuCxD;AAED,wBAAsB,cAAc,CAAC,CAAC,SAAS,MAAM,EACnD,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,CAAC,EACV,KAAK,GAAE,CAAC,KAAK,EAAE,OAAO,KAAK,CAAyB,GACnD,OAAO,CAAC,CAAC,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAMnC;AAED,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3F;AAED,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAOjG;AA4GD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAclG;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAU/D"}
|