@highflame/policy 1.1.3

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/src/engine.ts ADDED
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Highflame Policy Engine - TypeScript Wrapper
3
+ * Wraps @cedar-policy/cedar-wasm with Highflame-specific types
4
+ */
5
+
6
+ import * as cedar from "@cedar-policy/cedar-wasm/nodejs";
7
+ import { EntityType, EntityUID, Entity } from "./entities.gen.js";
8
+ import { ActionType } from "./actions.gen.js";
9
+ import { CEDAR_SCHEMA } from "./schema.gen.js";
10
+
11
+ export interface Decision {
12
+ effect: "Allow" | "Deny";
13
+ determining_policies: string[];
14
+ reason?: string;
15
+ }
16
+
17
+ export interface EvaluateRequest {
18
+ principal: EntityUID;
19
+ action: ActionType;
20
+ resource: EntityUID;
21
+ context?: Record<string, unknown>;
22
+ }
23
+
24
+ /**
25
+ * Convert a value to Cedar JSON format
26
+ */
27
+ function toCedarValue(value: unknown): cedar.CedarValueJson {
28
+ if (value === null || value === undefined) {
29
+ return null;
30
+ }
31
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
32
+ return value;
33
+ }
34
+ if (Array.isArray(value)) {
35
+ return value.map(toCedarValue);
36
+ }
37
+ if (typeof value === "object") {
38
+ const result: Record<string, cedar.CedarValueJson> = {};
39
+ for (const [k, v] of Object.entries(value)) {
40
+ result[k] = toCedarValue(v);
41
+ }
42
+ return result;
43
+ }
44
+ return String(value);
45
+ }
46
+
47
+ /**
48
+ * PolicyEngine wraps cedar-wasm with Highflame schema types.
49
+ */
50
+ export class PolicyEngine {
51
+ private policies: string = "";
52
+ private schema: string | undefined;
53
+
54
+ /**
55
+ * Load policies from a Cedar policy string.
56
+ */
57
+ loadPolicies(policies: string): void {
58
+ this.policies = policies;
59
+ }
60
+
61
+ /**
62
+ * Load schema from a Cedar schema string.
63
+ * If not called, uses the embedded Highflame schema.
64
+ */
65
+ loadSchema(schema: string): void {
66
+ this.schema = schema;
67
+ }
68
+
69
+ /**
70
+ * Load the embedded Highflame schema.
71
+ */
72
+ loadHighflameSchema(): void {
73
+ this.schema = CEDAR_SCHEMA;
74
+ }
75
+
76
+ /**
77
+ * Evaluate a policy request and return a decision.
78
+ */
79
+ evaluate(req: EvaluateRequest): Decision {
80
+ // Build EntityUIDs in Cedar JSON format
81
+ const principal: cedar.EntityUidJson = {
82
+ type: req.principal.type,
83
+ id: req.principal.id,
84
+ };
85
+ const action: cedar.EntityUidJson = {
86
+ type: "Action",
87
+ id: req.action,
88
+ };
89
+ const resource: cedar.EntityUidJson = {
90
+ type: req.resource.type,
91
+ id: req.resource.id,
92
+ };
93
+
94
+ // Convert context to Cedar format
95
+ const context: cedar.Context = {};
96
+ if (req.context) {
97
+ for (const [k, v] of Object.entries(req.context)) {
98
+ context[k] = toCedarValue(v);
99
+ }
100
+ }
101
+
102
+ // Build the authorization call
103
+ const call: cedar.AuthorizationCall = {
104
+ principal,
105
+ action,
106
+ resource,
107
+ context,
108
+ policies: { staticPolicies: this.policies },
109
+ entities: [],
110
+ };
111
+
112
+ // Add schema if available
113
+ if (this.schema) {
114
+ call.schema = this.schema;
115
+ }
116
+
117
+ const result = cedar.isAuthorized(call);
118
+
119
+ if (result.type === "failure") {
120
+ return {
121
+ effect: "Deny",
122
+ determining_policies: [],
123
+ reason: result.errors.map(e => e.message).join("; "),
124
+ };
125
+ }
126
+
127
+ return {
128
+ effect: result.response.decision === "allow" ? "Allow" : "Deny",
129
+ determining_policies: result.response.diagnostics.reason,
130
+ reason: result.response.diagnostics.errors.length > 0
131
+ ? result.response.diagnostics.errors.map(e => e.error.message).join("; ")
132
+ : undefined,
133
+ };
134
+ }
135
+
136
+ /**
137
+ * Convenience method for simple evaluations.
138
+ */
139
+ evaluateSimple(
140
+ principalType: EntityType,
141
+ principalId: string,
142
+ action: ActionType,
143
+ resourceType: EntityType,
144
+ resourceId: string,
145
+ context?: Record<string, unknown>
146
+ ): Decision {
147
+ return this.evaluate({
148
+ principal: { type: principalType, id: principalId },
149
+ action,
150
+ resource: { type: resourceType, id: resourceId },
151
+ context,
152
+ });
153
+ }
154
+
155
+ /**
156
+ * Validate policies against the schema.
157
+ * Returns validation errors or empty array if valid.
158
+ */
159
+ validatePolicies(policies: string): string[] {
160
+ const schemaToUse = this.schema ?? CEDAR_SCHEMA;
161
+
162
+ const result = cedar.validate({
163
+ validationSettings: { mode: "strict" },
164
+ schema: schemaToUse,
165
+ policies: { staticPolicies: policies },
166
+ });
167
+
168
+ if (result.type === "failure") {
169
+ return result.errors.map(e => e.message);
170
+ }
171
+
172
+ return result.validationErrors.map(e => e.error.message);
173
+ }
174
+ }
175
+
176
+ /**
177
+ * PolicyValidator provides static validation against the Highflame schema.
178
+ * Use this for quick validation without creating an engine instance.
179
+ */
180
+ export class PolicyValidator {
181
+ private schema: string;
182
+
183
+ /**
184
+ * Create a validator with the embedded Highflame schema.
185
+ */
186
+ constructor(schema?: string) {
187
+ this.schema = schema ?? CEDAR_SCHEMA;
188
+ }
189
+
190
+ /**
191
+ * Validate Cedar policy text against the schema.
192
+ */
193
+ validate(policies: string): { valid: boolean; errors: string[] } {
194
+ const result = cedar.validate({
195
+ validationSettings: { mode: "strict" },
196
+ schema: this.schema,
197
+ policies: { staticPolicies: policies },
198
+ });
199
+
200
+ if (result.type === "failure") {
201
+ return {
202
+ valid: false,
203
+ errors: result.errors.map(e => e.message),
204
+ };
205
+ }
206
+
207
+ if (result.validationErrors.length > 0) {
208
+ return {
209
+ valid: false,
210
+ errors: result.validationErrors.map(e => e.error.message),
211
+ };
212
+ }
213
+
214
+ return { valid: true, errors: [] };
215
+ }
216
+
217
+ /**
218
+ * Check if a policy parses correctly (syntax check only).
219
+ */
220
+ checkSyntax(policies: string): { valid: boolean; errors: string[] } {
221
+ const result = cedar.checkParsePolicySet({ staticPolicies: policies });
222
+ if (result.type === "failure") {
223
+ return {
224
+ valid: false,
225
+ errors: result.errors.map(e => e.message),
226
+ };
227
+ }
228
+ return { valid: true, errors: [] };
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Validate a Cedar policy against the Highflame schema.
234
+ * Convenience function that doesn't require creating a validator instance.
235
+ */
236
+ export function validatePolicy(policy: string): { valid: boolean; errors: string[] } {
237
+ const validator = new PolicyValidator();
238
+ return validator.validate(policy);
239
+ }
240
+
241
+ /**
242
+ * Get the embedded Highflame Cedar schema.
243
+ */
244
+ export function getHighflameSchema(): string {
245
+ return CEDAR_SCHEMA;
246
+ }
247
+
248
+ // Re-export types
249
+ export { EntityType, EntityUID, Entity, newEntityUID, newEntity } from "./entities.gen.js";
250
+ export { ActionType, actionUID } from "./actions.gen.js";
251
+ export * from "./context.gen.js";
252
+ export { CEDAR_SCHEMA } from "./schema.gen.js";
@@ -0,0 +1,60 @@
1
+ // Code generated by highflame-policy-codegen. DO NOT EDIT.
2
+ // Source: schema/highflame.cedarschema
3
+
4
+ /**
5
+ * Entity types defined in the Highflame Cedar schema.
6
+ */
7
+ export const EntityType = {
8
+ Agent: 'Agent',
9
+ Artifact: 'Artifact',
10
+ FilePath: 'FilePath',
11
+ HttpEndpoint: 'HttpEndpoint',
12
+ Package: 'Package',
13
+ Repository: 'Repository',
14
+ Resource: 'Resource',
15
+ ResponseData: 'ResponseData',
16
+ Scanner: 'Scanner',
17
+ Server: 'Server',
18
+ Service: 'Service',
19
+ Tool: 'Tool',
20
+ User: 'User',
21
+ } as const;
22
+
23
+ export type EntityType = (typeof EntityType)[keyof typeof EntityType];
24
+
25
+ /**
26
+ * Cedar entity unique identifier.
27
+ */
28
+ export interface EntityUID {
29
+ type: EntityType | string;
30
+ id: string;
31
+ }
32
+
33
+ /**
34
+ * Cedar entity with attributes.
35
+ */
36
+ export interface Entity {
37
+ uid: EntityUID;
38
+ attrs?: Record<string, unknown>;
39
+ parents?: EntityUID[];
40
+ }
41
+
42
+ /**
43
+ * Create a new EntityUID.
44
+ * Services should use this with their own identity from config/environment.
45
+ * @example newEntityUID(EntityType.Scanner, process.env.SERVICE_ID)
46
+ */
47
+ export function newEntityUID(type: EntityType | string, id: string): EntityUID {
48
+ return { type, id };
49
+ }
50
+
51
+ /**
52
+ * Create a new Entity.
53
+ */
54
+ export function newEntity(type: EntityType | string, id: string, attrs?: Record<string, unknown>): Entity {
55
+ return {
56
+ uid: { type, id },
57
+ attrs: attrs ?? {},
58
+ parents: [],
59
+ };
60
+ }
package/src/index.ts ADDED
@@ -0,0 +1,14 @@
1
+ // Code generated by highflame-policy-codegen. DO NOT EDIT.
2
+ // Source: schema/highflame.cedarschema
3
+ //
4
+ // NOTE: This module requires Node.js (uses @cedar-policy/cedar-wasm).
5
+ // For browser usage, import from '@highflame/policy/types' instead.
6
+
7
+ export * from './entities.gen.js';
8
+ export * from './actions.gen.js';
9
+ export * from './context.gen.js';
10
+ export * from './schema.gen.js';
11
+
12
+ // Non-generated modules (require Node.js)
13
+ export * from './engine.js';
14
+ export * from './builder.js';
@@ -0,0 +1,301 @@
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
9
+ // ======================
10
+ // This is the SOURCE OF TRUTH for all entity types, actions, and their relationships
11
+ // across the Highflame platform.
12
+ //
13
+ // All services (authz, Core, Guardian, Palisade) MUST use the types defined here.
14
+ // The codegen tool parses this file and generates typed constants for Go, TypeScript,
15
+ // and Python to ensure consistency.
16
+ //
17
+ // Usage:
18
+ // - Policies are validated against this schema when created/updated
19
+ // - Generated types prevent typos in application code
20
+ // - Cedar CLI can validate: cedar validate --schema highflame.cedarschema --policies policy.cedar
21
+
22
+ // =============================================================================
23
+ // PRINCIPAL TYPES (Who is making the request)
24
+ // =============================================================================
25
+
26
+ // Human user or service account making requests
27
+ // Well-known IDs: "mcp_client", "threat_processor"
28
+ entity User {
29
+ // User type: "external", "internal"
30
+ user_type: String,
31
+ };
32
+
33
+ // AI agent or bot
34
+ entity Agent {
35
+ // Agent type: "llm", "scanner", "bot"
36
+ agent_type: String,
37
+ };
38
+
39
+ // Security scanner service
40
+ // Well-known IDs: "ramparts", "palisade"
41
+ entity Scanner {
42
+ // Scanner type: "ramparts", "palisade"
43
+ scanner_type: String,
44
+ // Scanner version
45
+ version: String,
46
+ };
47
+
48
+ // Backend service account
49
+ entity Service {
50
+ // Service name
51
+ service_name: String,
52
+ // Environment: "production", "staging", "development"
53
+ environment: String,
54
+ };
55
+
56
+ // =============================================================================
57
+ // RESOURCE TYPES (What is being accessed)
58
+ // =============================================================================
59
+
60
+ // Generic resource
61
+ // Well-known IDs: "threat_analysis", "tools/list", "tools/call", "resources/list",
62
+ // "resources/read", "prompts/list", "unknown"
63
+ entity Resource {};
64
+
65
+ // LLM response data
66
+ // Well-known IDs: "response_data"
67
+ entity ResponseData {};
68
+
69
+ // MCP tool that can be called
70
+ entity Tool {
71
+ // Tool name
72
+ tool_name: String,
73
+ // Risk level: "safe", "moderate", "dangerous"
74
+ risk_level: String,
75
+ // Category: "file", "network", "shell", "api"
76
+ category: String,
77
+ };
78
+
79
+ // File system path
80
+ entity FilePath {
81
+ // Full path
82
+ path: String,
83
+ // File extension
84
+ extension: String,
85
+ // Whether file is sensitive (.env, credentials, etc.)
86
+ is_sensitive: Bool,
87
+ };
88
+
89
+ // HTTP endpoint
90
+ entity HttpEndpoint {
91
+ // Hostname
92
+ hostname: String,
93
+ // Scheme: "http", "https"
94
+ scheme: String,
95
+ // Port number
96
+ port: Long,
97
+ // Whether endpoint is internal
98
+ is_internal: Bool,
99
+ };
100
+
101
+ // MCP Server
102
+ entity Server {
103
+ // Server name
104
+ server_name: String,
105
+ };
106
+
107
+ // ML model artifact (for Palisade)
108
+ entity Artifact {
109
+ // Format: "safetensors", "pickle", "gguf", "onnx"
110
+ artifact_type: String,
111
+ // Source URL or path
112
+ source: String,
113
+ // SHA256 hash
114
+ hash: String,
115
+ // Whether artifact is signed
116
+ is_signed: Bool,
117
+ };
118
+
119
+ // Code repository
120
+ entity Repository {
121
+ // Repository URL
122
+ url: String,
123
+ };
124
+
125
+ // Software package
126
+ entity Package {
127
+ // Package name
128
+ name: String,
129
+ // Package version
130
+ version: String,
131
+ };
132
+
133
+ // =============================================================================
134
+ // ACTIONS
135
+ // =============================================================================
136
+
137
+ // --- LLM/Guardrails Actions ---
138
+
139
+ // Process an LLM prompt
140
+ // Context: prompt_text, yara_threats, threat_count, max_threat_severity,
141
+ // user_type, monitoring_enabled
142
+ action process_prompt appliesTo {
143
+ principal: [User, Agent],
144
+ resource: [Resource],
145
+ };
146
+
147
+ // Process an LLM response
148
+ // Context: response_size_mb
149
+ action process_response appliesTo {
150
+ principal: [User, Agent],
151
+ resource: [ResponseData],
152
+ };
153
+
154
+ // --- MCP/Tool Actions ---
155
+
156
+ // Call an MCP tool
157
+ // Context: tool_name
158
+ action call_tool appliesTo {
159
+ principal: [User, Agent, Service],
160
+ resource: [Tool, Resource],
161
+ };
162
+
163
+ // Connect to an MCP server
164
+ action connect_server appliesTo {
165
+ principal: [User, Agent, Service],
166
+ resource: [Server, Resource],
167
+ };
168
+
169
+ // Access a server-specific resource
170
+ // Context: tool_name, resource_name, prompt_name
171
+ action access_server_resource appliesTo {
172
+ principal: [User, Agent, Service],
173
+ resource: [Resource],
174
+ };
175
+
176
+ // Skip guardrails for an operation
177
+ action skip_guardrails appliesTo {
178
+ principal: [User, Agent, Service],
179
+ resource: [Resource],
180
+ };
181
+
182
+ // --- File System Actions ---
183
+
184
+ // Read a file
185
+ // Context: path
186
+ action read_file appliesTo {
187
+ principal: [User, Agent, Scanner],
188
+ resource: [FilePath, Resource],
189
+ };
190
+
191
+ // Write a file
192
+ // Context: path
193
+ action write_file appliesTo {
194
+ principal: [User, Agent],
195
+ resource: [FilePath, Resource],
196
+ };
197
+
198
+ // --- HTTP Actions ---
199
+
200
+ // Make an HTTP request
201
+ // Context: hostname, ip_address, scheme, port
202
+ action http_request appliesTo {
203
+ principal: [User, Agent, Service],
204
+ resource: [HttpEndpoint, Resource],
205
+ };
206
+
207
+ // --- Scanner Actions ---
208
+
209
+ // Scan a target (MCP server, repository, etc.)
210
+ action scan_target appliesTo {
211
+ principal: [Scanner, Service],
212
+ resource: [Resource, Repository, Server],
213
+ };
214
+
215
+ // Scan a software package
216
+ action scan_package appliesTo {
217
+ principal: [Scanner, Service],
218
+ resource: [Package, Resource],
219
+ };
220
+
221
+ // --- Palisade/ML Actions ---
222
+
223
+ // Scan an ML artifact
224
+ // Context: environment, artifact_format, artifact_signed, severity, finding_type,
225
+ // provenance_signer, pickle_exec_path_detected, metadata_malicious_pattern,
226
+ // tokenizer_added_tokens_count, safetensors_integrity_violation,
227
+ // gguf_suspicious_metadata, adapter_base_digest_mismatch,
228
+ // metadata_cosai_level_numeric
229
+ action scan_artifact appliesTo {
230
+ principal: [Scanner, Service],
231
+ resource: [Artifact, Resource],
232
+ };
233
+
234
+ // Validate artifact integrity
235
+ action validate_integrity appliesTo {
236
+ principal: [Scanner, Service],
237
+ resource: [Artifact],
238
+ };
239
+
240
+ // Validate artifact provenance
241
+ action validate_provenance appliesTo {
242
+ principal: [Scanner, Service],
243
+ resource: [Artifact],
244
+ };
245
+
246
+ // Quarantine an artifact
247
+ action quarantine_artifact appliesTo {
248
+ principal: [Scanner, Service],
249
+ resource: [Artifact],
250
+ };
251
+
252
+ // Load an ML model
253
+ action load_model appliesTo {
254
+ principal: [User, Agent, Service],
255
+ resource: [Artifact],
256
+ };
257
+
258
+ // Deploy an ML model
259
+ action deploy_model appliesTo {
260
+ principal: [User, Service],
261
+ resource: [Artifact],
262
+ };
263
+
264
+ // =============================================================================
265
+ // CONTEXT ATTRIBUTES REFERENCE (Documentation Only)
266
+ // =============================================================================
267
+ // Cedar context is dynamic and not enforced by schema, but these are the
268
+ // standard attributes used across Highflame services:
269
+ //
270
+ // GUARDRAILS/CORE:
271
+ // tool_name: String - Name of tool being called
272
+ // resource_name: String - Name of resource being accessed
273
+ // prompt_name: String - Name of prompt
274
+ // prompt_text: String - Raw prompt text (for injection detection)
275
+ // response_size_mb: Long - Response size in megabytes
276
+ // yara_threats: Set<String> - Set of detected YARA threat names
277
+ // threat_count: Long - Number of threats detected
278
+ // max_threat_severity: Long - Highest severity (0=INFO, 4=CRITICAL)
279
+ // user_type: String - "external" or "internal"
280
+ // monitoring_enabled: Bool - Whether monitoring is active
281
+ // path: String - File path
282
+ // hostname: String - HTTP hostname
283
+ // ip_address: String - IP address (for SSRF detection)
284
+ // scheme: String - HTTP scheme
285
+ // port: Long - Port number
286
+ //
287
+ // PALISADE:
288
+ // environment: String - "production", "development", "research"
289
+ // artifact_format: String - "pickle", "safetensors", "gguf", "onnx"
290
+ // artifact_signed: Bool - Whether artifact has signature
291
+ // severity: String - "CRITICAL", "HIGH", "MEDIUM", "LOW", "INFO"
292
+ // finding_type: String - Type of security finding
293
+ // provenance_signer: String - Who signed ("unknown", "unsigned", or name)
294
+ // pickle_exec_path_detected: Bool - RCE path found in pickle
295
+ // metadata_malicious_pattern: Bool - Malicious pattern in metadata
296
+ // tokenizer_added_tokens_count: Long - Number of added tokens
297
+ // safetensors_integrity_violation: Bool - Safetensors integrity failed
298
+ // gguf_suspicious_metadata: Bool - Suspicious GGUF metadata
299
+ // adapter_base_digest_mismatch: Bool - LoRA adapter digest mismatch
300
+ // metadata_cosai_level_numeric: Long - CoSAI maturity level (0-5)
301
+ `;
package/src/types.ts ADDED
@@ -0,0 +1,15 @@
1
+ // Code generated by highflame-policy-codegen. DO NOT EDIT.
2
+ // Source: schema/highflame.cedarschema
3
+ //
4
+ // Browser-safe exports - no WASM dependency.
5
+ // Use this entry point in browser environments:
6
+ // import { EntityType, PolicyBuilder } from '@highflame/policy/types';
7
+
8
+ // Generated types - work in browser and Node.js
9
+ export * from './entities.gen.js';
10
+ export * from './actions.gen.js';
11
+ export * from './context.gen.js';
12
+ export * from './schema.gen.js';
13
+
14
+ // PolicyBuilder - works in browser (no WASM dependency)
15
+ export * from './builder.js';