@highflame/policy 2.0.8 → 2.0.9

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.
Files changed (126) hide show
  1. package/dist/actions.gen.d.ts +0 -1
  2. package/dist/actions.gen.js +0 -1
  3. package/dist/annotations.d.ts +0 -1
  4. package/dist/annotations.js +0 -1
  5. package/dist/builder.d.ts +0 -1
  6. package/dist/builder.js +0 -1
  7. package/dist/context.gen.d.ts +0 -1
  8. package/dist/context.gen.js +0 -1
  9. package/dist/engine.d.ts +0 -1
  10. package/dist/engine.js +0 -1
  11. package/dist/entities.gen.d.ts +0 -1
  12. package/dist/entities.gen.js +0 -1
  13. package/dist/entity-metadata-types.gen.d.ts +0 -1
  14. package/dist/entity-metadata-types.gen.js +0 -1
  15. package/dist/errors.d.ts +0 -1
  16. package/dist/errors.js +0 -1
  17. package/dist/index.d.ts +0 -1
  18. package/dist/index.js +0 -1
  19. package/dist/overwatch-context.gen.d.ts +0 -1
  20. package/dist/overwatch-context.gen.js +0 -1
  21. package/dist/overwatch-defaults.gen.d.ts +0 -1
  22. package/dist/overwatch-defaults.gen.js +0 -1
  23. package/dist/overwatch-entities.gen.d.ts +0 -1
  24. package/dist/overwatch-entities.gen.js +0 -1
  25. package/dist/palisade-context.gen.d.ts +0 -1
  26. package/dist/palisade-context.gen.js +0 -1
  27. package/dist/palisade-entities.gen.d.ts +0 -1
  28. package/dist/palisade-entities.gen.js +0 -1
  29. package/dist/parser.d.ts +0 -1
  30. package/dist/parser.js +0 -1
  31. package/dist/schema.gen.d.ts +0 -1
  32. package/dist/schema.gen.js +0 -1
  33. package/dist/schemas.d.ts +0 -1
  34. package/dist/schemas.js +0 -1
  35. package/dist/service-schemas.gen.d.ts +0 -1
  36. package/dist/service-schemas.gen.js +0 -1
  37. package/dist/types.d.ts +0 -1
  38. package/dist/types.js +0 -1
  39. package/package.json +1 -2
  40. package/dist/actions.gen.d.ts.map +0 -1
  41. package/dist/actions.gen.js.map +0 -1
  42. package/dist/annotations.d.ts.map +0 -1
  43. package/dist/annotations.js.map +0 -1
  44. package/dist/builder.d.ts.map +0 -1
  45. package/dist/builder.js.map +0 -1
  46. package/dist/context.gen.d.ts.map +0 -1
  47. package/dist/context.gen.js.map +0 -1
  48. package/dist/engine.d.ts.map +0 -1
  49. package/dist/engine.js.map +0 -1
  50. package/dist/engine.test.d.ts +0 -8
  51. package/dist/engine.test.d.ts.map +0 -1
  52. package/dist/engine.test.js +0 -190
  53. package/dist/engine.test.js.map +0 -1
  54. package/dist/entities.gen.d.ts.map +0 -1
  55. package/dist/entities.gen.js.map +0 -1
  56. package/dist/entity-metadata-types.gen.d.ts.map +0 -1
  57. package/dist/entity-metadata-types.gen.js.map +0 -1
  58. package/dist/errors.d.ts.map +0 -1
  59. package/dist/errors.js.map +0 -1
  60. package/dist/index.d.ts.map +0 -1
  61. package/dist/index.js.map +0 -1
  62. package/dist/overwatch-context.gen.d.ts.map +0 -1
  63. package/dist/overwatch-context.gen.js.map +0 -1
  64. package/dist/overwatch-defaults.gen.d.ts.map +0 -1
  65. package/dist/overwatch-defaults.gen.js.map +0 -1
  66. package/dist/overwatch-defaults.test.d.ts +0 -8
  67. package/dist/overwatch-defaults.test.d.ts.map +0 -1
  68. package/dist/overwatch-defaults.test.js +0 -145
  69. package/dist/overwatch-defaults.test.js.map +0 -1
  70. package/dist/overwatch-entities.gen.d.ts.map +0 -1
  71. package/dist/overwatch-entities.gen.js.map +0 -1
  72. package/dist/overwatch-rebac.test.d.ts +0 -25
  73. package/dist/overwatch-rebac.test.d.ts.map +0 -1
  74. package/dist/overwatch-rebac.test.js +0 -301
  75. package/dist/overwatch-rebac.test.js.map +0 -1
  76. package/dist/palisade-context.gen.d.ts.map +0 -1
  77. package/dist/palisade-context.gen.js.map +0 -1
  78. package/dist/palisade-entities.gen.d.ts.map +0 -1
  79. package/dist/palisade-entities.gen.js.map +0 -1
  80. package/dist/parser.d.ts.map +0 -1
  81. package/dist/parser.js.map +0 -1
  82. package/dist/parser.test.d.ts +0 -8
  83. package/dist/parser.test.d.ts.map +0 -1
  84. package/dist/parser.test.js +0 -212
  85. package/dist/parser.test.js.map +0 -1
  86. package/dist/schema.gen.d.ts.map +0 -1
  87. package/dist/schema.gen.js.map +0 -1
  88. package/dist/schemas.d.ts.map +0 -1
  89. package/dist/schemas.js.map +0 -1
  90. package/dist/schemas.test.d.ts +0 -8
  91. package/dist/schemas.test.d.ts.map +0 -1
  92. package/dist/schemas.test.js +0 -407
  93. package/dist/schemas.test.js.map +0 -1
  94. package/dist/service-schemas.gen.d.ts.map +0 -1
  95. package/dist/service-schemas.gen.js.map +0 -1
  96. package/dist/studio-ui.test.d.ts +0 -8
  97. package/dist/studio-ui.test.d.ts.map +0 -1
  98. package/dist/studio-ui.test.js +0 -687
  99. package/dist/studio-ui.test.js.map +0 -1
  100. package/dist/types.d.ts.map +0 -1
  101. package/dist/types.js.map +0 -1
  102. package/src/actions.gen.ts +0 -57
  103. package/src/annotations.ts +0 -243
  104. package/src/builder.ts +0 -799
  105. package/src/context.gen.ts +0 -10
  106. package/src/engine.test.ts +0 -370
  107. package/src/engine.ts +0 -497
  108. package/src/entities.gen.ts +0 -65
  109. package/src/entity-metadata-types.gen.ts +0 -19
  110. package/src/errors.ts +0 -195
  111. package/src/index.ts +0 -62
  112. package/src/overwatch-context.gen.ts +0 -45
  113. package/src/overwatch-defaults.gen.ts +0 -1255
  114. package/src/overwatch-defaults.test.ts +0 -176
  115. package/src/overwatch-entities.gen.ts +0 -41
  116. package/src/overwatch-rebac.test.ts +0 -346
  117. package/src/palisade-context.gen.ts +0 -28
  118. package/src/palisade-entities.gen.ts +0 -49
  119. package/src/parser.test.ts +0 -251
  120. package/src/parser.ts +0 -579
  121. package/src/schema.gen.ts +0 -134
  122. package/src/schemas.test.ts +0 -477
  123. package/src/schemas.ts +0 -91
  124. package/src/service-schemas.gen.ts +0 -608
  125. package/src/studio-ui.test.ts +0 -813
  126. package/src/types.ts +0 -66
