@highflame/policy 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +219 -0
  2. package/_schemas/overwatch/context.json +463 -0
  3. package/_schemas/overwatch/schema.cedarschema +184 -0
  4. package/_schemas/palisade/context.json +325 -0
  5. package/_schemas/palisade/schema.cedarschema +168 -0
  6. package/dist/builder.d.ts +1 -2
  7. package/dist/builder.d.ts.map +1 -1
  8. package/dist/builder.js.map +1 -1
  9. package/dist/context.gen.d.ts +1 -94
  10. package/dist/context.gen.d.ts.map +1 -1
  11. package/dist/context.gen.js +1 -97
  12. package/dist/context.gen.js.map +1 -1
  13. package/dist/engine.d.ts +18 -18
  14. package/dist/engine.d.ts.map +1 -1
  15. package/dist/engine.js +44 -28
  16. package/dist/engine.js.map +1 -1
  17. package/dist/engine.test.js.map +1 -1
  18. package/dist/entities.gen.d.ts +1 -0
  19. package/dist/entities.gen.d.ts.map +1 -1
  20. package/dist/entities.gen.js +1 -0
  21. package/dist/entities.gen.js.map +1 -1
  22. package/dist/errors.d.ts +102 -0
  23. package/dist/errors.d.ts.map +1 -0
  24. package/dist/errors.js +127 -0
  25. package/dist/errors.js.map +1 -0
  26. package/dist/index.d.ts +2 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +2 -0
  29. package/dist/index.js.map +1 -1
  30. package/dist/overwatch-context.gen.d.ts +31 -0
  31. package/dist/overwatch-context.gen.d.ts.map +1 -0
  32. package/dist/overwatch-context.gen.js +32 -0
  33. package/dist/overwatch-context.gen.js.map +1 -0
  34. package/dist/palisade-context.gen.d.ts +25 -0
  35. package/dist/palisade-context.gen.d.ts.map +1 -0
  36. package/dist/palisade-context.gen.js +26 -0
  37. package/dist/palisade-context.gen.js.map +1 -0
  38. package/dist/parser.d.ts.map +1 -1
  39. package/dist/parser.js +79 -34
  40. package/dist/parser.js.map +1 -1
  41. package/dist/parser.test.js +44 -0
  42. package/dist/parser.test.js.map +1 -1
  43. package/dist/schema.gen.d.ts +1 -1
  44. package/dist/schema.gen.d.ts.map +1 -1
  45. package/dist/schema.gen.js +60 -541
  46. package/dist/schema.gen.js.map +1 -1
  47. package/dist/schemas.d.ts +64 -0
  48. package/dist/schemas.d.ts.map +1 -0
  49. package/dist/schemas.js +70 -0
  50. package/dist/schemas.js.map +1 -0
  51. package/dist/schemas.test.d.ts +8 -0
  52. package/dist/schemas.test.d.ts.map +1 -0
  53. package/dist/schemas.test.js +381 -0
  54. package/dist/schemas.test.js.map +1 -0
  55. package/dist/types.d.ts +1 -0
  56. package/dist/types.d.ts.map +1 -1
  57. package/dist/types.js +2 -0
  58. package/dist/types.js.map +1 -1
  59. package/package.json +13 -6
  60. package/src/builder.ts +1 -2
  61. package/src/context.gen.ts +0 -97
  62. package/src/engine.test.ts +0 -1
  63. package/src/engine.ts +62 -33
  64. package/src/entities.gen.ts +1 -0
  65. package/src/errors.ts +195 -0
  66. package/src/index.ts +2 -0
  67. package/src/overwatch-context.gen.ts +34 -0
  68. package/src/palisade-context.gen.ts +28 -0
  69. package/src/parser.test.ts +53 -0
  70. package/src/parser.ts +83 -36
  71. package/src/schema.gen.ts +60 -541
  72. package/src/schemas.test.ts +449 -0
  73. package/src/schemas.ts +91 -0
  74. package/src/types.ts +3 -0
