@aduek/ne-sy 0.1.0-alpha.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 +92 -0
- package/dist/adapters.d.ts +13 -0
- package/dist/adapters.d.ts.map +1 -0
- package/dist/adapters.js +20 -0
- package/dist/audit.d.ts +14 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +129 -0
- package/dist/capabilities.d.ts +10 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +89 -0
- package/dist/evidence.d.ts +19 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +48 -0
- package/dist/hubspot.d.ts +59 -0
- package/dist/hubspot.d.ts.map +1 -0
- package/dist/hubspot.js +175 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/ir.d.ts +104 -0
- package/dist/ir.d.ts.map +1 -0
- package/dist/ir.js +859 -0
- package/dist/metering.d.ts +53 -0
- package/dist/metering.d.ts.map +1 -0
- package/dist/metering.js +224 -0
- package/dist/openaiAgents.d.ts +29 -0
- package/dist/openaiAgents.d.ts.map +1 -0
- package/dist/openaiAgents.js +81 -0
- package/dist/policy.d.ts +12 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +362 -0
- package/dist/types.d.ts +112 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +71 -0
- package/dist/utils.d.ts +13 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +51 -0
- package/dist/validation.d.ts +14 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +226 -0
- package/dist/verifier.d.ts +13 -0
- package/dist/verifier.d.ts.map +1 -0
- package/dist/verifier.js +69 -0
- package/package.json +60 -0
package/dist/policy.js
ADDED
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { DECISION_RANK, PolicyEvaluationError, errorCategoryForCode, isDecisionValue, } from "./types.js";
|
|
3
|
+
import { analyzePolicyIr, hashPolicyIr, normalizePolicyPack as normalizePolicyPackIr, } from "./ir.js";
|
|
4
|
+
import { compactRecord, compareStrings, getDotted, isPolicyPackInput, isRecord, makeDecision, stableValue, } from "./utils.js";
|
|
5
|
+
import { validatePolicyPackSchema } from "./validation.js";
|
|
6
|
+
export const POLICY_HASH_ALGORITHM = "sha256";
|
|
7
|
+
export function analyzePolicies(policyInput) {
|
|
8
|
+
const findings = [];
|
|
9
|
+
const pack = normalizePolicyPackForAnalysis(policyInput, findings);
|
|
10
|
+
const policyIr = normalizePolicyPackIr(policyInput);
|
|
11
|
+
const policies = policyIr.policies;
|
|
12
|
+
if (policyInput !== undefined && isPolicyPackInput(policyInput)) {
|
|
13
|
+
if (policyIr.id === undefined || policyIr.id === null) {
|
|
14
|
+
findings.push({
|
|
15
|
+
severity: "error",
|
|
16
|
+
code: "missing_policy_pack_id",
|
|
17
|
+
message: "Policy pack must declare id.",
|
|
18
|
+
policyIds: [],
|
|
19
|
+
field: "id",
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
if (policyIr.version === undefined || policyIr.version === null) {
|
|
23
|
+
findings.push({
|
|
24
|
+
severity: "error",
|
|
25
|
+
code: "missing_policy_version",
|
|
26
|
+
message: "Policy pack must declare version.",
|
|
27
|
+
policyIds: [],
|
|
28
|
+
field: "version",
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
if (!pack.hasExplicitDefault) {
|
|
32
|
+
findings.push({
|
|
33
|
+
severity: "error",
|
|
34
|
+
code: "missing_default_decision",
|
|
35
|
+
message: "Policy pack must declare defaultDecision.",
|
|
36
|
+
policyIds: [],
|
|
37
|
+
field: "defaultDecision",
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (!isDecisionValue(policyIr.defaultDecision)) {
|
|
41
|
+
findings.push({
|
|
42
|
+
severity: "error",
|
|
43
|
+
code: "unsupported_default_decision",
|
|
44
|
+
message: `Policy pack has unsupported defaultDecision: ${String(policyIr.defaultDecision)}`,
|
|
45
|
+
policyIds: [],
|
|
46
|
+
field: "defaultDecision",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
findings.push(...analyzePolicyIr(policyIr));
|
|
51
|
+
if (policies.length === 0) {
|
|
52
|
+
findings.push({
|
|
53
|
+
severity: "warning",
|
|
54
|
+
code: "empty_policy_pack",
|
|
55
|
+
message: "Policy pack contains no policies.",
|
|
56
|
+
policyIds: [],
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
const hasDefaultAllow = pack.hasExplicitDefault && pack.defaultDecision === "allow";
|
|
60
|
+
if (policies.length > 0 &&
|
|
61
|
+
!policies.some((policy) => policy.effect === "allow") &&
|
|
62
|
+
!hasDefaultAllow) {
|
|
63
|
+
findings.push({
|
|
64
|
+
severity: "warning",
|
|
65
|
+
code: "missing_explicit_allow",
|
|
66
|
+
message: "Policy pack has no explicit allow policy or allow default.",
|
|
67
|
+
policyIds: [],
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
const summary = {
|
|
71
|
+
policyPackId: pack.id,
|
|
72
|
+
policyVersion: pack.version,
|
|
73
|
+
defaultDecision: policyIr.defaultDecision,
|
|
74
|
+
hasExplicitDefault: pack.hasExplicitDefault,
|
|
75
|
+
policyCount: policies.length,
|
|
76
|
+
policyIrHash: hashPolicyIr(policyIr),
|
|
77
|
+
findingCount: findings.length,
|
|
78
|
+
errorCount: findings.filter((finding) => finding.severity === "error").length,
|
|
79
|
+
warningCount: findings.filter((finding) => finding.severity === "warning").length,
|
|
80
|
+
infoCount: findings.filter((finding) => finding.severity === "info").length,
|
|
81
|
+
};
|
|
82
|
+
const categorizedFindings = findings.map(categorizeFinding);
|
|
83
|
+
return {
|
|
84
|
+
summary,
|
|
85
|
+
findings: categorizedFindings,
|
|
86
|
+
hasErrors: summary.errorCount > 0,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
export function validatePolicyPack(policyInput) {
|
|
90
|
+
const schemaErrors = validatePolicyPackSchema(policyInput);
|
|
91
|
+
const semanticErrors = analyzePolicies(policyInput).findings
|
|
92
|
+
.filter((finding) => finding.severity === "error")
|
|
93
|
+
.map((finding) => `${finding.code}: ${finding.message}`);
|
|
94
|
+
return [...schemaErrors, ...semanticErrors];
|
|
95
|
+
}
|
|
96
|
+
export function assertValidPolicyPack(policyInput) {
|
|
97
|
+
const errors = validatePolicyPack(policyInput);
|
|
98
|
+
if (errors.length > 0) {
|
|
99
|
+
const { category, code } = classifyValidationErrors(errors);
|
|
100
|
+
throw new PolicyEvaluationError(errors.join("; "), { category, code });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export function evaluatePolicies(agent, action, context, policyInput) {
|
|
104
|
+
if (policyInput === undefined) {
|
|
105
|
+
return makeDecision({
|
|
106
|
+
decision: "review",
|
|
107
|
+
reason: "No policies were configured for verification.",
|
|
108
|
+
matchedPolicyIds: [],
|
|
109
|
+
metadata: { enforcementSource: "no_policy", failClosed: true },
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
assertValidPolicyPack(policyInput);
|
|
113
|
+
const pack = normalizePolicyPack(policyInput);
|
|
114
|
+
const scope = { agent, action, context };
|
|
115
|
+
const matched = pack.policies.filter((policy) => matchesPolicy(policy, scope));
|
|
116
|
+
if (matched.length === 0) {
|
|
117
|
+
return defaultDecision(pack, policyInput);
|
|
118
|
+
}
|
|
119
|
+
const selected = matched.reduce((current, next) => {
|
|
120
|
+
return DECISION_RANK[next.effect] > DECISION_RANK[current.effect] ? next : current;
|
|
121
|
+
});
|
|
122
|
+
return makeDecision({
|
|
123
|
+
decision: selected.effect,
|
|
124
|
+
reason: selected.reason || selected.description || "Policy matched.",
|
|
125
|
+
matchedPolicyIds: matched.map((policy) => policy.id),
|
|
126
|
+
metadata: compactRecord({
|
|
127
|
+
enforcementSource: "matched_policy",
|
|
128
|
+
matchedPolicyCount: matched.length,
|
|
129
|
+
selectedPolicyId: selected.id,
|
|
130
|
+
policyPackId: pack.id,
|
|
131
|
+
policyVersion: pack.version,
|
|
132
|
+
policyHash: policyHash(policyInput),
|
|
133
|
+
...(selected.metadata ?? {}),
|
|
134
|
+
}),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
export function policyVersion(policyInput) {
|
|
138
|
+
if (policyInput && !Array.isArray(policyInput) && isPolicyPackInput(policyInput)) {
|
|
139
|
+
return policyInput.version;
|
|
140
|
+
}
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
export function policyPackId(policyInput) {
|
|
144
|
+
if (policyInput && !Array.isArray(policyInput) && isPolicyPackInput(policyInput)) {
|
|
145
|
+
return policyInput.id;
|
|
146
|
+
}
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
export function policyHash(policyInput) {
|
|
150
|
+
if (policyInput === undefined)
|
|
151
|
+
return undefined;
|
|
152
|
+
return hashPolicyPack(policyInput);
|
|
153
|
+
}
|
|
154
|
+
export function canonicalPolicyJson(policyInput) {
|
|
155
|
+
return JSON.stringify(stableValue(policyInput));
|
|
156
|
+
}
|
|
157
|
+
export function hashPolicyPack(policyInput) {
|
|
158
|
+
return createHash(POLICY_HASH_ALGORITHM)
|
|
159
|
+
.update(canonicalPolicyJson(policyInput), "utf8")
|
|
160
|
+
.digest("hex");
|
|
161
|
+
}
|
|
162
|
+
function defaultDecision(pack, policyInput) {
|
|
163
|
+
if (!isDecisionValue(pack.defaultDecision)) {
|
|
164
|
+
throw new PolicyEvaluationError(`Unknown default decision: ${pack.defaultDecision}`);
|
|
165
|
+
}
|
|
166
|
+
return makeDecision({
|
|
167
|
+
decision: pack.defaultDecision,
|
|
168
|
+
reason: pack.defaultReason,
|
|
169
|
+
matchedPolicyIds: [],
|
|
170
|
+
metadata: compactRecord({
|
|
171
|
+
enforcementSource: "policy_pack_default",
|
|
172
|
+
defaultDecision: pack.defaultDecision,
|
|
173
|
+
policyPackId: pack.id,
|
|
174
|
+
policyVersion: pack.version,
|
|
175
|
+
policyHash: policyHash(policyInput),
|
|
176
|
+
}),
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
function normalizePolicyPack(policyInput) {
|
|
180
|
+
if (policyInput === undefined) {
|
|
181
|
+
return {
|
|
182
|
+
defaultDecision: "review",
|
|
183
|
+
defaultReason: "No policies were configured for verification.",
|
|
184
|
+
hasExplicitDefault: true,
|
|
185
|
+
policies: [],
|
|
186
|
+
raw: undefined,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
if (Array.isArray(policyInput)) {
|
|
190
|
+
return {
|
|
191
|
+
defaultDecision: "allow",
|
|
192
|
+
defaultReason: "No policy matched; action allowed by default.",
|
|
193
|
+
hasExplicitDefault: false,
|
|
194
|
+
policies: policyInput,
|
|
195
|
+
raw: policyInput,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (isPolicyPackInput(policyInput)) {
|
|
199
|
+
const defaultDecisionValue = String(policyInput.defaultDecision ?? "allow");
|
|
200
|
+
return {
|
|
201
|
+
id: policyInput.id,
|
|
202
|
+
version: policyInput.version,
|
|
203
|
+
defaultDecision: defaultDecisionValue,
|
|
204
|
+
defaultReason: policyInput.defaultReason ??
|
|
205
|
+
`No policy matched; default decision \`${defaultDecisionValue}\` applied.`,
|
|
206
|
+
hasExplicitDefault: policyInput.defaultDecision !== undefined,
|
|
207
|
+
policies: Array.isArray(policyInput.policies) ? policyInput.policies : [],
|
|
208
|
+
raw: policyInput,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
defaultDecision: "allow",
|
|
213
|
+
defaultReason: "No policy matched; action allowed by default.",
|
|
214
|
+
hasExplicitDefault: false,
|
|
215
|
+
policies: [policyInput],
|
|
216
|
+
raw: policyInput,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function normalizePolicyPackForAnalysis(policyInput, findings) {
|
|
220
|
+
try {
|
|
221
|
+
return normalizePolicyPack(policyInput);
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
findings.push({
|
|
225
|
+
severity: "error",
|
|
226
|
+
code: "malformed_policy_pack",
|
|
227
|
+
message: error instanceof Error ? error.message : String(error),
|
|
228
|
+
policyIds: [],
|
|
229
|
+
});
|
|
230
|
+
return {
|
|
231
|
+
defaultDecision: "allow",
|
|
232
|
+
defaultReason: "No policy matched; action allowed by default.",
|
|
233
|
+
hasExplicitDefault: false,
|
|
234
|
+
policies: [],
|
|
235
|
+
raw: undefined,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function categorizeFinding(finding) {
|
|
240
|
+
return {
|
|
241
|
+
...finding,
|
|
242
|
+
errorCategory: finding.errorCategory ?? errorCategoryForCode(finding.code),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function classifyValidationErrors(errors) {
|
|
246
|
+
const codes = errors
|
|
247
|
+
.filter((error) => error.includes(":"))
|
|
248
|
+
.map((error) => error.split(":", 1)[0]);
|
|
249
|
+
if (errors.some((error) => error.startsWith("schema_validation_error"))) {
|
|
250
|
+
return { category: "validation_error", code: "policy_validation_error" };
|
|
251
|
+
}
|
|
252
|
+
for (const preferred of ["malformed_policy", "unsupported_policy_construct", "validation_error"]) {
|
|
253
|
+
for (const code of codes) {
|
|
254
|
+
const category = errorCategoryForCode(code);
|
|
255
|
+
if (category === preferred)
|
|
256
|
+
return { category, code };
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return { category: "evaluation_error", code: "policy_evaluation_error" };
|
|
260
|
+
}
|
|
261
|
+
function matchesPolicy(policy, scope) {
|
|
262
|
+
if (!policy.conditions)
|
|
263
|
+
return true;
|
|
264
|
+
return evaluateCondition(policy.conditions, scope);
|
|
265
|
+
}
|
|
266
|
+
function evaluateCondition(condition, scope) {
|
|
267
|
+
if ("all" in condition) {
|
|
268
|
+
return condition.all.every((item) => evaluateCondition(item, scope));
|
|
269
|
+
}
|
|
270
|
+
if ("any" in condition) {
|
|
271
|
+
return condition.any.some((item) => evaluateCondition(item, scope));
|
|
272
|
+
}
|
|
273
|
+
const actual = getDotted(scope, condition.field);
|
|
274
|
+
switch (condition.operator) {
|
|
275
|
+
case "equals":
|
|
276
|
+
return actual === condition.value;
|
|
277
|
+
case "not_equals":
|
|
278
|
+
return actual !== condition.value;
|
|
279
|
+
case "greater_than":
|
|
280
|
+
return Number(actual) > Number(condition.value);
|
|
281
|
+
case "less_than":
|
|
282
|
+
return Number(actual) < Number(condition.value);
|
|
283
|
+
case "in":
|
|
284
|
+
return Array.isArray(condition.value) && condition.value.includes(actual);
|
|
285
|
+
default:
|
|
286
|
+
throw new PolicyEvaluationError(`Unsupported operator: ${String(condition.operator)}`, {
|
|
287
|
+
category: "unsupported_policy_construct",
|
|
288
|
+
code: "unsupported_operator",
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function validateConditionTree(condition, policyId) {
|
|
293
|
+
const findings = [];
|
|
294
|
+
if (condition === undefined)
|
|
295
|
+
return findings;
|
|
296
|
+
if (!isRecord(condition)) {
|
|
297
|
+
return [{
|
|
298
|
+
severity: "error",
|
|
299
|
+
code: "malformed_conditions",
|
|
300
|
+
message: "Policy conditions must be an object.",
|
|
301
|
+
policyIds: [policyId],
|
|
302
|
+
field: "conditions",
|
|
303
|
+
}];
|
|
304
|
+
}
|
|
305
|
+
if ("all" in condition || "any" in condition) {
|
|
306
|
+
const key = "all" in condition ? "all" : "any";
|
|
307
|
+
const group = condition[key];
|
|
308
|
+
if (!Array.isArray(group)) {
|
|
309
|
+
return [{
|
|
310
|
+
severity: "error",
|
|
311
|
+
code: "malformed_condition_group",
|
|
312
|
+
message: `Condition group \`${key}\` must be a list.`,
|
|
313
|
+
policyIds: [policyId],
|
|
314
|
+
field: `conditions.${key}`,
|
|
315
|
+
}];
|
|
316
|
+
}
|
|
317
|
+
for (const child of group) {
|
|
318
|
+
findings.push(...validateConditionTree(child, policyId));
|
|
319
|
+
}
|
|
320
|
+
return findings;
|
|
321
|
+
}
|
|
322
|
+
if (!condition.field) {
|
|
323
|
+
findings.push({
|
|
324
|
+
severity: "error",
|
|
325
|
+
code: "missing_condition_field",
|
|
326
|
+
message: "Condition is missing a field.",
|
|
327
|
+
policyIds: [policyId],
|
|
328
|
+
field: "conditions.field",
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
const operator = String(condition.operator ?? "equals");
|
|
332
|
+
if (!["equals", "not_equals", "greater_than", "less_than", "in"].includes(operator)) {
|
|
333
|
+
findings.push({
|
|
334
|
+
severity: "error",
|
|
335
|
+
code: "unsupported_operator",
|
|
336
|
+
message: `Condition uses unsupported operator: ${operator}`,
|
|
337
|
+
policyIds: [policyId],
|
|
338
|
+
field: "conditions.operator",
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
return findings;
|
|
342
|
+
}
|
|
343
|
+
function conditionSignature(condition) {
|
|
344
|
+
return JSON.stringify(signatureValue(condition));
|
|
345
|
+
}
|
|
346
|
+
function signatureValue(value) {
|
|
347
|
+
if (isRecord(value)) {
|
|
348
|
+
if (Array.isArray(value.all)) {
|
|
349
|
+
return { all: value.all.map(conditionSignature).sort() };
|
|
350
|
+
}
|
|
351
|
+
if (Array.isArray(value.any)) {
|
|
352
|
+
return { any: value.any.map(conditionSignature).sort() };
|
|
353
|
+
}
|
|
354
|
+
return Object.fromEntries(Object.entries(value)
|
|
355
|
+
.sort(([left], [right]) => compareStrings(left, right))
|
|
356
|
+
.map(([key, entry]) => [key, signatureValue(entry)]));
|
|
357
|
+
}
|
|
358
|
+
if (Array.isArray(value)) {
|
|
359
|
+
return value.map(signatureValue);
|
|
360
|
+
}
|
|
361
|
+
return value;
|
|
362
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
export type DecisionValue = "allow" | "deny" | "review" | "log";
|
|
2
|
+
export type ExecutionOutcome = "executed" | "blocked" | "pending_review" | "failed";
|
|
3
|
+
export type FindingSeverity = "info" | "warning" | "error";
|
|
4
|
+
export type ErrorCategory = "validation_error" | "malformed_policy" | "unsupported_policy_construct" | "evaluation_error" | "adapter_input_error" | "audit_write_error" | "simulation_unknown" | "solver_unknown";
|
|
5
|
+
export declare const ERROR_CATEGORIES: readonly ErrorCategory[];
|
|
6
|
+
export type PolicyOperator = "equals" | "not_equals" | "greater_than" | "less_than" | "in";
|
|
7
|
+
export interface Decision {
|
|
8
|
+
decision: DecisionValue;
|
|
9
|
+
reason: string;
|
|
10
|
+
matchedPolicyIds: string[];
|
|
11
|
+
metadata: Record<string, unknown>;
|
|
12
|
+
allowed: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface VerifyActionInput {
|
|
15
|
+
agent: unknown;
|
|
16
|
+
action: unknown;
|
|
17
|
+
context?: unknown;
|
|
18
|
+
policies?: PolicyInput;
|
|
19
|
+
auditPath?: string;
|
|
20
|
+
failClosed?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface VerificationResult {
|
|
23
|
+
decision: Decision;
|
|
24
|
+
auditEvent: AuditEvent;
|
|
25
|
+
}
|
|
26
|
+
export interface PolicyPack {
|
|
27
|
+
id?: string;
|
|
28
|
+
version?: string;
|
|
29
|
+
defaultDecision?: DecisionValue;
|
|
30
|
+
defaultReason?: string;
|
|
31
|
+
policies: Policy[];
|
|
32
|
+
}
|
|
33
|
+
export type PolicyInput = Policy | Policy[] | PolicyPack;
|
|
34
|
+
export interface Policy {
|
|
35
|
+
id: string;
|
|
36
|
+
name?: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
effect: DecisionValue;
|
|
39
|
+
conditions?: ConditionTree;
|
|
40
|
+
reason: string;
|
|
41
|
+
metadata?: Record<string, unknown>;
|
|
42
|
+
}
|
|
43
|
+
export type ConditionTree = {
|
|
44
|
+
all: ConditionTree[];
|
|
45
|
+
} | {
|
|
46
|
+
any: ConditionTree[];
|
|
47
|
+
} | Condition;
|
|
48
|
+
export interface Condition {
|
|
49
|
+
field: string;
|
|
50
|
+
operator: PolicyOperator;
|
|
51
|
+
value: unknown;
|
|
52
|
+
}
|
|
53
|
+
export interface AuditEvent {
|
|
54
|
+
id: string;
|
|
55
|
+
action: unknown;
|
|
56
|
+
decision: Omit<Decision, "allowed">;
|
|
57
|
+
policyPackId?: string;
|
|
58
|
+
policyVersion?: string;
|
|
59
|
+
policyHash?: string;
|
|
60
|
+
actionHash?: string;
|
|
61
|
+
envelopeHash?: string;
|
|
62
|
+
evidenceHash?: string;
|
|
63
|
+
verifierVersion?: string;
|
|
64
|
+
runtime: {
|
|
65
|
+
agent: unknown;
|
|
66
|
+
context: unknown;
|
|
67
|
+
executionOutcome: ExecutionOutcome;
|
|
68
|
+
};
|
|
69
|
+
timestamp: string;
|
|
70
|
+
}
|
|
71
|
+
export interface PolicyFinding {
|
|
72
|
+
severity: FindingSeverity;
|
|
73
|
+
code: string;
|
|
74
|
+
message: string;
|
|
75
|
+
policyIds: string[];
|
|
76
|
+
field?: string;
|
|
77
|
+
errorCategory?: ErrorCategory;
|
|
78
|
+
}
|
|
79
|
+
export interface PolicyAnalysis {
|
|
80
|
+
summary: {
|
|
81
|
+
policyPackId?: string;
|
|
82
|
+
policyVersion?: string;
|
|
83
|
+
defaultDecision: string;
|
|
84
|
+
hasExplicitDefault: boolean;
|
|
85
|
+
policyCount: number;
|
|
86
|
+
policyIrHash?: string;
|
|
87
|
+
findingCount: number;
|
|
88
|
+
errorCount: number;
|
|
89
|
+
warningCount: number;
|
|
90
|
+
infoCount: number;
|
|
91
|
+
};
|
|
92
|
+
findings: PolicyFinding[];
|
|
93
|
+
hasErrors: boolean;
|
|
94
|
+
}
|
|
95
|
+
export declare const DECISION_RANK: Record<DecisionValue, number>;
|
|
96
|
+
export declare class AduekError extends Error {
|
|
97
|
+
category: ErrorCategory;
|
|
98
|
+
code: string;
|
|
99
|
+
constructor(message: string, options?: {
|
|
100
|
+
category?: ErrorCategory;
|
|
101
|
+
code?: string;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
export declare class PolicyEvaluationError extends AduekError {
|
|
105
|
+
constructor(message: string, options?: {
|
|
106
|
+
category?: ErrorCategory;
|
|
107
|
+
code?: string;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
export declare function isDecisionValue(value: unknown): value is DecisionValue;
|
|
111
|
+
export declare function errorCategoryForCode(code: string): ErrorCategory;
|
|
112
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export const ERROR_CATEGORIES = [
|
|
2
|
+
"validation_error",
|
|
3
|
+
"malformed_policy",
|
|
4
|
+
"unsupported_policy_construct",
|
|
5
|
+
"evaluation_error",
|
|
6
|
+
"adapter_input_error",
|
|
7
|
+
"audit_write_error",
|
|
8
|
+
"simulation_unknown",
|
|
9
|
+
"solver_unknown",
|
|
10
|
+
];
|
|
11
|
+
export const DECISION_RANK = {
|
|
12
|
+
allow: 0,
|
|
13
|
+
log: 1,
|
|
14
|
+
review: 2,
|
|
15
|
+
deny: 3,
|
|
16
|
+
};
|
|
17
|
+
export class AduekError extends Error {
|
|
18
|
+
category;
|
|
19
|
+
code;
|
|
20
|
+
constructor(message, options = {}) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = "AduekError";
|
|
23
|
+
this.category = options.category ?? "evaluation_error";
|
|
24
|
+
this.code = options.code ?? "aduek_error";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export class PolicyEvaluationError extends AduekError {
|
|
28
|
+
constructor(message, options = {}) {
|
|
29
|
+
super(message, {
|
|
30
|
+
category: options.category ?? "evaluation_error",
|
|
31
|
+
code: options.code ?? "policy_evaluation_error",
|
|
32
|
+
});
|
|
33
|
+
this.name = "PolicyEvaluationError";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export function isDecisionValue(value) {
|
|
37
|
+
return value === "allow" || value === "deny" || value === "review" || value === "log";
|
|
38
|
+
}
|
|
39
|
+
export function errorCategoryForCode(code) {
|
|
40
|
+
if ([
|
|
41
|
+
"schema_validation_error",
|
|
42
|
+
"missing_policy_pack_id",
|
|
43
|
+
"missing_policy_version",
|
|
44
|
+
"missing_default_decision",
|
|
45
|
+
"missing_condition_field",
|
|
46
|
+
].includes(code))
|
|
47
|
+
return "validation_error";
|
|
48
|
+
if ([
|
|
49
|
+
"malformed_policy",
|
|
50
|
+
"malformed_policy_pack",
|
|
51
|
+
"malformed_policy_ir",
|
|
52
|
+
"malformed_conditions",
|
|
53
|
+
"malformed_condition_group",
|
|
54
|
+
].includes(code))
|
|
55
|
+
return "malformed_policy";
|
|
56
|
+
if ([
|
|
57
|
+
"unsupported_default_decision",
|
|
58
|
+
"unsupported_effect",
|
|
59
|
+
"unsupported_operator",
|
|
60
|
+
].includes(code))
|
|
61
|
+
return "unsupported_policy_construct";
|
|
62
|
+
if (code.startsWith("adapter_"))
|
|
63
|
+
return "adapter_input_error";
|
|
64
|
+
if (code.startsWith("audit_"))
|
|
65
|
+
return "audit_write_error";
|
|
66
|
+
if (code.startsWith("simulation_"))
|
|
67
|
+
return "simulation_unknown";
|
|
68
|
+
if (code.startsWith("solver_"))
|
|
69
|
+
return "solver_unknown";
|
|
70
|
+
return "evaluation_error";
|
|
71
|
+
}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Decision, PolicyPack } from "./types.js";
|
|
2
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
3
|
+
export declare function isPolicyPackInput(value: unknown): value is PolicyPack;
|
|
4
|
+
export declare function getDotted(value: unknown, path: string): unknown;
|
|
5
|
+
export declare function makeDecision(input: Omit<Decision, "allowed">): Decision;
|
|
6
|
+
export declare function stableValue(value: unknown): unknown;
|
|
7
|
+
export declare function compareStrings(left: string, right: string): number;
|
|
8
|
+
export declare function compactRecord(record: Record<string, unknown>): Record<string, unknown>;
|
|
9
|
+
export declare function agentRef(agent: unknown): {
|
|
10
|
+
id: string;
|
|
11
|
+
kind: string;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEvD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAErE;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAO/D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,QAAQ,CAKvE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAYnD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAIlE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAItF;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CASrE"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export function isRecord(value) {
|
|
2
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
export function isPolicyPackInput(value) {
|
|
5
|
+
return isRecord(value) && "policies" in value;
|
|
6
|
+
}
|
|
7
|
+
export function getDotted(value, path) {
|
|
8
|
+
return path.split(".").reduce((current, part) => {
|
|
9
|
+
if (current && typeof current === "object" && part in current) {
|
|
10
|
+
return current[part];
|
|
11
|
+
}
|
|
12
|
+
return undefined;
|
|
13
|
+
}, value);
|
|
14
|
+
}
|
|
15
|
+
export function makeDecision(input) {
|
|
16
|
+
return {
|
|
17
|
+
...input,
|
|
18
|
+
allowed: input.decision === "allow" || input.decision === "log",
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function stableValue(value) {
|
|
22
|
+
if (Array.isArray(value)) {
|
|
23
|
+
return value.map(stableValue);
|
|
24
|
+
}
|
|
25
|
+
if (isRecord(value)) {
|
|
26
|
+
return Object.fromEntries(Object.entries(value)
|
|
27
|
+
.sort(([left], [right]) => compareStrings(left, right))
|
|
28
|
+
.map(([key, entry]) => [key, stableValue(entry)]));
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
export function compareStrings(left, right) {
|
|
33
|
+
if (left < right)
|
|
34
|
+
return -1;
|
|
35
|
+
if (left > right)
|
|
36
|
+
return 1;
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
export function compactRecord(record) {
|
|
40
|
+
return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined && value !== null));
|
|
41
|
+
}
|
|
42
|
+
export function agentRef(agent) {
|
|
43
|
+
if (agent && typeof agent === "object") {
|
|
44
|
+
const record = agent;
|
|
45
|
+
return {
|
|
46
|
+
id: String(record.id ?? "agent"),
|
|
47
|
+
kind: String(record.kind ?? "agent"),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return { id: "agent", kind: "agent" };
|
|
51
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type JsonSchema = Record<string, unknown>;
|
|
2
|
+
export declare const ACTION_SCHEMA: JsonSchema;
|
|
3
|
+
export declare const DECISION_SCHEMA: JsonSchema;
|
|
4
|
+
export declare const POLICY_SCHEMA: JsonSchema;
|
|
5
|
+
export declare const AUDIT_EVENT_SCHEMA: JsonSchema;
|
|
6
|
+
export declare const SDK_SCHEMAS: {
|
|
7
|
+
readonly "action.schema.json": JsonSchema;
|
|
8
|
+
readonly "audit-event.schema.json": JsonSchema;
|
|
9
|
+
readonly "decision.schema.json": JsonSchema;
|
|
10
|
+
readonly "policy.schema.json": JsonSchema;
|
|
11
|
+
};
|
|
12
|
+
export declare function validatePolicyPackSchema(policyInput: unknown): string[];
|
|
13
|
+
export declare function validateAuditEventSchema(event: unknown): string[];
|
|
14
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD,eAAO,MAAM,aAAa,EAAE,UA+C3B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,UA2B7B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,UAkE3B,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,UA+ChC,CAAC;AAEF,eAAO,MAAM,WAAW;;;;;CAKd,CAAC;AAeX,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,EAAE,CAIvE;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAIjE"}
|