package/src/parser.ts DELETED
@@ -1,579 +0,0 @@
1
- /**
2
- * Cedar Policy Parser
3
- *
4
- * Converts Cedar policy text to structured PolicyRule format using the
5
- * official Cedar engine (cedar-wasm) for parsing.
6
- *
7
- * Architecture:
8
- * 1. Cedar text → Cedar JSON (via cedar-wasm policyToJson)
9
- * 2. Cedar JSON → PolicyRule (simple JSON mapping with annotation extraction)
10
- */
11
-
12
- import * as cedar from "@cedar-policy/cedar-wasm/nodejs";
13
- import type { PolicyRule, PolicyCondition, PolicyEntity, PolicyEffect, ConditionOperator } from "./builder.js";
14
- import { parseAnnotations, generateRuleId } from "./annotations.js";
15
- import { ParserError, ErrorCodes } from "./errors.js";
16
-
17
- /**
18
- * Result of parsing Cedar policies
19
- */
20
- export interface ParseResult {
21
- /** Policies successfully converted to PolicyRule format */
22
- rules: PolicyRule[];
23
- /** Policies that couldn't be fully represented as PolicyRule (raw Cedar text) */
24
- unstructured: string[];
25
- /** Any parsing errors encountered */
26
- errors: string[];
27
- }
28
-
29
- /**
30
- * Cedar's JSON policy format (from cedar-wasm)
31
- * @see https://docs.cedarpolicy.com/policies/json-format.html
32
- */
33
- interface CedarPolicyJSON {
34
- effect: "permit" | "forbid";
35
- principal: CedarScopeConstraint;
36
- action: CedarActionConstraint;
37
- resource: CedarScopeConstraint;
38
- conditions: CedarCondition[];
39
- annotations?: Record<string, string>;
40
- }
41
-
42
- // Principal/Resource constraint types
43
- type CedarScopeConstraint =
44
- | { op: "All" }
45
- | { op: "=="; entity: CedarEntityRef }
46
- | { op: "=="; slot: string }
47
- | { op: "in"; entity: CedarEntityRef }
48
- | { op: "in"; slot: string }
49
- | { op: "is"; entity_type: string; in?: { entity: CedarEntityRef } | { slot: string } };
50
-
51
- // Action constraint types (slightly different from principal/resource)
52
- type CedarActionConstraint =
53
- | { op: "All" }
54
- | { op: "=="; entity: CedarEntityRef }
55
- | { op: "in"; entity: CedarEntityRef }
56
- | { op: "in"; entities: CedarEntityRef[] };
57
-
58
- // Entity UID can be { type, id } or { __entity: { type, id } }
59
- type CedarEntityRef =
60
- | { type: string; id: string }
61
- | { __entity: { type: string; id: string } };
62
-
63
- interface CedarCondition {
64
- kind: "when" | "unless";
65
- body: Record<string, unknown>;
66
- }
67
-
68
- /**
69
- * Normalize entity reference to simple { type, id } format
70
- */
71
- function normalizeEntityRef(ref: CedarEntityRef): { type: string; id: string } {
72
- if ("__entity" in ref) {
73
- return ref.__entity;
74
- }
75
- return ref;
76
- }
77
-
78
- /**
79
- * Parse Cedar policy text and convert to PolicyRule format.
80
- *
81
- * Uses the official cedar-wasm engine for parsing, ensuring correctness.
82
- * Policies with features that can't be represented as PolicyRule (e.g.,
83
- * unless clauses, complex expressions) are returned in the unstructured array.
84
- *
85
- * @param cedarText - Cedar policy text to parse
86
- * @returns ParseResult with structured rules, unstructured policies, and errors
87
- */
88
- export function parseCedarToRules(cedarText: string): ParseResult {
89
- const result: ParseResult = {
90
- rules: [],
91
- unstructured: [],
92
- errors: [],
93
- };
94
-
95
- try {
96
- // Split the policy set into individual policies and templates
97
- const partsResult = cedar.policySetTextToParts(cedarText);
98
-
99
- if (partsResult.type === "failure") {
100
- for (const error of partsResult.errors) {
101
- result.errors.push(error.message);
102
- }
103
- return result;
104
- }
105
-
106
- // Process each policy
107
- let index = 0;
108
- for (const policyText of partsResult.policies) {
109
- // Convert individual policy to JSON using cedar-wasm
110
- const jsonResult = cedar.policyToJson(policyText);
111
-
112
- if (jsonResult.type === "failure") {
113
- for (const error of jsonResult.errors) {
114
- result.errors.push(`Policy ${index}: ${error.message}`);
115
- }
116
- index++;
117
- continue;
118
- }
119
-
120
- const policy = jsonResult.json as CedarPolicyJSON;
121
- const policyId = policy.annotations?.id || `policy${index}`;
122
-
123
- // Get engine-serialized Cedar text for rawCondition extraction.
124
- // Using cedar-wasm's policyToText ensures we get the official engine's
125
- // representation rather than relying on our own text extraction.
126
- const engineTextResult = cedar.policyToText(jsonResult.json);
127
- const engineText = engineTextResult.type === "success" ? engineTextResult.text : policyText;
128
-
129
- const conversion = cedarJsonToRule(policy, policyId, index, engineText);
130
-
131
- if (conversion.error) {
132
- result.errors.push(`Policy ${policyId}: ${conversion.error}`);
133
- }
134
-
135
- if (conversion.rule) {
136
- result.rules.push(conversion.rule);
137
- } else if (conversion.raw) {
138
- result.unstructured.push(conversion.raw);
139
- }
140
-
141
- index++;
142
- }
143
-
144
- // Templates can't be represented as PolicyRule
145
- for (const templateText of partsResult.policy_templates) {
146
- result.unstructured.push(templateText);
147
- }
148
-
149
- } catch (e) {
150
- result.errors.push(`Parse error: ${e instanceof Error ? e.message : String(e)}`);
151
- }
152
-
153
- // Check for duplicate policy IDs and add warnings
154
- const idOccurrences = new Map<string, number[]>();
155
- result.rules.forEach((rule, idx) => {
156
- const ruleId = rule.annotations.id;
157
- if (ruleId) {
158
- const indices = idOccurrences.get(ruleId) || [];
159
- indices.push(idx);
160
- idOccurrences.set(ruleId, indices);
161
- }
162
- });
163
- for (const [id, indices] of idOccurrences) {
164
- if (indices.length > 1) {
165
- result.errors.push(
166
- `[${ErrorCodes.PARSE_DUPLICATE_ID}] Duplicate policy ID '${id}' found at indices [${indices.join(", ")}]`
167
- );
168
- }
169
- }
170
-
171
- return result;
172
- }
173
-
174
- /**
175
- * Convert Cedar JSON policy to PolicyRule.
176
- * This is pure JSON mapping - uses parseAnnotations to extract structured annotations.
177
- */
178
- function cedarJsonToRule(
179
- policy: CedarPolicyJSON,
180
- policyId: string,
181
- index: number,
182
- originalText?: string
183
- ): { rule?: PolicyRule; raw?: string; error?: string } {
184
-
185
- // Check if this policy can be represented as PolicyRule
186
- if (!canRepresentAsRule(policy)) {
187
- // Return original text if available, otherwise convert back from JSON
188
- const raw = originalText || getRawCedar(policyId, policy);
189
- return { raw };
190
- }
191
-
192
- try {
193
- // Parse annotations using the shared utility
194
- const { annotations, customAnnotations } = parseAnnotations(policy.annotations);
195
-
196
- // Ensure id and name have sensible defaults
197
- if (!annotations.id) {
198
- annotations.id = policyId || generateRuleId();
199
- }
200
- if (!annotations.name) {
201
- annotations.name = annotations.id;
202
- }
203
-
204
- const rule: PolicyRule = {
205
- annotations,
206
- customAnnotations,
207
- effect: policy.effect as PolicyEffect,
208
- principal: mapScopeToEntity(policy.principal, "principal"),
209
- action: mapActionScope(policy.action),
210
- resource: mapScopeToEntity(policy.resource, "resource"),
211
- conditions: [],
212
- enabled: true,
213
- order: index,
214
- };
215
-
216
- // Map conditions
217
- const { conditions, rawCondition } = mapConditions(policy.conditions, originalText);
218
- rule.conditions = conditions;
219
- if (rawCondition) {
220
- rule.rawCondition = rawCondition;
221
- }
222
-
223
- return { rule };
224
- } catch (e) {
225
- const error = e instanceof Error ? e.message : String(e);
226
- const raw = originalText || getRawCedar(policyId, policy);
227
- return { raw, error };
228
- }
229
- }
230
-
231
- /**
232
- * Check if a Cedar policy can be represented as PolicyRule
233
- */
234
- function canRepresentAsRule(policy: CedarPolicyJSON): boolean {
235
- // Unless clauses can't be represented
236
- for (const cond of policy.conditions) {
237
- if (cond.kind === "unless") {
238
- return false;
239
- }
240
- }
241
-
242
- // Template slots can't be represented
243
- if (hasSlot(policy.principal) || hasSlot(policy.resource)) {
244
- return false;
245
- }
246
-
247
- // Multiple entity "in" constraints are complex
248
- const action = policy.action;
249
- if (action.op === "in" && "entities" in action && action.entities.length > 1) {
250
- // Multiple actions are OK, we handle those
251
- }
252
-
253
- return true;
254
- }
255
-
256
- /**
257
- * Check if a scope constraint uses a slot (template)
258
- */
259
- function hasSlot(scope: CedarScopeConstraint): boolean {
260
- if (scope.op === "All" || scope.op === "is") {
261
- return false;
262
- }
263
- return "slot" in scope;
264
- }
265
-
266
- /**
267
- * Get raw Cedar text for a policy that can't be represented as PolicyRule
268
- */
269
- function getRawCedar(policyId: string, policy: CedarPolicyJSON): string {
270
- try {
271
- // policyToText accepts Policy which is string | PolicyJson
272
- const textResult = cedar.policyToText(policy as cedar.PolicyJson);
273
- if (textResult.type === "success") {
274
- return textResult.text;
275
- }
276
- } catch {
277
- // Ignore conversion errors
278
- }
279
- // Sanitize policyId to prevent newline injection attacks
280
- const safeId = policyId.replace(/[\n\r]/g, " ");
281
- return `// Complex policy: ${safeId}`;
282
- }
283
-
284
- /**
285
- * Map Cedar scope constraint to PolicyEntity
286
- *
287
- * Returns null for unconstrained ("All") scopes.
288
- * Throws ParserError for malformed constraints to prevent silent misinterpretation.
289
- *
290
- * @param scope - The Cedar scope constraint
291
- * @param field - The field name ("principal" or "resource") for error context
292
- */
293
- function mapScopeToEntity(scope: CedarScopeConstraint, field: string): PolicyEntity | null {
294
- if (scope.op === "All") {
295
- return null;
296
- }
297
-
298
- if (scope.op === "==") {
299
- if ("entity" in scope) {
300
- const entity = normalizeEntityRef(scope.entity);
301
- return { type: entity.type, id: entity.id };
302
- }
303
- if ("slot" in scope) {
304
- throw ParserError.scopeSlotNotSupported("==", field);
305
- }
306
- throw ParserError.scopeMissingEntity("==", field);
307
- }
308
-
309
- if (scope.op === "is") {
310
- if (scope.entity_type) {
311
- return { type: scope.entity_type };
312
- }
313
- throw ParserError.scopeMissingEntityType(field);
314
- }
315
-
316
- if (scope.op === "in") {
317
- if ("entity" in scope) {
318
- const entity = normalizeEntityRef(scope.entity);
319
- return { type: entity.type, id: entity.id };
320
- }
321
- if ("slot" in scope) {
322
- throw ParserError.scopeSlotNotSupported("in", field);
323
- }
324
- throw ParserError.scopeMissingEntityList(field);
325
- }
326
-
327
- throw ParserError.scopeUnsupportedOp((scope as { op: string }).op, field);
328
- }
329
-
330
- /**
331
- * Map action scope to action string(s)
332
- *
333
- * Throws ParserError for malformed constraints to prevent silent misinterpretation.
334
- */
335
- /**
336
- * Format action entity reference, preserving namespace if present.
337
- *
338
- * If entity type is just "Action", returns just the id (e.g., "process_prompt").
339
- * If entity type has a namespace (e.g., "Overwatch::Action"),
340
- * returns the fully qualified action string (e.g., 'Overwatch::Action::"process_prompt"').
341
- */
342
- function formatActionEntity(entity: { type: string; id: string }): string {
343
- if (entity.type !== "Action") {
344
- return `${entity.type}::"${entity.id}"`;
345
- }
346
- return entity.id;
347
- }
348
-
349
- function mapActionScope(scope: CedarActionConstraint): string | string[] {
350
- if (scope.op === "All") {
351
- return "*";
352
- }
353
-
354
- if (scope.op === "==") {
355
- if ("entity" in scope) {
356
- const entity = normalizeEntityRef(scope.entity);
357
- return formatActionEntity(entity);
358
- }
359
- throw ParserError.actionMissingEntity("==");
360
- }
361
-
362
- if (scope.op === "in") {
363
- if ("entities" in scope) {
364
- const actions = scope.entities.map(e => formatActionEntity(normalizeEntityRef(e)));
365
- return actions.length === 1 ? actions[0] : actions;
366
- }
367
- if ("entity" in scope) {
368
- const entity = normalizeEntityRef(scope.entity);
369
- return formatActionEntity(entity);
370
- }
371
- throw ParserError.actionMissingEntities();
372
- }
373
-
374
- throw ParserError.actionUnsupportedOp((scope as { op: string }).op);
375
- }
376
-
377
- /**
378
- * Map Cedar conditions to PolicyCondition array.
379
- * When conditions can't be mapped to structured format, extract the raw Cedar
380
- * condition text from the engine-serialized policy text (not JSON AST).
381
- */
382
- function mapConditions(conditions: CedarCondition[], originalText?: string): {
383
- conditions: PolicyCondition[];
384
- rawCondition?: string;
385
- } {
386
- const result: PolicyCondition[] = [];
387
- let hasUnmapped = false;
388
-
389
- for (const cond of conditions) {
390
- if (cond.kind !== "when") {
391
- continue;
392
- }
393
-
394
- const parsed = mapConditionBody(cond.body);
395
- if (parsed.condition) {
396
- result.push(parsed.condition);
397
- } else if (parsed.raw) {
398
- hasUnmapped = true;
399
- }
400
- }
401
-
402
- // Extract readable Cedar condition text instead of storing JSON AST
403
- let rawCondition: string | undefined;
404
- if (hasUnmapped && originalText) {
405
- rawCondition = extractWhenClause(originalText);
406
- }
407
-
408
- return {
409
- conditions: result,
410
- rawCondition: rawCondition || undefined,
411
- };
412
- }
413
-
414
- /**
415
- * Extract the readable condition text from a Cedar policy's when clause.
416
- * Given: `forbid (...)\nwhen { context.path like "/etc/*" };`
417
- * Returns: `context.path like "/etc/*"`
418
- */
419
- function extractWhenClause(cedarText: string): string {
420
- const whenPrefix = "when {";
421
- const idx = cedarText.indexOf(whenPrefix);
422
- if (idx < 0) {
423
- return "";
424
- }
425
-
426
- const body = cedarText.substring(idx + whenPrefix.length);
427
- let depth = 1;
428
- for (let i = 0; i < body.length; i++) {
429
- if (body[i] === "{") depth++;
430
- if (body[i] === "}") {
431
- depth--;
432
- if (depth === 0) {
433
- return body.substring(0, i).trim();
434
- }
435
- }
436
- }
437
-
438
- return body.trim();
439
- }
440
-
441
- /**
442
- * Cedar expression types (subset used for condition mapping)
443
- */
444
- interface CedarExpr {
445
- "."?: { left: CedarExpr; attr: string };
446
- Var?: string;
447
- Value?: unknown;
448
- "=="?: { left: CedarExpr; right: CedarExpr };
449
- "!="?: { left: CedarExpr; right: CedarExpr };
450
- "<"?: { left: CedarExpr; right: CedarExpr };
451
- "<="?: { left: CedarExpr; right: CedarExpr };
452
- ">"?: { left: CedarExpr; right: CedarExpr };
453
- ">="?: { left: CedarExpr; right: CedarExpr };
454
- contains?: { left: CedarExpr; right: CedarExpr };
455
- like?: { left: CedarExpr; pattern: Array<"Wildcard" | { Literal: string }> };
456
- }
457
-
458
- /**
459
- * Map a Cedar expression body to PolicyCondition
460
- *
461
- * Cedar JSON expressions use nested objects with operator keys.
462
- * Comparison format: { "==": { left: { ".": { left: { Var: "context" }, attr: "field" } }, right: { Value: "x" } } }
463
- */
464
- function mapConditionBody(body: Record<string, unknown>): {
465
- condition?: PolicyCondition;
466
- raw?: string;
467
- } {
468
- const expr = body as CedarExpr;
469
-
470
- // Check comparison operators
471
- for (const op of ["==", "!=", "<", "<=", ">", ">="] as const) {
472
- const comparison = expr[op];
473
- if (comparison) {
474
- const condition = mapComparison(op, comparison);
475
- if (condition) return { condition };
476
- }
477
- }
478
-
479
- // Check contains
480
- if (expr.contains) {
481
- const condition = mapContains(expr.contains);
482
- if (condition) return { condition };
483
- }
484
-
485
- // Check like
486
- if (expr.like) {
487
- const condition = mapLike(expr.like);
488
- if (condition) return { condition };
489
- }
490
-
491
- // Can't map - return as raw JSON
492
- return { raw: JSON.stringify(body) };
493
- }
494
-
495
- function mapComparison(op: string, args: { left: CedarExpr; right: CedarExpr }): PolicyCondition | null {
496
- const field = extractContextField(args.left);
497
- if (!field) return null;
498
-
499
- const value = extractLiteralValue(args.right);
500
- if (value === undefined) return null;
501
-
502
- const operator = mapOperator(op);
503
- if (!operator) return null;
504
-
505
- return { field, operator, value };
506
- }
507
-
508
- function mapContains(args: { left: CedarExpr; right: CedarExpr }): PolicyCondition | null {
509
- const field = extractContextField(args.left);
510
- if (!field) return null;
511
-
512
- const value = extractLiteralValue(args.right);
513
- if (value === undefined) return null;
514
-
515
- return { field, operator: "contains", value };
516
- }
517
-
518
- function mapLike(args: { left: CedarExpr; pattern: Array<"Wildcard" | { Literal: string }> }): PolicyCondition | null {
519
- const field = extractContextField(args.left);
520
- if (!field) return null;
521
-
522
- // Convert pattern to string (e.g., ["Wildcard", { Literal: "foo" }, "Wildcard"] -> "*foo*")
523
- // Escape literal * characters to distinguish from wildcards on round-trip
524
- const patternStr = args.pattern.map(p => {
525
- if (p === "Wildcard") return "*";
526
- if (typeof p === "object" && "Literal" in p) return p.Literal.replace(/\*/g, "\\*");
527
- return "";
528
- }).join("");
529
-
530
- return { field, operator: "like", value: patternStr };
531
- }
532
-
533
- /**
534
- * Extract field name from context.field access pattern
535
- * Pattern: { ".": { left: { Var: "context" }, attr: "field_name" } }
536
- */
537
- function extractContextField(expr: CedarExpr): string | null {
538
- const dotAccess = expr["."];
539
- if (!dotAccess) return null;
540
-
541
- // Check if accessing context variable
542
- const leftExpr = dotAccess.left;
543
- if (leftExpr.Var !== "context") return null;
544
-
545
- return dotAccess.attr;
546
- }
547
-
548
- /**
549
- * Extract literal value from Cedar JSON
550
- * Pattern: { Value: <literal> }
551
- */
552
- function extractLiteralValue(expr: CedarExpr): string | number | boolean | string[] | undefined {
553
- if (!("Value" in expr)) return undefined;
554
-
555
- const value = expr.Value;
556
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
557
- return value;
558
- }
559
- if (Array.isArray(value) && value.every(v => typeof v === "string")) {
560
- return value as string[];
561
- }
562
-
563
- return undefined;
564
- }
565
-
566
- /**
567
- * Map Cedar operator to ConditionOperator
568
- */
569
- function mapOperator(cedarOp: string): ConditionOperator | null {
570
- const mapping: Record<string, ConditionOperator> = {
571
- "==": "eq",
572
- "!=": "neq",
573
- "<": "lt",
574
- "<=": "lte",
575
- ">": "gt",
576
- ">=": "gte",
577
- };
578
- return mapping[cedarOp] || null;
579
- }
package/src/schema.gen.ts DELETED
@@ -1,134 +0,0 @@
1
- // Code generated by highflame-policy-codegen. DO NOT EDIT.
2
- // Source: schema/highflame.cedarschema
3
-
4
- /**
5
- * Embedded Cedar schema for policy validation.
6
- * This is the Highflame Cedar schema used across all services.
7
- */
8
- export const CEDAR_SCHEMA = `// Highflame Cedar Schema - Entity and Action Definitions
9
- // =======================================================
10
- // This file defines all entity types and actions used across Highflame services.
11
- // Used for code generation (EntityType and ActionType constants).
12
- //
13
- // For policy validation, use service-specific schemas:
14
- // - schemas/overwatch/schema.cedarschema (Guardian IDE security)
15
- // - schemas/palisade/schema.cedarschema (ML supply chain security)
16
-
17
- namespace Highflame {
18
-
19
- // =============================================================================
20
- // ENTITIES
21
- // =============================================================================
22
-
23
- entity User {
24
- user_type: String,
25
- };
26
-
27
- entity Agent {
28
- agent_type: String,
29
- };
30
-
31
- entity Scanner {
32
- scanner_type: String,
33
- };
34
-
35
- entity Service {
36
- service_type: String,
37
- };
38
-
39
- entity Resource {};
40
-
41
- entity LlmPrompt {
42
- prompt_type: String,
43
- };
44
-
45
- entity ResponseData {};
46
-
47
- entity Tool {
48
- tool_name: String,
49
- };
50
-
51
- entity FilePath {
52
- path: String,
53
- };
54
-
55
- entity HttpEndpoint {
56
- hostname: String,
57
- };
58
-
59
- entity Server {
60
- server_name: String,
61
- };
62
-
63
- entity Artifact {
64
- artifact_format: String,
65
- };
66
-
67
- entity Repository {
68
- repo_url: String,
69
- };
70
-
71
- entity Package {
72
- package_name: String,
73
- };
74
-
75
- entity GitBranch {
76
- branch_name: String,
77
- };
78
-
79
- entity Model {
80
- model_name: String,
81
- };
82
-
83
- entity ExternalAPI {
84
- api_name: String,
85
- };
86
-
87
- entity Memory {
88
- memory_type: String,
89
- };
90
-
91
- // =============================================================================
92
- // ACTIONS
93
- // =============================================================================
94
-
95
- action process_prompt;
96
- action process_response;
97
- action invoke_model;
98
- action filter_content;
99
- action call_tool;
100
- action connect_server;
101
- action access_server_resource;
102
- action skip_guardrails;
103
- action read_file;
104
- action write_file;
105
- action delete_file;
106
- action http_request;
107
- action call_external_api;
108
- action execute_code;
109
- action run_tests;
110
- action run_build;
111
- action git_operation;
112
- action git_clone;
113
- action git_commit;
114
- action git_push;
115
- action git_pull;
116
- action git_merge;
117
- action git_checkout;
118
- action git_reset;
119
- action git_rebase;
120
- action delegate_task;
121
- action spawn_subprocess;
122
- action access_memory;
123
- action scan_target;
124
- action scan_package;
125
- action scan_artifact;
126
- action validate_integrity;
127
- action validate_provenance;
128
- action quarantine_artifact;
129
- action load_model;
130
- action deploy_model;
131
- action transfer_data;
132
- action export_data;
133
- }
134
- `;