@@ -10,6 +10,7 @@ export const EntityType = {
10
10
  FilePath: 'FilePath',
11
11
  GitBranch: 'GitBranch',
12
12
  HttpEndpoint: 'HttpEndpoint',
13
+ LlmPrompt: 'LlmPrompt',
13
14
  Memory: 'Memory',
14
15
  Model: 'Model',
15
16
  Package: 'Package',
@@ -1 +1 @@
1
- {"version":3,"file":"entities.gen.js","sourceRoot":"","sources":["../src/entities.gen.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,uCAAuC;AAEvC;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACtB,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,UAAU;IACpB,WAAW,EAAE,aAAa;IAC1B,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;IACtB,YAAY,EAAE,cAAc;IAC5B,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,UAAU,EAAE,YAAY;IACxB,QAAQ,EAAE,UAAU;IACpB,YAAY,EAAE,cAAc;IAC5B,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;CACN,CAAC;AAqBX;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAyB,EAAE,EAAU;IAC9D,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAyB,EAAE,EAAU,EAAE,KAA+B;IAC5F,OAAO;QACH,GAAG,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,KAAK,EAAE,KAAK,IAAI,EAAE;QAClB,OAAO,EAAE,EAAE;KACd,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"entities.gen.js","sourceRoot":"","sources":["../src/entities.gen.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,uCAAuC;AAEvC;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACtB,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,UAAU;IACpB,WAAW,EAAE,aAAa;IAC1B,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;IACtB,YAAY,EAAE,cAAc;IAC5B,SAAS,EAAE,WAAW;IACtB,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,UAAU,EAAE,YAAY;IACxB,QAAQ,EAAE,UAAU;IACpB,YAAY,EAAE,cAAc;IAC5B,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;CACN,CAAC;AAqBX;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAyB,EAAE,EAAU;IAC9D,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAyB,EAAE,EAAU,EAAE,KAA+B;IAC5F,OAAO;QACH,GAAG,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,KAAK,EAAE,KAAK,IAAI,EAAE;QAClB,OAAO,EAAE,EAAE;KACd,CAAC;AACN,CAAC"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Parser error types and codes for highflame-policy.
3
+ *
4
+ * This module provides standardized error codes that are consistent
5
+ * across all language implementations (Rust, Go, TypeScript, Python).
6
+ */
7
+ /**
8
+ * Error codes for parser errors.
9
+ *
10
+ * These codes are stable and consistent across all language implementations.
11
+ * Format: HFP-<CATEGORY>-<NUMBER>
12
+ * - HFP = HighFlame Policy
13
+ * - CATEGORY = SCOPE | ACTION | COND | PARSE
14
+ * - NUMBER = 3-digit incremental
15
+ */
16
+ export declare const ErrorCodes: {
17
+ /** Scope constraint is missing an entity (for == operator) */
18
+ readonly SCOPE_MISSING_ENTITY: "HFP-SCOPE-001";
19
+ /** Scope constraint is missing an entity type (for is operator) */
20
+ readonly SCOPE_MISSING_ENTITY_TYPE: "HFP-SCOPE-002";
21
+ /** Scope constraint is missing entity list (for in operator) */
22
+ readonly SCOPE_MISSING_ENTITY_LIST: "HFP-SCOPE-003";
23
+ /** Slot constraints are not supported in PolicyRule */
24
+ readonly SCOPE_SLOT_NOT_SUPPORTED: "HFP-SCOPE-004";
25
+ /** Unsupported scope operator */
26
+ readonly SCOPE_UNSUPPORTED_OP: "HFP-SCOPE-005";
27
+ /** Action constraint is missing an entity (for == operator) */
28
+ readonly ACTION_MISSING_ENTITY: "HFP-ACTION-001";
29
+ /** Action constraint is missing entities (for in operator) */
30
+ readonly ACTION_MISSING_ENTITIES: "HFP-ACTION-002";
31
+ /** Unsupported action operator */
32
+ readonly ACTION_UNSUPPORTED_OP: "HFP-ACTION-003";
33
+ /** Action scope is null/nil */
34
+ readonly ACTION_SCOPE_NIL: "HFP-ACTION-004";
35
+ /** Unless clauses are not supported in PolicyRule */
36
+ readonly COND_UNLESS_NOT_SUPPORTED: "HFP-COND-001";
37
+ /** Complex condition cannot be parsed */
38
+ readonly COND_COMPLEX_EXPRESSION: "HFP-COND-002";
39
+ /** Invalid Cedar syntax */
40
+ readonly PARSE_INVALID_SYNTAX: "HFP-PARSE-001";
41
+ /** Failed to convert policy to JSON */
42
+ readonly PARSE_JSON_CONVERSION: "HFP-PARSE-002";
43
+ /** Failed to parse Cedar JSON structure */
44
+ readonly PARSE_JSON_STRUCTURE: "HFP-PARSE-003";
45
+ /** Unknown policy effect (not permit or forbid) */
46
+ readonly PARSE_UNKNOWN_EFFECT: "HFP-PARSE-004";
47
+ /** Duplicate policy ID found */
48
+ readonly PARSE_DUPLICATE_ID: "HFP-PARSE-005";
49
+ };
50
+ export type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
51
+ /**
52
+ * Context information for parser errors.
53
+ */
54
+ export interface ErrorContext {
55
+ /** The operator that caused the error (e.g., "==", "in", "is") */
56
+ operator?: string;
57
+ /** The field that caused the error (e.g., "principal", "action", "resource") */
58
+ field?: string;
59
+ /** The policy ID if available */
60
+ policyId?: string;
61
+ }
62
+ /**
63
+ * A structured parser error with code, message, and optional context.
64
+ */
65
+ export declare class ParserError extends Error {
66
+ /** Machine-readable error code (e.g., "HFP-SCOPE-001") */
67
+ readonly code: ErrorCode;
68
+ /** Optional context for debugging */
69
+ readonly context?: ErrorContext;
70
+ constructor(code: ErrorCode, message: string, context?: ErrorContext);
71
+ /**
72
+ * Returns a string representation including the error code.
73
+ */
74
+ toString(): string;
75
+ /**
76
+ * Serializes the error to a plain object for JSON serialization.
77
+ */
78
+ toJSON(): {
79
+ code: string;
80
+ message: string;
81
+ context?: ErrorContext;
82
+ };
83
+ /** Scope constraint is missing an entity */
84
+ static scopeMissingEntity(operator: string, field: string): ParserError;
85
+ /** Scope constraint is missing an entity type */
86
+ static scopeMissingEntityType(field: string): ParserError;
87
+ /** Scope constraint is missing entity list */
88
+ static scopeMissingEntityList(field: string): ParserError;
89
+ /** Slot constraints are not supported */
90
+ static scopeSlotNotSupported(operator: string, field: string): ParserError;
91
+ /** Unsupported scope operator */
92
+ static scopeUnsupportedOp(operator: string, field: string): ParserError;
93
+ /** Action constraint is missing an entity */
94
+ static actionMissingEntity(operator: string): ParserError;
95
+ /** Action constraint is missing entities */
96
+ static actionMissingEntities(): ParserError;
97
+ /** Unsupported action operator */
98
+ static actionUnsupportedOp(operator: string): ParserError;
99
+ /** Action scope is nil */
100
+ static actionScopeNil(): ParserError;
101
+ }
102
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU;IAErB,8DAA8D;;IAE9D,mEAAmE;;IAEnE,gEAAgE;;IAEhE,uDAAuD;;IAEvD,iCAAiC;;IAIjC,+DAA+D;;IAE/D,8DAA8D;;IAE9D,kCAAkC;;IAElC,+BAA+B;;IAI/B,qDAAqD;;IAErD,yCAAyC;;IAIzC,2BAA2B;;IAE3B,uCAAuC;;IAEvC,2CAA2C;;IAE3C,mDAAmD;;IAEnD,gCAAgC;;CAExB,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC,0DAA0D;IAC1D,SAAgB,IAAI,EAAE,SAAS,CAAC;IAChC,qCAAqC;IACrC,SAAgB,OAAO,CAAC,EAAE,YAAY,CAAC;gBAE3B,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;IAapE;;OAEG;IACM,QAAQ,IAAI,MAAM;IAI3B;;OAEG;IACH,MAAM,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,YAAY,CAAA;KAAE;IAUnE,4CAA4C;IAC5C,MAAM,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW;IAQvE,iDAAiD;IACjD,MAAM,CAAC,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW;IAQzD,8CAA8C;IAC9C,MAAM,CAAC,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW;IAQzD,yCAAyC;IACzC,MAAM,CAAC,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW;IAQ1E,iCAAiC;IACjC,MAAM,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW;IAQvE,6CAA6C;IAC7C,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW;IAQzD,4CAA4C;IAC5C,MAAM,CAAC,qBAAqB,IAAI,WAAW;IAQ3C,kCAAkC;IAClC,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW;IAQzD,0BAA0B;IAC1B,MAAM,CAAC,cAAc,IAAI,WAAW;CAOrC"}
package/dist/errors.js ADDED
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Parser error types and codes for highflame-policy.
3
+ *
4
+ * This module provides standardized error codes that are consistent
5
+ * across all language implementations (Rust, Go, TypeScript, Python).
6
+ */
7
+ /**
8
+ * Error codes for parser errors.
9
+ *
10
+ * These codes are stable and consistent across all language implementations.
11
+ * Format: HFP-<CATEGORY>-<NUMBER>
12
+ * - HFP = HighFlame Policy
13
+ * - CATEGORY = SCOPE | ACTION | COND | PARSE
14
+ * - NUMBER = 3-digit incremental
15
+ */
16
+ export const ErrorCodes = {
17
+ // Scope constraint errors (HFP-SCOPE-xxx)
18
+ /** Scope constraint is missing an entity (for == operator) */
19
+ SCOPE_MISSING_ENTITY: "HFP-SCOPE-001",
20
+ /** Scope constraint is missing an entity type (for is operator) */
21
+ SCOPE_MISSING_ENTITY_TYPE: "HFP-SCOPE-002",
22
+ /** Scope constraint is missing entity list (for in operator) */
23
+ SCOPE_MISSING_ENTITY_LIST: "HFP-SCOPE-003",
24
+ /** Slot constraints are not supported in PolicyRule */
25
+ SCOPE_SLOT_NOT_SUPPORTED: "HFP-SCOPE-004",
26
+ /** Unsupported scope operator */
27
+ SCOPE_UNSUPPORTED_OP: "HFP-SCOPE-005",
28
+ // Action constraint errors (HFP-ACTION-xxx)
29
+ /** Action constraint is missing an entity (for == operator) */
30
+ ACTION_MISSING_ENTITY: "HFP-ACTION-001",
31
+ /** Action constraint is missing entities (for in operator) */
32
+ ACTION_MISSING_ENTITIES: "HFP-ACTION-002",
33
+ /** Unsupported action operator */
34
+ ACTION_UNSUPPORTED_OP: "HFP-ACTION-003",
35
+ /** Action scope is null/nil */
36
+ ACTION_SCOPE_NIL: "HFP-ACTION-004",
37
+ // Condition errors (HFP-COND-xxx)
38
+ /** Unless clauses are not supported in PolicyRule */
39
+ COND_UNLESS_NOT_SUPPORTED: "HFP-COND-001",
40
+ /** Complex condition cannot be parsed */
41
+ COND_COMPLEX_EXPRESSION: "HFP-COND-002",
42
+ // Parse errors (HFP-PARSE-xxx)
43
+ /** Invalid Cedar syntax */
44
+ PARSE_INVALID_SYNTAX: "HFP-PARSE-001",
45
+ /** Failed to convert policy to JSON */
46
+ PARSE_JSON_CONVERSION: "HFP-PARSE-002",
47
+ /** Failed to parse Cedar JSON structure */
48
+ PARSE_JSON_STRUCTURE: "HFP-PARSE-003",
49
+ /** Unknown policy effect (not permit or forbid) */
50
+ PARSE_UNKNOWN_EFFECT: "HFP-PARSE-004",
51
+ /** Duplicate policy ID found */
52
+ PARSE_DUPLICATE_ID: "HFP-PARSE-005",
53
+ };
54
+ /**
55
+ * A structured parser error with code, message, and optional context.
56
+ */
57
+ export class ParserError extends Error {
58
+ /** Machine-readable error code (e.g., "HFP-SCOPE-001") */
59
+ code;
60
+ /** Optional context for debugging */
61
+ context;
62
+ constructor(code, message, context) {
63
+ super(message);
64
+ this.name = "ParserError";
65
+ this.code = code;
66
+ this.context = context;
67
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
68
+ const ErrorWithCapture = Error;
69
+ if (ErrorWithCapture.captureStackTrace) {
70
+ ErrorWithCapture.captureStackTrace(this, ParserError);
71
+ }
72
+ }
73
+ /**
74
+ * Returns a string representation including the error code.
75
+ */
76
+ toString() {
77
+ return `[${this.code}] ${this.message}`;
78
+ }
79
+ /**
80
+ * Serializes the error to a plain object for JSON serialization.
81
+ */
82
+ toJSON() {
83
+ return {
84
+ code: this.code,
85
+ message: this.message,
86
+ ...(this.context && { context: this.context }),
87
+ };
88
+ }
89
+ // Convenience static factory methods for common errors
90
+ /** Scope constraint is missing an entity */
91
+ static scopeMissingEntity(operator, field) {
92
+ return new ParserError(ErrorCodes.SCOPE_MISSING_ENTITY, `'${operator}' constraint is missing an entity`, { operator, field });
93
+ }
94
+ /** Scope constraint is missing an entity type */
95
+ static scopeMissingEntityType(field) {
96
+ return new ParserError(ErrorCodes.SCOPE_MISSING_ENTITY_TYPE, "'is' constraint is missing an entity_type", { operator: "is", field });
97
+ }
98
+ /** Scope constraint is missing entity list */
99
+ static scopeMissingEntityList(field) {
100
+ return new ParserError(ErrorCodes.SCOPE_MISSING_ENTITY_LIST, "'in' constraint is missing an entity", { operator: "in", field });
101
+ }
102
+ /** Slot constraints are not supported */
103
+ static scopeSlotNotSupported(operator, field) {
104
+ return new ParserError(ErrorCodes.SCOPE_SLOT_NOT_SUPPORTED, `'${operator}' constraint with slot cannot be represented`, { operator, field });
105
+ }
106
+ /** Unsupported scope operator */
107
+ static scopeUnsupportedOp(operator, field) {
108
+ return new ParserError(ErrorCodes.SCOPE_UNSUPPORTED_OP, `Unsupported scope operator: ${operator}`, { operator, field });
109
+ }
110
+ /** Action constraint is missing an entity */
111
+ static actionMissingEntity(operator) {
112
+ return new ParserError(ErrorCodes.ACTION_MISSING_ENTITY, `Action '${operator}' constraint is missing an entity`, { operator, field: "action" });
113
+ }
114
+ /** Action constraint is missing entities */
115
+ static actionMissingEntities() {
116
+ return new ParserError(ErrorCodes.ACTION_MISSING_ENTITIES, "Action 'in' constraint is missing entities", { operator: "in", field: "action" });
117
+ }
118
+ /** Unsupported action operator */
119
+ static actionUnsupportedOp(operator) {
120
+ return new ParserError(ErrorCodes.ACTION_UNSUPPORTED_OP, `Unsupported action operator: ${operator}`, { operator, field: "action" });
121
+ }
122
+ /** Action scope is nil */
123
+ static actionScopeNil() {
124
+ return new ParserError(ErrorCodes.ACTION_SCOPE_NIL, "Action scope is nil", { field: "action" });
125
+ }
126
+ }
127
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -4,4 +4,6 @@ export * from './context.gen.js';
4
4
  export * from './schema.gen.js';
5
5
  export * from './engine.js';
6
6
  export * from './builder.js';
7
+ export * from './parser.js';
8
+ export * from './errors.js';
7
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAGhC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAGhC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -10,4 +10,6 @@ export * from './schema.gen.js';
10
10
  // Non-generated modules (require Node.js)
11
11
  export * from './engine.js';
12
12
  export * from './builder.js';
13
+ export * from './parser.js';
14
+ export * from './errors.js';
13
15
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,uCAAuC;AACvC,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AAEpE,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAEhC,0CAA0C;AAC1C,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,uCAAuC;AACvC,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AAEpE,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAEhC,0CAA0C;AAC1C,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Context attribute keys for Overwatch Overwatch (Guardian) IDE security & policy enforcement.
3
+ *
4
+ * These constants correspond to the context attributes defined in the
5
+ * Overwatch Cedar schema and are used at policy evaluation time.
6
+ */
7
+ export declare const OverwatchContextKey: {
8
+ readonly ContainsSecrets: "contains_secrets";
9
+ readonly Content: "content";
10
+ readonly Cwd: "cwd";
11
+ readonly Event: "event";
12
+ readonly FilePath: "file_path";
13
+ readonly HighestSeverity: "highest_severity";
14
+ readonly MaxThreatSeverity: "max_threat_severity";
15
+ readonly McpServer: "mcp_server";
16
+ readonly McpTool: "mcp_tool";
17
+ readonly Path: "path";
18
+ readonly PromptText: "prompt_text";
19
+ readonly ResponseContent: "response_content";
20
+ readonly ServerName: "server_name";
21
+ readonly Source: "source";
22
+ readonly ThreatCategories: "threat_categories";
23
+ readonly ThreatCount: "threat_count";
24
+ readonly ThreatTypes: "threat_types";
25
+ readonly ToolName: "tool_name";
26
+ readonly UserEmail: "user_email";
27
+ readonly WorkspaceRoot: "workspace_root";
28
+ readonly YaraThreats: "yara_threats";
29
+ };
30
+ export type OverwatchContextKey = (typeof OverwatchContextKey)[keyof typeof OverwatchContextKey];
31
+ //# sourceMappingURL=overwatch-context.gen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overwatch-context.gen.d.ts","sourceRoot":"","sources":["../src/overwatch-context.gen.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;CAsBtB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,OAAO,mBAAmB,CAAC,CAAC"}
@@ -0,0 +1,32 @@
1
+ // Code generated by highflame-policy-codegen. DO NOT EDIT.
2
+ // Source: schemas/overwatch/context.json
3
+ /**
4
+ * Context attribute keys for Overwatch Overwatch (Guardian) IDE security & policy enforcement.
5
+ *
6
+ * These constants correspond to the context attributes defined in the
7
+ * Overwatch Cedar schema and are used at policy evaluation time.
8
+ */
9
+ export const OverwatchContextKey = {
10
+ ContainsSecrets: 'contains_secrets',
11
+ Content: 'content',
12
+ Cwd: 'cwd',
13
+ Event: 'event',
14
+ FilePath: 'file_path',
15
+ HighestSeverity: 'highest_severity',
16
+ MaxThreatSeverity: 'max_threat_severity',
17
+ McpServer: 'mcp_server',
18
+ McpTool: 'mcp_tool',
19
+ Path: 'path',
20
+ PromptText: 'prompt_text',
21
+ ResponseContent: 'response_content',
22
+ ServerName: 'server_name',
23
+ Source: 'source',
24
+ ThreatCategories: 'threat_categories',
25
+ ThreatCount: 'threat_count',
26
+ ThreatTypes: 'threat_types',
27
+ ToolName: 'tool_name',
28
+ UserEmail: 'user_email',
29
+ WorkspaceRoot: 'workspace_root',
30
+ YaraThreats: 'yara_threats',
31
+ };
32
+ //# sourceMappingURL=overwatch-context.gen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overwatch-context.gen.js","sourceRoot":"","sources":["../src/overwatch-context.gen.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,yCAAyC;AAEzC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,eAAe,EAAE,kBAAkB;IACnC,OAAO,EAAE,SAAS;IAClB,GAAG,EAAE,KAAK;IACV,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,WAAW;IACrB,eAAe,EAAE,kBAAkB;IACnC,iBAAiB,EAAE,qBAAqB;IACxC,SAAS,EAAE,YAAY;IACvB,OAAO,EAAE,UAAU;IACnB,IAAI,EAAE,MAAM;IACZ,UAAU,EAAE,aAAa;IACzB,eAAe,EAAE,kBAAkB;IACnC,UAAU,EAAE,aAAa;IACzB,MAAM,EAAE,QAAQ;IAChB,gBAAgB,EAAE,mBAAmB;IACrC,WAAW,EAAE,cAAc;IAC3B,WAAW,EAAE,cAAc;IAC3B,QAAQ,EAAE,WAAW;IACrB,SAAS,EAAE,YAAY;IACvB,aAAa,EAAE,gBAAgB;IAC/B,WAAW,EAAE,cAAc;CACnB,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Context attribute keys for Palisade Palisade ML supply chain security & artifact scanning.
3
+ *
4
+ * These constants correspond to the context attributes defined in the
5
+ * Palisade Cedar schema and are used at policy evaluation time.
6
+ */
7
+ export declare const PalisadeContextKey: {
8
+ readonly AdapterBaseDigestMismatch: "adapter_base_digest_mismatch";
9
+ readonly ArtifactFormat: "artifact_format";
10
+ readonly ArtifactSigned: "artifact_signed";
11
+ readonly Environment: "environment";
12
+ readonly FindingType: "finding_type";
13
+ readonly GgufSuspiciousMetadata: "gguf_suspicious_metadata";
14
+ readonly MatchCount: "match_count";
15
+ readonly MetadataCosaiLevelNumeric: "metadata_cosai_level_numeric";
16
+ readonly MetadataMaliciousPattern: "metadata_malicious_pattern";
17
+ readonly Path: "path";
18
+ readonly PickleExecPathDetected: "pickle_exec_path_detected";
19
+ readonly ProvenanceSigner: "provenance_signer";
20
+ readonly SafetensorsIntegrityViolation: "safetensors_integrity_violation";
21
+ readonly Severity: "severity";
22
+ readonly TokenizerAddedTokensCount: "tokenizer_added_tokens_count";
23
+ };
24
+ export type PalisadeContextKey = (typeof PalisadeContextKey)[keyof typeof PalisadeContextKey];
25
+ //# sourceMappingURL=palisade-context.gen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"palisade-context.gen.d.ts","sourceRoot":"","sources":["../src/palisade-context.gen.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;CAgBrB,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,OAAO,kBAAkB,CAAC,CAAC"}
@@ -0,0 +1,26 @@
1
+ // Code generated by highflame-policy-codegen. DO NOT EDIT.
2
+ // Source: schemas/palisade/context.json
3
+ /**
4
+ * Context attribute keys for Palisade Palisade ML supply chain security & artifact scanning.
5
+ *
6
+ * These constants correspond to the context attributes defined in the
7
+ * Palisade Cedar schema and are used at policy evaluation time.
8
+ */
9
+ export const PalisadeContextKey = {
10
+ AdapterBaseDigestMismatch: 'adapter_base_digest_mismatch',
11
+ ArtifactFormat: 'artifact_format',
12
+ ArtifactSigned: 'artifact_signed',
13
+ Environment: 'environment',
14
+ FindingType: 'finding_type',
15
+ GgufSuspiciousMetadata: 'gguf_suspicious_metadata',
16
+ MatchCount: 'match_count',
17
+ MetadataCosaiLevelNumeric: 'metadata_cosai_level_numeric',
18
+ MetadataMaliciousPattern: 'metadata_malicious_pattern',
19
+ Path: 'path',
20
+ PickleExecPathDetected: 'pickle_exec_path_detected',
21
+ ProvenanceSigner: 'provenance_signer',
22
+ SafetensorsIntegrityViolation: 'safetensors_integrity_violation',
23
+ Severity: 'severity',
24
+ TokenizerAddedTokensCount: 'tokenizer_added_tokens_count',
25
+ };
26
+ //# sourceMappingURL=palisade-context.gen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"palisade-context.gen.js","sourceRoot":"","sources":["../src/palisade-context.gen.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,wCAAwC;AAExC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,yBAAyB,EAAE,8BAA8B;IACzD,cAAc,EAAE,iBAAiB;IACjC,cAAc,EAAE,iBAAiB;IACjC,WAAW,EAAE,aAAa;IAC1B,WAAW,EAAE,cAAc;IAC3B,sBAAsB,EAAE,0BAA0B;IAClD,UAAU,EAAE,aAAa;IACzB,yBAAyB,EAAE,8BAA8B;IACzD,wBAAwB,EAAE,4BAA4B;IACtD,IAAI,EAAE,MAAM;IACZ,sBAAsB,EAAE,2BAA2B;IACnD,gBAAgB,EAAE,mBAAmB;IACrC,6BAA6B,EAAE,iCAAiC;IAChE,QAAQ,EAAE,UAAU;IACpB,yBAAyB,EAAE,8BAA8B;CACjD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAkE,MAAM,cAAc,CAAC;AAE/G;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,2DAA2D;IAC3D,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,iFAAiF;IACjF,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,qCAAqC;IACrC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAmDD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,CA2DhE"}
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAkE,MAAM,cAAc,CAAC;AAG/G;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,2DAA2D;IAC3D,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,iFAAiF;IACjF,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,qCAAqC;IACrC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAmDD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,CA4EhE"}
package/dist/parser.js CHANGED
@@ -9,6 +9,7 @@
9
9
  * 2. Cedar JSON → PolicyRule (simple JSON mapping)
10
10
  */
11
11
  import * as cedar from "@cedar-policy/cedar-wasm/nodejs";
12
+ import { ParserError, ErrorCodes } from "./errors.js";
12
13
  /**
13
14
  * Normalize entity reference to simple { type, id } format
14
15
  */
@@ -77,6 +78,20 @@ export function parseCedarToRules(cedarText) {
77
78
  catch (e) {
78
79
  result.errors.push(`Parse error: ${e instanceof Error ? e.message : String(e)}`);
79
80
  }
81
+ // Check for duplicate policy IDs and add warnings
82
+ const idOccurrences = new Map();
83
+ result.rules.forEach((rule, idx) => {
84
+ if (rule.id) {
85
+ const indices = idOccurrences.get(rule.id) || [];
86
+ indices.push(idx);
87
+ idOccurrences.set(rule.id, indices);
88
+ }
89
+ });
90
+ for (const [id, indices] of idOccurrences) {
91
+ if (indices.length > 1) {
92
+ result.errors.push(`[${ErrorCodes.PARSE_DUPLICATE_ID}] Duplicate policy ID '${id}' found at indices [${indices.join(", ")}]`);
93
+ }
94
+ }
80
95
  return result;
81
96
  }
82
97
  /**
@@ -90,28 +105,35 @@ function cedarJsonToRule(policy, policyId, index, originalText) {
90
105
  const raw = originalText || getRawCedar(policyId, policy);
91
106
  return { raw };
92
107
  }
93
- const rule = {
94
- id: policy.annotations?.id || policyId,
95
- name: policy.annotations?.name || policy.annotations?.id || policyId,
96
- effect: policy.effect,
97
- principal: mapScopeToEntity(policy.principal),
98
- action: mapActionScope(policy.action),
99
- resource: mapScopeToEntity(policy.resource),
100
- conditions: [],
101
- enabled: true,
102
- order: index,
103
- };
104
- // Map description from annotations
105
- if (policy.annotations?.description) {
106
- rule.description = policy.annotations.description;
108
+ try {
109
+ const rule = {
110
+ id: policy.annotations?.id || policyId,
111
+ name: policy.annotations?.name || policy.annotations?.id || policyId,
112
+ effect: policy.effect,
113
+ principal: mapScopeToEntity(policy.principal, "principal"),
114
+ action: mapActionScope(policy.action),
115
+ resource: mapScopeToEntity(policy.resource, "resource"),
116
+ conditions: [],
117
+ enabled: true,
118
+ order: index,
119
+ };
120
+ // Map description from annotations
121
+ if (policy.annotations?.description) {
122
+ rule.description = policy.annotations.description;
123
+ }
124
+ // Map conditions
125
+ const { conditions, rawCondition } = mapConditions(policy.conditions);
126
+ rule.conditions = conditions;
127
+ if (rawCondition) {
128
+ rule.rawCondition = rawCondition;
129
+ }
130
+ return { rule };
107
131
  }
108
- // Map conditions
109
- const { conditions, rawCondition } = mapConditions(policy.conditions);
110
- rule.conditions = conditions;
111
- if (rawCondition) {
112
- rule.rawCondition = rawCondition;
132
+ catch (e) {
133
+ const error = e instanceof Error ? e.message : String(e);
134
+ const raw = originalText || getRawCedar(policyId, policy);
135
+ return { raw, error };
113
136
  }
114
- return { rule };
115
137
  }
116
138
  /**
117
139
  * Check if a Cedar policy can be represented as PolicyRule
@@ -157,12 +179,20 @@ function getRawCedar(policyId, policy) {
157
179
  catch {
158
180
  // Ignore conversion errors
159
181
  }
160
- return `// Complex policy: ${policyId}`;
182
+ // Sanitize policyId to prevent newline injection attacks
183
+ const safeId = policyId.replace(/[\n\r]/g, " ");
184
+ return `// Complex policy: ${safeId}`;
161
185
  }
162
186
  /**
163
187
  * Map Cedar scope constraint to PolicyEntity
188
+ *
189
+ * Returns null for unconstrained ("All") scopes.
190
+ * Throws ParserError for malformed constraints to prevent silent misinterpretation.
191
+ *
192
+ * @param scope - The Cedar scope constraint
193
+ * @param field - The field name ("principal" or "resource") for error context
164
194
  */
165
- function mapScopeToEntity(scope) {
195
+ function mapScopeToEntity(scope, field) {
166
196
  if (scope.op === "All") {
167
197
  return null;
168
198
  }
@@ -171,33 +201,44 @@ function mapScopeToEntity(scope) {
171
201
  const entity = normalizeEntityRef(scope.entity);
172
202
  return { type: entity.type, id: entity.id };
173
203
  }
174
- // Slot - can't represent
175
- return null;
204
+ if ("slot" in scope) {
205
+ throw ParserError.scopeSlotNotSupported("==", field);
206
+ }
207
+ throw ParserError.scopeMissingEntity("==", field);
176
208
  }
177
209
  if (scope.op === "is") {
178
- // Type constraint
179
- return { type: scope.entity_type };
210
+ if (scope.entity_type) {
211
+ return { type: scope.entity_type };
212
+ }
213
+ throw ParserError.scopeMissingEntityType(field);
180
214
  }
181
215
  if (scope.op === "in") {
182
216
  if ("entity" in scope) {
183
217
  const entity = normalizeEntityRef(scope.entity);
184
218
  return { type: entity.type, id: entity.id };
185
219
  }
186
- // Slot - can't represent
187
- return null;
220
+ if ("slot" in scope) {
221
+ throw ParserError.scopeSlotNotSupported("in", field);
222
+ }
223
+ throw ParserError.scopeMissingEntityList(field);
188
224
  }
189
- return null;
225
+ throw ParserError.scopeUnsupportedOp(scope.op, field);
190
226
  }
191
227
  /**
192
228
  * Map action scope to action string(s)
229
+ *
230
+ * Throws ParserError for malformed constraints to prevent silent misinterpretation.
193
231
  */
194
232
  function mapActionScope(scope) {
195
233
  if (scope.op === "All") {
196
234
  return "*";
197
235
  }
198
236
  if (scope.op === "==") {
199
- const entity = normalizeEntityRef(scope.entity);
200
- return entity.id;
237
+ if ("entity" in scope) {
238
+ const entity = normalizeEntityRef(scope.entity);
239
+ return entity.id;
240
+ }
241
+ throw ParserError.actionMissingEntity("==");
201
242
  }
202
243
  if (scope.op === "in") {
203
244
  if ("entities" in scope) {
@@ -208,8 +249,9 @@ function mapActionScope(scope) {
208
249
  const entity = normalizeEntityRef(scope.entity);
209
250
  return entity.id;
210
251
  }
252
+ throw ParserError.actionMissingEntities();
211
253
  }
212
- return "";
254
+ throw ParserError.actionUnsupportedOp(scope.op);
213
255
  }
214
256
  /**
215
257
  * Map Cedar conditions to PolicyCondition array
@@ -229,9 +271,11 @@ function mapConditions(conditions) {
229
271
  rawParts.push(parsed.raw);
230
272
  }
231
273
  }
274
+ // Store raw conditions as a valid JSON array instead of joining with " && "
275
+ // This ensures downstream systems can parse the rawCondition field
232
276
  return {
233
277
  conditions: result,
234
- rawCondition: rawParts.length > 0 ? rawParts.join(" && ") : undefined,
278
+ rawCondition: rawParts.length > 0 ? `[${rawParts.join(",")}]` : undefined,
235
279
  };
236
280
  }
237
281
  /**
@@ -292,11 +336,12 @@ function mapLike(args) {
292
336
  if (!field)
293
337
  return null;
294
338
  // Convert pattern to string (e.g., ["Wildcard", { Literal: "foo" }, "Wildcard"] -> "*foo*")
339
+ // Escape literal * characters to distinguish from wildcards on round-trip
295
340
  const patternStr = args.pattern.map(p => {
296
341
  if (p === "Wildcard")
297
342
  return "*";
298
343
  if (typeof p === "object" && "Literal" in p)
299
- return p.Literal;
344
+ return p.Literal.replace(/\*/g, "\\*");
300
345
  return "";
301
346
  }).join("");
302
347
  return { field, operator: "like", value: patternStr };