@fabricorg/platform 0.1.2 → 0.2.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/actions/index.cjs +48 -0
- package/dist/actions/index.cjs.map +1 -0
- package/dist/actions/index.d.cts +116 -0
- package/dist/adapters/index.cjs +28 -0
- package/dist/adapters/index.cjs.map +1 -0
- package/dist/adapters/index.d.cts +83 -0
- package/dist/chunk-7KJHGAZY.cjs +99 -0
- package/dist/chunk-7KJHGAZY.cjs.map +1 -0
- package/dist/chunk-GB2PSZ33.cjs +74 -0
- package/dist/chunk-GB2PSZ33.cjs.map +1 -0
- package/dist/chunk-JAXDEK5Z.cjs +63 -0
- package/dist/chunk-JAXDEK5Z.cjs.map +1 -0
- package/dist/chunk-KQEBNUZI.cjs +70 -0
- package/dist/chunk-KQEBNUZI.cjs.map +1 -0
- package/dist/chunk-LHCSVEFT.cjs +8 -0
- package/dist/chunk-LHCSVEFT.cjs.map +1 -0
- package/dist/chunk-LYX73U3P.cjs +195 -0
- package/dist/chunk-LYX73U3P.cjs.map +1 -0
- package/dist/chunk-LZSE6QGQ.cjs +60 -0
- package/dist/chunk-LZSE6QGQ.cjs.map +1 -0
- package/dist/chunk-NPVIFZQV.cjs +107 -0
- package/dist/chunk-NPVIFZQV.cjs.map +1 -0
- package/dist/chunk-PG5LYTUX.cjs +4 -0
- package/dist/chunk-PG5LYTUX.cjs.map +1 -0
- package/dist/chunk-Q3WYIWCN.cjs +183 -0
- package/dist/chunk-Q3WYIWCN.cjs.map +1 -0
- package/dist/chunk-QETQGAXJ.cjs +35 -0
- package/dist/chunk-QETQGAXJ.cjs.map +1 -0
- package/dist/chunk-SDXDHVTV.cjs +555 -0
- package/dist/chunk-SDXDHVTV.cjs.map +1 -0
- package/dist/chunk-YZKUEC2J.cjs +31 -0
- package/dist/chunk-YZKUEC2J.cjs.map +1 -0
- package/dist/displays/index.cjs +24 -0
- package/dist/displays/index.cjs.map +1 -0
- package/dist/displays/index.d.cts +34 -0
- package/dist/events/index.cjs +36 -0
- package/dist/events/index.cjs.map +1 -0
- package/dist/events/index.d.cts +35 -0
- package/dist/evidence/index.cjs +6 -0
- package/dist/evidence/index.cjs.map +1 -0
- package/dist/evidence/index.d.cts +43 -0
- package/dist/ids/index.cjs +24 -0
- package/dist/ids/index.cjs.map +1 -0
- package/dist/ids/index.d.cts +19 -0
- package/dist/index.cjs +268 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +13 -0
- package/dist/modules/index.cjs +42 -0
- package/dist/modules/index.cjs.map +1 -0
- package/dist/modules/index.d.cts +73 -0
- package/dist/objects/index.cjs +24 -0
- package/dist/objects/index.cjs.map +1 -0
- package/dist/objects/index.d.cts +7 -0
- package/dist/policies/index.cjs +48 -0
- package/dist/policies/index.cjs.map +1 -0
- package/dist/policies/index.d.cts +143 -0
- package/dist/privacy/index.cjs +12 -0
- package/dist/privacy/index.cjs.map +1 -0
- package/dist/privacy/index.d.cts +77 -0
- package/dist/projections/index.cjs +12 -0
- package/dist/projections/index.cjs.map +1 -0
- package/dist/projections/index.d.cts +52 -0
- package/dist/state-machines/index.cjs +32 -0
- package/dist/state-machines/index.cjs.map +1 -0
- package/dist/state-machines/index.d.cts +60 -0
- package/dist/testing/index.cjs +21 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +19 -0
- package/package.json +196 -111
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../projections/index.ts"],"names":[],"mappings":"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","file":"chunk-Q3WYIWCN.cjs","sourcesContent":["export interface ReplayableAssetEvent<Payload = unknown> {\n\tid: string;\n\ttenantId: string;\n\tspaceId: string;\n\teventType: string;\n\tsubjectType: string;\n\tsubjectId: string;\n\tpayload: Payload;\n\tsequence: number;\n\toccurredAt: Date | string;\n\trecordedAt: Date | string;\n\tactionInvocationId: string;\n\tcorrelationId: string;\n}\n\nexport interface ReplayScope {\n\ttenantId: string;\n\tspaceId: string;\n\tsubjectType?: string;\n\tsubjectId?: string;\n}\n\nexport interface ReplaySnapshot<State = unknown> {\n\tsnapshotData: State;\n\teventCursor?: string | null;\n\teventSequence?: number | null;\n}\n\nexport type ReplayWarningCode =\n\t| \"cursor_not_found\"\n\t| \"duplicate_event\"\n\t| \"missing_sequence\"\n\t| \"subject_scope_incomplete\";\n\nexport interface ReplayWarning {\n\tcode: ReplayWarningCode;\n\tmessage: string;\n\teventId?: string;\n\tsubjectType?: string;\n\tsubjectId?: string;\n\texpectedSequence?: number;\n\tactualSequence?: number;\n}\n\nexport interface ReplayEventsOptions<State, Event extends ReplayableAssetEvent = ReplayableAssetEvent> {\n\tevents: Iterable<Event> | AsyncIterable<Event>;\n\tscope: ReplayScope;\n\tinitialState: State;\n\tsnapshot?: ReplaySnapshot<State> | null;\n\tapplyEvent: (state: State, event: Event) => State | Promise<State>;\n}\n\nexport interface ReplayEventsResult<State, Event extends ReplayableAssetEvent = ReplayableAssetEvent> {\n\tstate: State;\n\tappliedEvents: Event[];\n\twarnings: ReplayWarning[];\n\teventCursor: string | null;\n\teventSequence: number;\n}\n\nexport async function replayEvents<State, Event extends ReplayableAssetEvent = ReplayableAssetEvent>({\n\tevents,\n\tscope,\n\tinitialState,\n\tsnapshot,\n\tapplyEvent,\n}: ReplayEventsOptions<State, Event>): Promise<ReplayEventsResult<State, Event>> {\n\tconst warnings: ReplayWarning[] = [];\n\tconst scopedEvents = filterEventsByScope(await collectEvents(events), scope, warnings);\n\tconst orderedEvents = sortEvents(scopedEvents, isSubjectScoped(scope));\n\tconst uniqueEvents = removeDuplicateEvents(orderedEvents, warnings);\n\tconst resumableEvents = applyCursor(uniqueEvents, snapshot, isSubjectScoped(scope), warnings);\n\n\tlet state = snapshot?.snapshotData ?? initialState;\n\tconst appliedEvents: Event[] = [];\n\tlet eventCursor = snapshot?.eventCursor ?? null;\n\tlet eventSequence = snapshot?.eventSequence ?? 0;\n\n\tfor (const event of resumableEvents) {\n\t\tstate = await applyEvent(state, event);\n\t\tappliedEvents.push(event);\n\t\teventCursor = event.id;\n\t\teventSequence = event.sequence;\n\t}\n\n\treturn {\n\t\tstate,\n\t\tappliedEvents,\n\t\twarnings,\n\t\teventCursor,\n\t\teventSequence,\n\t};\n}\n\nasync function collectEvents<Event extends ReplayableAssetEvent>(\n\tevents: Iterable<Event> | AsyncIterable<Event>,\n): Promise<Event[]> {\n\tconst collected: Event[] = [];\n\n\tif (Symbol.asyncIterator in events) {\n\t\tfor await (const event of events) {\n\t\t\tcollected.push(event);\n\t\t}\n\n\t\treturn collected;\n\t}\n\n\tfor (const event of events) {\n\t\tcollected.push(event);\n\t}\n\n\treturn collected;\n}\n\nfunction filterEventsByScope<Event extends ReplayableAssetEvent>(\n\tevents: Event[],\n\tscope: ReplayScope,\n\twarnings: ReplayWarning[],\n): Event[] {\n\tif ((scope.subjectType && !scope.subjectId) || (!scope.subjectType && scope.subjectId)) {\n\t\twarnings.push({\n\t\t\tcode: \"subject_scope_incomplete\",\n\t\t\tmessage: \"Both subjectType and subjectId are required for subject-scoped replay.\",\n\t\t\tsubjectType: scope.subjectType,\n\t\t\tsubjectId: scope.subjectId,\n\t\t});\n\t}\n\n\treturn events.filter((event) => {\n\t\tif (event.tenantId !== scope.tenantId || event.spaceId !== scope.spaceId) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (scope.subjectType && event.subjectType !== scope.subjectType) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (scope.subjectId && event.subjectId !== scope.subjectId) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t});\n}\n\nfunction removeDuplicateEvents<Event extends ReplayableAssetEvent>(\n\tevents: Event[],\n\twarnings: ReplayWarning[],\n): Event[] {\n\tconst seenEventIds = new Set<string>();\n\tconst uniqueEvents: Event[] = [];\n\n\tfor (const event of events) {\n\t\tif (seenEventIds.has(event.id)) {\n\t\t\twarnings.push({\n\t\t\t\tcode: \"duplicate_event\",\n\t\t\t\tmessage: `Duplicate event ${event.id} ignored during replay.`,\n\t\t\t\teventId: event.id,\n\t\t\t\tsubjectType: event.subjectType,\n\t\t\t\tsubjectId: event.subjectId,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tseenEventIds.add(event.id);\n\t\tuniqueEvents.push(event);\n\t}\n\n\trecordMissingSequenceWarnings(uniqueEvents, warnings);\n\n\treturn uniqueEvents;\n}\n\nfunction recordMissingSequenceWarnings<Event extends ReplayableAssetEvent>(\n\tevents: Event[],\n\twarnings: ReplayWarning[],\n): void {\n\tconst lastSequenceBySubject = new Map<string, number>();\n\n\tfor (const event of events) {\n\t\tconst subjectKey = `${event.subjectType}:${event.subjectId}`;\n\t\tconst previousSequence = lastSequenceBySubject.get(subjectKey);\n\t\tconst expectedSequence = previousSequence === undefined ? event.sequence : previousSequence + 1;\n\n\t\tif (previousSequence !== undefined && event.sequence > expectedSequence) {\n\t\t\twarnings.push({\n\t\t\t\tcode: \"missing_sequence\",\n\t\t\t\tmessage: `Missing event sequence for ${subjectKey}: expected ${expectedSequence}, received ${event.sequence}.`,\n\t\t\t\teventId: event.id,\n\t\t\t\tsubjectType: event.subjectType,\n\t\t\t\tsubjectId: event.subjectId,\n\t\t\t\texpectedSequence,\n\t\t\t\tactualSequence: event.sequence,\n\t\t\t});\n\t\t}\n\n\t\tlastSequenceBySubject.set(subjectKey, Math.max(previousSequence ?? event.sequence, event.sequence));\n\t}\n}\n\nfunction applyCursor<Event extends ReplayableAssetEvent>(\n\tevents: Event[],\n\tsnapshot: ReplaySnapshot | null | undefined,\n\tsubjectScoped: boolean,\n\twarnings: ReplayWarning[],\n): Event[] {\n\tconst eventCursor = snapshot?.eventCursor;\n\n\tif (eventCursor) {\n\t\tconst cursorIndex = events.findIndex((event) => event.id === eventCursor);\n\n\t\tif (cursorIndex >= 0) {\n\t\t\treturn events.slice(cursorIndex + 1);\n\t\t}\n\n\t\twarnings.push({\n\t\t\tcode: \"cursor_not_found\",\n\t\t\tmessage: `Snapshot cursor ${eventCursor} was not found in the scoped event stream.`,\n\t\t\teventId: eventCursor,\n\t\t});\n\t}\n\n\tif (subjectScoped && snapshot?.eventSequence !== undefined && snapshot.eventSequence !== null) {\n\t\treturn events.filter((event) => event.sequence > snapshot.eventSequence!);\n\t}\n\n\treturn events;\n}\n\nfunction sortEvents<Event extends ReplayableAssetEvent>(events: Event[], subjectScoped: boolean): Event[] {\n\treturn [...events].sort((first, second) =>\n\t\tsubjectScoped ? compareSubjectEvents(first, second) : compareGlobalEvents(first, second),\n\t);\n}\n\nfunction compareSubjectEvents(first: ReplayableAssetEvent, second: ReplayableAssetEvent): number {\n\treturn compareValues(\n\t\t[first.sequence, toTimestamp(first.recordedAt), toTimestamp(first.occurredAt), first.id],\n\t\t[second.sequence, toTimestamp(second.recordedAt), toTimestamp(second.occurredAt), second.id],\n\t);\n}\n\nfunction compareGlobalEvents(first: ReplayableAssetEvent, second: ReplayableAssetEvent): number {\n\treturn compareValues(\n\t\t[\n\t\t\ttoTimestamp(first.recordedAt),\n\t\t\ttoTimestamp(first.occurredAt),\n\t\t\tfirst.actionInvocationId,\n\t\t\tfirst.correlationId,\n\t\t\tfirst.subjectType,\n\t\t\tfirst.subjectId,\n\t\t\tfirst.sequence,\n\t\t\tfirst.id,\n\t\t],\n\t\t[\n\t\t\ttoTimestamp(second.recordedAt),\n\t\t\ttoTimestamp(second.occurredAt),\n\t\t\tsecond.actionInvocationId,\n\t\t\tsecond.correlationId,\n\t\t\tsecond.subjectType,\n\t\t\tsecond.subjectId,\n\t\t\tsecond.sequence,\n\t\t\tsecond.id,\n\t\t],\n\t);\n}\n\nfunction compareValues(firstValues: Array<number | string>, secondValues: Array<number | string>): number {\n\tfor (const [index, firstValue] of firstValues.entries()) {\n\t\tconst secondValue = secondValues[index];\n\n\t\tif (firstValue < secondValue) {\n\t\t\treturn -1;\n\t\t}\n\n\t\tif (firstValue > secondValue) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nfunction isSubjectScoped(scope: ReplayScope): boolean {\n\treturn Boolean(scope.subjectType && scope.subjectId);\n}\n\nfunction toTimestamp(value: Date | string): number {\n\treturn value instanceof Date ? value.getTime() : new Date(value).getTime();\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// objects/index.ts
|
|
4
|
+
var objectTypeRegistry = /* @__PURE__ */ new Set([
|
|
5
|
+
"AssetEvent",
|
|
6
|
+
"ActionInvocation",
|
|
7
|
+
"PolicyEvaluation",
|
|
8
|
+
"ApprovalRequest",
|
|
9
|
+
"ConsentRecord",
|
|
10
|
+
"AgentRun"
|
|
11
|
+
]);
|
|
12
|
+
function assertObjectType(type) {
|
|
13
|
+
if (!/^[A-Z][a-zA-Z0-9]*$/.test(type)) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
`Invalid object type: "${type}". Object types must be PascalCase alphanumeric.`
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function registerObjectType(type) {
|
|
20
|
+
assertObjectType(type);
|
|
21
|
+
objectTypeRegistry.add(type);
|
|
22
|
+
}
|
|
23
|
+
function isValidObjectType(type) {
|
|
24
|
+
return objectTypeRegistry.has(type);
|
|
25
|
+
}
|
|
26
|
+
function getRegisteredObjectTypes() {
|
|
27
|
+
return Array.from(objectTypeRegistry);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
exports.assertObjectType = assertObjectType;
|
|
31
|
+
exports.getRegisteredObjectTypes = getRegisteredObjectTypes;
|
|
32
|
+
exports.isValidObjectType = isValidObjectType;
|
|
33
|
+
exports.registerObjectType = registerObjectType;
|
|
34
|
+
//# sourceMappingURL=chunk-QETQGAXJ.cjs.map
|
|
35
|
+
//# sourceMappingURL=chunk-QETQGAXJ.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../objects/index.ts"],"names":[],"mappings":";;;AAAA,IAAM,kBAAA,uBAAyB,GAAA,CAAY;AAAA,EAC1C,YAAA;AAAA,EACA,kBAAA;AAAA,EACA,kBAAA;AAAA,EACA,iBAAA;AAAA,EACA,eAAA;AAAA,EACA;AACD,CAAC,CAAA;AAIM,SAAS,iBAAiB,IAAA,EAAgD;AAChF,EAAA,IAAI,CAAC,qBAAA,CAAsB,IAAA,CAAK,IAAI,CAAA,EAAG;AACtC,IAAA,MAAM,IAAI,KAAA;AAAA,MACT,yBAAyB,IAAI,CAAA,gDAAA;AAAA,KAC9B;AAAA,EACD;AACD;AAEO,SAAS,mBAAmB,IAAA,EAAoB;AACtD,EAAA,gBAAA,CAAiB,IAAI,CAAA;AACrB,EAAA,kBAAA,CAAmB,IAAI,IAAI,CAAA;AAC5B;AAEO,SAAS,kBAAkB,IAAA,EAAuB;AACxD,EAAA,OAAO,kBAAA,CAAmB,IAAI,IAAI,CAAA;AACnC;AAEO,SAAS,wBAAA,GAAqC;AACpD,EAAA,OAAO,KAAA,CAAM,KAAK,kBAAkB,CAAA;AACrC","file":"chunk-QETQGAXJ.cjs","sourcesContent":["const objectTypeRegistry = new Set<string>([\n\t\"AssetEvent\",\n\t\"ActionInvocation\",\n\t\"PolicyEvaluation\",\n\t\"ApprovalRequest\",\n\t\"ConsentRecord\",\n\t\"AgentRun\",\n]);\n\nexport type FabricObjectType = string;\n\nexport function assertObjectType(type: string): asserts type is FabricObjectType {\n\tif (!/^[A-Z][a-zA-Z0-9]*$/.test(type)) {\n\t\tthrow new Error(\n\t\t\t`Invalid object type: \"${type}\". Object types must be PascalCase alphanumeric.`,\n\t\t);\n\t}\n}\n\nexport function registerObjectType(type: string): void {\n\tassertObjectType(type);\n\tobjectTypeRegistry.add(type);\n}\n\nexport function isValidObjectType(type: string): boolean {\n\treturn objectTypeRegistry.has(type);\n}\n\nexport function getRegisteredObjectTypes(): string[] {\n\treturn Array.from(objectTypeRegistry);\n}\n"]}
|
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// policies/index.ts
|
|
4
|
+
function assertPolicyId(policyId) {
|
|
5
|
+
if (!/^[a-z][a-z0-9_-]*(\.[a-z][a-z0-9_-]*)*\.v[0-9]+$/.test(policyId)) {
|
|
6
|
+
throw new Error(`Invalid policy ID: ${policyId}`);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
var DATA_POLICY_MAX_DEPTH = 5;
|
|
10
|
+
var DATA_POLICY_MAX_CONDITIONS_PER_NODE = 20;
|
|
11
|
+
var DATA_POLICY_MAX_TOTAL_CONDITIONS = 100;
|
|
12
|
+
var DATA_POLICY_MAX_PATH_SEGMENTS = 12;
|
|
13
|
+
var DATA_POLICY_MAX_STRING_LENGTH = 500;
|
|
14
|
+
var DATA_POLICY_CONTEXT_PATHS = /* @__PURE__ */ new Set([
|
|
15
|
+
"tenantId",
|
|
16
|
+
"spaceId",
|
|
17
|
+
"actionInvocationId",
|
|
18
|
+
"actionId",
|
|
19
|
+
"mode"
|
|
20
|
+
]);
|
|
21
|
+
var DATA_POLICY_COMPARISON_OPERATORS = /* @__PURE__ */ new Set([
|
|
22
|
+
"exists",
|
|
23
|
+
"equals",
|
|
24
|
+
"notEquals",
|
|
25
|
+
"gt",
|
|
26
|
+
"gte",
|
|
27
|
+
"lt",
|
|
28
|
+
"lte"
|
|
29
|
+
]);
|
|
30
|
+
var POLICY_RESULTS = /* @__PURE__ */ new Set(["pass", "warn", "block"]);
|
|
31
|
+
var registry = /* @__PURE__ */ new Map();
|
|
32
|
+
function registerPolicy(evaluator) {
|
|
33
|
+
assertPolicyId(evaluator.policyId);
|
|
34
|
+
const existing = registry.get(evaluator.policyId);
|
|
35
|
+
if (existing && existing !== evaluator) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
`Conflicting policy registration for "${evaluator.policyId}". A different evaluator is already registered.`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
registry.set(evaluator.policyId, evaluator);
|
|
41
|
+
}
|
|
42
|
+
function registerPolicyIfMissing(evaluator) {
|
|
43
|
+
if (!registry.has(evaluator.policyId)) {
|
|
44
|
+
registerPolicy(evaluator);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const existing = registry.get(evaluator.policyId);
|
|
48
|
+
if (existing && existing !== evaluator) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
`Conflicting policy registration for "${evaluator.policyId}". A different evaluator is already registered.`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function resolvePolicy(policyId) {
|
|
55
|
+
return registry.get(policyId);
|
|
56
|
+
}
|
|
57
|
+
function getRegisteredPolicyIds() {
|
|
58
|
+
return Array.from(registry.keys());
|
|
59
|
+
}
|
|
60
|
+
async function evaluateRegisteredPolicies(policyIds, ctx) {
|
|
61
|
+
return evaluatePolicyDefinitions(
|
|
62
|
+
policyIds.map((policyId) => ({
|
|
63
|
+
policyId,
|
|
64
|
+
policyVersion: parsePolicyVersion(policyId),
|
|
65
|
+
kind: "code",
|
|
66
|
+
codeEvaluatorPolicyId: policyId
|
|
67
|
+
})),
|
|
68
|
+
ctx
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
async function evaluatePolicyDefinitions(policies, ctx) {
|
|
72
|
+
const outcomes = [];
|
|
73
|
+
for (const policy of policies) {
|
|
74
|
+
assertPolicyId(policy.policyId);
|
|
75
|
+
outcomes.push(await evaluatePolicyDefinition(policy, ctx));
|
|
76
|
+
}
|
|
77
|
+
return outcomes;
|
|
78
|
+
}
|
|
79
|
+
async function evaluatePolicyDefinition(policy, ctx) {
|
|
80
|
+
if (policy.kind === "data") {
|
|
81
|
+
return evaluateDataPolicy(policy, ctx);
|
|
82
|
+
}
|
|
83
|
+
if (policy.kind === "code") {
|
|
84
|
+
return evaluateCodePolicy(policy, ctx);
|
|
85
|
+
}
|
|
86
|
+
return evaluateHybridPolicy(policy, ctx);
|
|
87
|
+
}
|
|
88
|
+
async function evaluateCodePolicy(policy, ctx) {
|
|
89
|
+
const codeEvaluatorPolicyId = policy.codeEvaluatorPolicyId ?? policy.policyId;
|
|
90
|
+
const evaluator = registry.get(codeEvaluatorPolicyId);
|
|
91
|
+
if (!evaluator) {
|
|
92
|
+
return {
|
|
93
|
+
policyId: policy.policyId,
|
|
94
|
+
policyVersion: policy.policyVersion,
|
|
95
|
+
policyKind: policy.kind,
|
|
96
|
+
result: "block",
|
|
97
|
+
reason: `No evaluator registered for policy ${codeEvaluatorPolicyId}`,
|
|
98
|
+
metadata: {
|
|
99
|
+
missingCodeEvaluatorPolicyId: codeEvaluatorPolicyId
|
|
100
|
+
},
|
|
101
|
+
dispatchEvidence: {
|
|
102
|
+
policyKind: policy.kind,
|
|
103
|
+
policyId: policy.policyId,
|
|
104
|
+
policyVersion: policy.policyVersion,
|
|
105
|
+
dispatchPath: ["code"],
|
|
106
|
+
code: {
|
|
107
|
+
requestedPolicyId: codeEvaluatorPolicyId,
|
|
108
|
+
policyId: codeEvaluatorPolicyId,
|
|
109
|
+
registered: false
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const outcome = await evaluator.evaluate(ctx);
|
|
115
|
+
return normalizeOutcome(policy, outcome, {
|
|
116
|
+
policyKind: policy.kind,
|
|
117
|
+
policyId: policy.policyId,
|
|
118
|
+
policyVersion: policy.policyVersion,
|
|
119
|
+
dispatchPath: ["code"],
|
|
120
|
+
code: {
|
|
121
|
+
requestedPolicyId: codeEvaluatorPolicyId,
|
|
122
|
+
policyId: evaluator.policyId,
|
|
123
|
+
version: evaluator.version,
|
|
124
|
+
registered: true
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
async function evaluateHybridPolicy(policy, ctx) {
|
|
129
|
+
const dataOutcome = evaluateDataPolicy(policy, ctx);
|
|
130
|
+
const fallback = policy.fallback;
|
|
131
|
+
const fallbackDecision = fallback ? resolveFallbackDecision(policy, dataOutcome, fallback) : { shouldFallback: false, trigger: "not_triggered" };
|
|
132
|
+
if (!fallback || !fallbackDecision.shouldFallback) {
|
|
133
|
+
if (fallback && dataOutcome.dispatchEvidence) {
|
|
134
|
+
return {
|
|
135
|
+
...dataOutcome,
|
|
136
|
+
dispatchEvidence: {
|
|
137
|
+
...dataOutcome.dispatchEvidence,
|
|
138
|
+
fallback: {
|
|
139
|
+
used: false,
|
|
140
|
+
trigger: "not_triggered",
|
|
141
|
+
reason: "Data policy result did not trigger fallback",
|
|
142
|
+
fromResult: dataOutcome.result,
|
|
143
|
+
definitionVersion: policy.policyVersion,
|
|
144
|
+
codeEvaluatorPolicyId: fallback.codeEvaluatorPolicyId
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return dataOutcome;
|
|
150
|
+
}
|
|
151
|
+
const codePolicy = {
|
|
152
|
+
policyId: policy.policyId,
|
|
153
|
+
policyVersion: policy.policyVersion,
|
|
154
|
+
kind: "hybrid",
|
|
155
|
+
codeEvaluatorPolicyId: fallback.codeEvaluatorPolicyId
|
|
156
|
+
};
|
|
157
|
+
const codeOutcome = await evaluateCodePolicy(codePolicy, ctx);
|
|
158
|
+
return normalizeOutcome(policy, codeOutcome, {
|
|
159
|
+
...codeOutcome.dispatchEvidence ?? {
|
|
160
|
+
policyKind: "hybrid",
|
|
161
|
+
policyId: policy.policyId,
|
|
162
|
+
policyVersion: policy.policyVersion,
|
|
163
|
+
dispatchPath: ["code"]
|
|
164
|
+
},
|
|
165
|
+
policyKind: "hybrid",
|
|
166
|
+
policyId: policy.policyId,
|
|
167
|
+
policyVersion: policy.policyVersion,
|
|
168
|
+
dispatchPath: ["data", "fallback", "code"],
|
|
169
|
+
data: dataOutcome.dispatchEvidence?.data,
|
|
170
|
+
fallback: {
|
|
171
|
+
used: true,
|
|
172
|
+
trigger: fallbackDecision.trigger,
|
|
173
|
+
reason: fallback.reason ?? "Data policy result triggered code fallback",
|
|
174
|
+
fromResult: dataOutcome.result,
|
|
175
|
+
definitionVersion: policy.policyVersion,
|
|
176
|
+
codeEvaluatorPolicyId: fallback.codeEvaluatorPolicyId
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function resolveFallbackDecision(policy, dataOutcome, fallback) {
|
|
181
|
+
const allowedTriggers = fallback.triggers ?? [
|
|
182
|
+
"data_result",
|
|
183
|
+
"missing_data_definition",
|
|
184
|
+
"invalid_data_definition"
|
|
185
|
+
];
|
|
186
|
+
const definitionStatus = dataOutcome.dispatchEvidence?.data?.definitionStatus;
|
|
187
|
+
if (definitionStatus === "missing") {
|
|
188
|
+
return {
|
|
189
|
+
shouldFallback: allowedTriggers.includes("missing_data_definition"),
|
|
190
|
+
trigger: "missing_data_definition"
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
if (definitionStatus === "invalid") {
|
|
194
|
+
return {
|
|
195
|
+
shouldFallback: allowedTriggers.includes("invalid_data_definition"),
|
|
196
|
+
trigger: "invalid_data_definition"
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
const fallbackResults = fallback.onResults ?? ["warn", "block"];
|
|
200
|
+
return {
|
|
201
|
+
shouldFallback: policy.kind === "hybrid" && allowedTriggers.includes("data_result") && fallbackResults.includes(dataOutcome.result),
|
|
202
|
+
trigger: "data_result"
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function evaluateDataPolicy(policy, ctx) {
|
|
206
|
+
const definition = policy.dataDefinition;
|
|
207
|
+
if (!definition) {
|
|
208
|
+
return {
|
|
209
|
+
policyId: policy.policyId,
|
|
210
|
+
policyVersion: policy.policyVersion,
|
|
211
|
+
policyKind: policy.kind,
|
|
212
|
+
result: "block",
|
|
213
|
+
reason: "Data policy definition is missing",
|
|
214
|
+
dispatchEvidence: {
|
|
215
|
+
policyKind: policy.kind,
|
|
216
|
+
policyId: policy.policyId,
|
|
217
|
+
policyVersion: policy.policyVersion,
|
|
218
|
+
dispatchPath: ["data"],
|
|
219
|
+
data: {
|
|
220
|
+
definitionVersion: policy.policyVersion,
|
|
221
|
+
definitionStatus: "missing",
|
|
222
|
+
conditionResults: []
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
const validation = validateDataPolicyDefinition(definition);
|
|
228
|
+
if (!validation.valid) {
|
|
229
|
+
return {
|
|
230
|
+
policyId: policy.policyId,
|
|
231
|
+
policyVersion: policy.policyVersion,
|
|
232
|
+
policyKind: policy.kind,
|
|
233
|
+
result: "block",
|
|
234
|
+
reason: `Invalid data policy definition: ${validation.errors.join("; ")}`,
|
|
235
|
+
metadata: {
|
|
236
|
+
validationErrors: validation.errors
|
|
237
|
+
},
|
|
238
|
+
dispatchEvidence: {
|
|
239
|
+
policyKind: policy.kind,
|
|
240
|
+
policyId: policy.policyId,
|
|
241
|
+
policyVersion: policy.policyVersion,
|
|
242
|
+
dispatchPath: ["data"],
|
|
243
|
+
data: {
|
|
244
|
+
definitionVersion: policy.policyVersion,
|
|
245
|
+
definitionStatus: "invalid",
|
|
246
|
+
conditionResults: [],
|
|
247
|
+
validationErrors: validation.errors
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
const evaluations = definition.conditions.map((condition) => evaluateDataPolicyCondition(condition, ctx));
|
|
253
|
+
const conditionResults = evaluations.flatMap((evaluation) => evaluation.evidence);
|
|
254
|
+
const topLevelResults = evaluations.map((evaluation) => evaluation.result);
|
|
255
|
+
const aggregate = topLevelResults.find((result2) => result2.result === "block") ?? topLevelResults.find((result2) => result2.result === "warn");
|
|
256
|
+
const result = aggregate?.result ?? definition.defaultResult ?? "pass";
|
|
257
|
+
return {
|
|
258
|
+
policyId: policy.policyId,
|
|
259
|
+
policyVersion: policy.policyVersion,
|
|
260
|
+
policyKind: policy.kind,
|
|
261
|
+
result,
|
|
262
|
+
reason: aggregate?.reason ?? definition.reason,
|
|
263
|
+
metadata: {
|
|
264
|
+
conditionCount: definition.conditions.length,
|
|
265
|
+
failedConditionId: aggregate?.conditionId
|
|
266
|
+
},
|
|
267
|
+
dispatchEvidence: {
|
|
268
|
+
policyKind: policy.kind,
|
|
269
|
+
policyId: policy.policyId,
|
|
270
|
+
policyVersion: policy.policyVersion,
|
|
271
|
+
dispatchPath: ["data"],
|
|
272
|
+
data: {
|
|
273
|
+
definitionVersion: policy.policyVersion,
|
|
274
|
+
definitionStatus: "evaluated",
|
|
275
|
+
conditionResults
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function validateDataPolicyDefinition(definition) {
|
|
281
|
+
const errors = [];
|
|
282
|
+
if (!Array.isArray(definition.conditions) || definition.conditions.length === 0) {
|
|
283
|
+
errors.push("conditions must contain at least one condition");
|
|
284
|
+
} else if (definition.conditions.length > DATA_POLICY_MAX_CONDITIONS_PER_NODE) {
|
|
285
|
+
errors.push(
|
|
286
|
+
`conditions must contain at most ${DATA_POLICY_MAX_CONDITIONS_PER_NODE} top-level conditions`
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
if (definition.defaultResult && !POLICY_RESULTS.has(definition.defaultResult)) {
|
|
290
|
+
errors.push("defaultResult must be pass, warn, or block");
|
|
291
|
+
}
|
|
292
|
+
let totalConditions = 0;
|
|
293
|
+
for (const condition of definition.conditions ?? []) {
|
|
294
|
+
validateDataPolicyCondition(condition, errors, 1, () => {
|
|
295
|
+
totalConditions += 1;
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
if (totalConditions > DATA_POLICY_MAX_TOTAL_CONDITIONS) {
|
|
299
|
+
errors.push(`policy must contain at most ${DATA_POLICY_MAX_TOTAL_CONDITIONS} total conditions`);
|
|
300
|
+
}
|
|
301
|
+
return { valid: errors.length === 0, errors };
|
|
302
|
+
}
|
|
303
|
+
function validateDataPolicyCondition(condition, errors, depth, count) {
|
|
304
|
+
count();
|
|
305
|
+
if (!condition || typeof condition !== "object") {
|
|
306
|
+
errors.push("condition must be an object");
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (depth > DATA_POLICY_MAX_DEPTH) {
|
|
310
|
+
errors.push(`condition depth must not exceed ${DATA_POLICY_MAX_DEPTH}`);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (!isNonEmptyBoundedString(condition.conditionId)) {
|
|
314
|
+
errors.push("conditionId must be a non-empty bounded string");
|
|
315
|
+
}
|
|
316
|
+
validateOptionalPolicyResult("onPass" in condition ? condition.onPass : void 0, "onPass", errors);
|
|
317
|
+
validateOptionalPolicyResult("onFail" in condition ? condition.onFail : void 0, "onFail", errors);
|
|
318
|
+
if (condition.reason !== void 0 && !isNonEmptyBoundedString(condition.reason)) {
|
|
319
|
+
errors.push(`condition ${condition.conditionId} reason must be a bounded string`);
|
|
320
|
+
}
|
|
321
|
+
if (condition.type === "always") {
|
|
322
|
+
if (!POLICY_RESULTS.has(condition.result)) {
|
|
323
|
+
errors.push(`condition ${condition.conditionId} result must be pass, warn, or block`);
|
|
324
|
+
}
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if (condition.type === "parameter") {
|
|
328
|
+
validatePath(condition.path, `condition ${condition.conditionId} path`, errors);
|
|
329
|
+
validateComparison(condition.operator, condition.value, condition.conditionId, errors);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (condition.type === "comparison") {
|
|
333
|
+
validateSourceReference(condition.left, condition.conditionId, errors);
|
|
334
|
+
validateComparison(condition.operator, condition.value, condition.conditionId, errors);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (condition.type === "all" || condition.type === "any") {
|
|
338
|
+
if (!Array.isArray(condition.conditions) || condition.conditions.length === 0) {
|
|
339
|
+
errors.push(`condition ${condition.conditionId} must contain child conditions`);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
if (condition.conditions.length > DATA_POLICY_MAX_CONDITIONS_PER_NODE) {
|
|
343
|
+
errors.push(
|
|
344
|
+
`condition ${condition.conditionId} must contain at most ${DATA_POLICY_MAX_CONDITIONS_PER_NODE} child conditions`
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
for (const child of condition.conditions) {
|
|
348
|
+
validateDataPolicyCondition(child, errors, depth + 1, count);
|
|
349
|
+
}
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
if (condition.type === "not") {
|
|
353
|
+
validateDataPolicyCondition(condition.condition, errors, depth + 1, count);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
errors.push(`condition ${condition.conditionId} has unsupported type`);
|
|
357
|
+
}
|
|
358
|
+
function validateOptionalPolicyResult(result, fieldName, errors) {
|
|
359
|
+
if (result !== void 0 && !POLICY_RESULTS.has(result)) {
|
|
360
|
+
errors.push(`${fieldName} must be pass, warn, or block`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
function validateSourceReference(reference, conditionId, errors) {
|
|
364
|
+
if (!reference || typeof reference !== "object") {
|
|
365
|
+
errors.push(`condition ${conditionId} left must be a source reference`);
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
if (reference.source !== "parameters" && reference.source !== "context") {
|
|
369
|
+
errors.push(`condition ${conditionId} source must be parameters or context`);
|
|
370
|
+
}
|
|
371
|
+
validatePath(reference.path, `condition ${conditionId} left.path`, errors);
|
|
372
|
+
if (reference.source === "context" && !DATA_POLICY_CONTEXT_PATHS.has(reference.path)) {
|
|
373
|
+
errors.push(`condition ${conditionId} uses an unsupported context path`);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
function validateComparison(operator, value, conditionId, errors) {
|
|
377
|
+
if (!DATA_POLICY_COMPARISON_OPERATORS.has(operator)) {
|
|
378
|
+
errors.push(`condition ${conditionId} has unsupported operator`);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (operator === "exists") {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (!isDataPolicyLiteral(value)) {
|
|
385
|
+
errors.push(`condition ${conditionId} comparison value must be a bounded literal`);
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
if (["gt", "gte", "lt", "lte"].includes(operator) && typeof value !== "number") {
|
|
389
|
+
errors.push(`condition ${conditionId} numeric comparison requires a number value`);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
function validatePath(path, fieldName, errors) {
|
|
393
|
+
if (!isNonEmptyBoundedString(path)) {
|
|
394
|
+
errors.push(`${fieldName} must be a non-empty bounded string`);
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
const segments = path.split(".");
|
|
398
|
+
if (segments.length > DATA_POLICY_MAX_PATH_SEGMENTS) {
|
|
399
|
+
errors.push(`${fieldName} must contain at most ${DATA_POLICY_MAX_PATH_SEGMENTS} segments`);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
for (const segment of segments) {
|
|
403
|
+
if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(segment)) {
|
|
404
|
+
errors.push(`${fieldName} contains an invalid path segment`);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
if (["__proto__", "constructor", "prototype"].includes(segment)) {
|
|
408
|
+
errors.push(`${fieldName} contains a forbidden path segment`);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
function isDataPolicyLiteral(value) {
|
|
414
|
+
if (value === null || typeof value === "number" || typeof value === "boolean") {
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
417
|
+
return typeof value === "string" && value.length <= DATA_POLICY_MAX_STRING_LENGTH;
|
|
418
|
+
}
|
|
419
|
+
function isNonEmptyBoundedString(value) {
|
|
420
|
+
return typeof value === "string" && value.length > 0 && value.length <= DATA_POLICY_MAX_STRING_LENGTH;
|
|
421
|
+
}
|
|
422
|
+
function evaluateDataPolicyCondition(condition, ctx) {
|
|
423
|
+
if (condition.type === "always") {
|
|
424
|
+
const result2 = {
|
|
425
|
+
conditionId: condition.conditionId,
|
|
426
|
+
passed: condition.result === "pass",
|
|
427
|
+
result: condition.result,
|
|
428
|
+
reason: condition.reason
|
|
429
|
+
};
|
|
430
|
+
return { result: result2, evidence: [result2] };
|
|
431
|
+
}
|
|
432
|
+
if (condition.type === "all" || condition.type === "any") {
|
|
433
|
+
const childEvaluations = condition.conditions.map((child) => evaluateDataPolicyCondition(child, ctx));
|
|
434
|
+
const passed2 = condition.type === "all" ? childEvaluations.every((evaluation) => evaluation.result.passed) : childEvaluations.some((evaluation) => evaluation.result.passed);
|
|
435
|
+
const result2 = {
|
|
436
|
+
conditionId: condition.conditionId,
|
|
437
|
+
passed: passed2,
|
|
438
|
+
result: passed2 ? condition.onPass ?? "pass" : condition.onFail ?? "block",
|
|
439
|
+
reason: passed2 ? void 0 : condition.reason
|
|
440
|
+
};
|
|
441
|
+
return {
|
|
442
|
+
result: result2,
|
|
443
|
+
evidence: [result2, ...childEvaluations.flatMap((evaluation) => evaluation.evidence)]
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
if (condition.type === "not") {
|
|
447
|
+
const childEvaluation = evaluateDataPolicyCondition(condition.condition, ctx);
|
|
448
|
+
const passed2 = !childEvaluation.result.passed;
|
|
449
|
+
const result2 = {
|
|
450
|
+
conditionId: condition.conditionId,
|
|
451
|
+
passed: passed2,
|
|
452
|
+
result: passed2 ? condition.onPass ?? "pass" : condition.onFail ?? "block",
|
|
453
|
+
reason: passed2 ? void 0 : condition.reason
|
|
454
|
+
};
|
|
455
|
+
return { result: result2, evidence: [result2, ...childEvaluation.evidence] };
|
|
456
|
+
}
|
|
457
|
+
if (condition.type !== "parameter" && condition.type !== "comparison") {
|
|
458
|
+
const result2 = {
|
|
459
|
+
conditionId: condition.conditionId,
|
|
460
|
+
passed: false,
|
|
461
|
+
result: "block",
|
|
462
|
+
reason: "Unsupported data policy condition type"
|
|
463
|
+
};
|
|
464
|
+
return { result: result2, evidence: [result2] };
|
|
465
|
+
}
|
|
466
|
+
const value = condition.type === "parameter" ? readPath(ctx.parameters, condition.path) : readDataPolicySource(ctx, condition.left);
|
|
467
|
+
const operator = condition.operator;
|
|
468
|
+
const expected = condition.value;
|
|
469
|
+
const passed = evaluateOperator(value, operator, expected);
|
|
470
|
+
const result = {
|
|
471
|
+
conditionId: condition.conditionId,
|
|
472
|
+
passed,
|
|
473
|
+
result: passed ? condition.onPass ?? "pass" : condition.onFail ?? "block",
|
|
474
|
+
reason: passed ? void 0 : condition.reason
|
|
475
|
+
};
|
|
476
|
+
return { result, evidence: [result] };
|
|
477
|
+
}
|
|
478
|
+
function evaluateOperator(actual, operator, expected) {
|
|
479
|
+
switch (operator) {
|
|
480
|
+
case "exists":
|
|
481
|
+
return actual !== void 0 && actual !== null && actual !== "";
|
|
482
|
+
case "equals":
|
|
483
|
+
return actual === expected;
|
|
484
|
+
case "notEquals":
|
|
485
|
+
return actual !== expected;
|
|
486
|
+
case "gt":
|
|
487
|
+
return typeof actual === "number" && typeof expected === "number" && actual > expected;
|
|
488
|
+
case "gte":
|
|
489
|
+
return typeof actual === "number" && typeof expected === "number" && actual >= expected;
|
|
490
|
+
case "lt":
|
|
491
|
+
return typeof actual === "number" && typeof expected === "number" && actual < expected;
|
|
492
|
+
case "lte":
|
|
493
|
+
return typeof actual === "number" && typeof expected === "number" && actual <= expected;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
function readDataPolicySource(ctx, reference) {
|
|
497
|
+
if (reference.source === "parameters") {
|
|
498
|
+
return readPath(ctx.parameters, reference.path);
|
|
499
|
+
}
|
|
500
|
+
return readPath(
|
|
501
|
+
{
|
|
502
|
+
tenantId: ctx.tenantId,
|
|
503
|
+
spaceId: ctx.spaceId,
|
|
504
|
+
actionInvocationId: ctx.actionInvocationId,
|
|
505
|
+
actionId: ctx.actionId,
|
|
506
|
+
mode: ctx.mode
|
|
507
|
+
},
|
|
508
|
+
reference.path
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
function readPath(source, path) {
|
|
512
|
+
if (!source || typeof source !== "object") {
|
|
513
|
+
return void 0;
|
|
514
|
+
}
|
|
515
|
+
return path.split(".").reduce((current, segment) => {
|
|
516
|
+
if (!current || typeof current !== "object") {
|
|
517
|
+
return void 0;
|
|
518
|
+
}
|
|
519
|
+
return current[segment];
|
|
520
|
+
}, source);
|
|
521
|
+
}
|
|
522
|
+
function normalizeOutcome(policy, outcome, dispatchEvidence) {
|
|
523
|
+
return {
|
|
524
|
+
...outcome,
|
|
525
|
+
policyId: policy.policyId,
|
|
526
|
+
policyVersion: policy.policyVersion,
|
|
527
|
+
policyKind: policy.kind,
|
|
528
|
+
metadata: {
|
|
529
|
+
...outcome.metadata ?? {},
|
|
530
|
+
codePolicyId: dispatchEvidence.code?.policyId ?? outcome.policyId,
|
|
531
|
+
codePolicyVersion: dispatchEvidence.code?.version ?? outcome.policyVersion
|
|
532
|
+
},
|
|
533
|
+
dispatchEvidence
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
function parsePolicyVersion(policyId) {
|
|
537
|
+
const segments = policyId.split(".v");
|
|
538
|
+
return Number(segments[segments.length - 1] ?? 1);
|
|
539
|
+
}
|
|
540
|
+
function aggregatePolicyOutcomes(outcomes) {
|
|
541
|
+
return outcomes.find((outcome) => outcome.result === "block") ?? outcomes.find((outcome) => outcome.result === "warn");
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
exports.aggregatePolicyOutcomes = aggregatePolicyOutcomes;
|
|
545
|
+
exports.assertPolicyId = assertPolicyId;
|
|
546
|
+
exports.evaluatePolicyDefinition = evaluatePolicyDefinition;
|
|
547
|
+
exports.evaluatePolicyDefinitions = evaluatePolicyDefinitions;
|
|
548
|
+
exports.evaluateRegisteredPolicies = evaluateRegisteredPolicies;
|
|
549
|
+
exports.getRegisteredPolicyIds = getRegisteredPolicyIds;
|
|
550
|
+
exports.registerPolicy = registerPolicy;
|
|
551
|
+
exports.registerPolicyIfMissing = registerPolicyIfMissing;
|
|
552
|
+
exports.resolvePolicy = resolvePolicy;
|
|
553
|
+
exports.validateDataPolicyDefinition = validateDataPolicyDefinition;
|
|
554
|
+
//# sourceMappingURL=chunk-SDXDHVTV.cjs.map
|
|
555
|
+
//# sourceMappingURL=chunk-SDXDHVTV.cjs.map
|