@janssenproject/cedarling_wasm 1.15.0 → 2.0.0-nodejs

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -46,14 +46,14 @@ After building WASM bindings in folder `pkg` you can find where you can find `ce
46
46
  In `index.html` described simple usage of `cedarling wasm` API:
47
47
 
48
48
  ```js
49
- import { BOOTSTRAP_CONFIG, REQUEST } from "/example_data.js"; // Import js objects: bootstrap config and request
49
+ import { BOOTSTRAP_CONFIG, REQUEST_UNSIGNED } from "/example_data.js"; // Import js objects: bootstrap config and request
50
50
  import initWasm, { init } from "/pkg/cedarling_wasm.js";
51
51
 
52
52
  async function main() {
53
53
  await initWasm(); // Initialize the WebAssembly module
54
54
 
55
55
  let instance = await init(BOOTSTRAP_CONFIG);
56
- let result = await instance.authorize(REQUEST);
56
+ let result = await instance.authorize_unsigned(REQUEST_UNSIGNED);
57
57
  console.log("result:", result);
58
58
  }
59
59
  main().catch(console.error);
@@ -70,6 +70,25 @@ Before using any function from library you need initialize WASM runtime by calli
70
70
  */
71
71
  export function init(config: any): Promise<Cedarling>;
72
72
 
73
+ /**
74
+ * Create a new instance of the Cedarling application from archive bytes.
75
+ *
76
+ * This function allows loading a policy store from a Cedar Archive (.cjar)
77
+ * that was fetched with custom logic (e.g., with authentication headers).
78
+ *
79
+ * # Arguments
80
+ * * `config` - Bootstrap configuration (Map or Object). Policy store config is ignored.
81
+ * * `archive_bytes` - The .cjar archive bytes (Uint8Array)
82
+ *
83
+ * # Example
84
+ * ```javascript
85
+ * const response = await fetch(url, { headers: { Authorization: 'Bearer ...' } });
86
+ * const bytes = new Uint8Array(await response.arrayBuffer());
87
+ * const cedarling = await init_from_archive_bytes(config, bytes);
88
+ * ```
89
+ */
90
+ export function init_from_archive_bytes(config: any, archive_bytes: Uint8Array): Promise<Cedarling>;
91
+
73
92
  /**
74
93
  * The instance of the Cedarling application.
75
94
  */
@@ -85,13 +104,11 @@ export class Cedarling {
85
104
  */
86
105
  static new_from_map(config: Map<any, any>): Promise<Cedarling>;
87
106
  /**
88
- * Authorize request
89
- * makes authorization decision based on the [`Request`]
90
- */
91
- authorize(request: any): Promise<AuthorizeResult>;
92
- /**
93
- * Authorize request for unsigned principals.
94
- * makes authorization decision based on the [`RequestUnsigned`]
107
+ * Authorize an unsigned request carrying an optional single principal.
108
+ * Makes an authorization decision based on the [`RequestUnsigned`].
109
+ * When `principal` is omitted / `null` the core uses Cedar partial evaluation;
110
+ * residual-dependent requests fail closed with `Decision::Deny` and surface
111
+ * residual policy ids in `response.diagnostics.reason`.
95
112
  */
96
113
  authorize_unsigned(request: any): Promise<AuthorizeResult>;
97
114
  /**
@@ -130,6 +147,111 @@ export class Cedarling {
130
147
  * Return log entries that match the given request_id and tag.
131
148
  */
132
149
  get_logs_by_request_id_and_tag(request_id: string, tag: string): any[];
150
+ /**
151
+ * Push a value into the data store with an optional TTL.
152
+ * If the key already exists, the value will be replaced.
153
+ * If TTL is not provided, the default TTL from configuration is used.
154
+ *
155
+ * # Arguments
156
+ * * `key` - The key for the data entry
157
+ * * `value` - The value to store (any JSON-serializable value)
158
+ * * `ttl_secs` - Optional TTL in seconds (undefined uses default from config)
159
+ *
160
+ * # Example
161
+ * ```javascript
162
+ * cedarling.push_data_ctx("user:123", { name: "John", age: 30 }, 3600);
163
+ * cedarling.push_data_ctx("config", { setting: "value" }); // Uses default TTL
164
+ * ```
165
+ */
166
+ push_data_ctx(key: string, value: any, ttl_secs?: number): void;
167
+ /**
168
+ * Get a value from the data store by key.
169
+ * Returns null if the key doesn't exist or the entry has expired.
170
+ *
171
+ * # Arguments
172
+ * * `key` - The key to retrieve
173
+ *
174
+ * # Example
175
+ * ```javascript
176
+ * const value = cedarling.get_data_ctx("user:123");
177
+ * if (value) {
178
+ * console.log(value.name);
179
+ * }
180
+ * ```
181
+ */
182
+ get_data_ctx(key: string): any;
183
+ /**
184
+ * Get a data entry with full metadata by key.
185
+ * Returns null if the key doesn't exist or the entry has expired.
186
+ * Includes metadata like creation time, expiration, access count, and type.
187
+ *
188
+ * # Arguments
189
+ * * `key` - The key to retrieve
190
+ *
191
+ * # Example
192
+ * ```javascript
193
+ * const entry = cedarling.get_data_entry_ctx("user:123");
194
+ * if (entry) {
195
+ * console.log(`Created: ${entry.created_at}, Access count: ${entry.access_count}`);
196
+ * }
197
+ * ```
198
+ */
199
+ get_data_entry_ctx(key: string): any;
200
+ /**
201
+ * Remove a value from the data store by key.
202
+ * Returns true if the key existed and was removed, false otherwise.
203
+ *
204
+ * # Arguments
205
+ * * `key` - The key to remove
206
+ *
207
+ * # Example
208
+ * ```javascript
209
+ * const removed = cedarling.remove_data_ctx("user:123");
210
+ * ```
211
+ */
212
+ remove_data_ctx(key: string): boolean;
213
+ /**
214
+ * Clear all entries from the data store.
215
+ *
216
+ * # Example
217
+ * ```javascript
218
+ * cedarling.clear_data_ctx();
219
+ * ```
220
+ */
221
+ clear_data_ctx(): void;
222
+ /**
223
+ * List all entries with their metadata.
224
+ * Returns an array of data entries containing key, value, type, and timing metadata.
225
+ *
226
+ * # Example
227
+ * ```javascript
228
+ * const entries = cedarling.list_data_ctx();
229
+ * entries.forEach(entry => {
230
+ * console.log(`Key: ${entry.key}, Type: ${entry.data_type}`);
231
+ * });
232
+ * ```
233
+ */
234
+ list_data_ctx(): any[];
235
+ /**
236
+ * Get statistics about the data store.
237
+ * Returns current entry count, capacity limits, and configuration state.
238
+ *
239
+ * # Example
240
+ * ```javascript
241
+ * const stats = cedarling.get_stats_ctx();
242
+ * console.log(`Entries: ${stats.entry_count}/${stats.max_entries}`);
243
+ * ```
244
+ */
245
+ get_stats_ctx(): DataStoreStats;
246
+ /**
247
+ * Trusted issuer loading status helpers.
248
+ */
249
+ is_trusted_issuer_loaded_by_name(issuer_id: string): boolean;
250
+ is_trusted_issuer_loaded_by_iss(iss_claim: string): boolean;
251
+ total_issuers(): number;
252
+ loaded_trusted_issuers_count(): number;
253
+ loaded_trusted_issuer_ids(): Array<string>;
254
+ failed_trusted_issuer_ids(): Array<string>;
133
255
  }
134
256
 
135
257
  /**
@@ -142,17 +264,9 @@ export class AuthorizeResult {
142
264
  */
143
265
  json_string(): string;
144
266
  /**
145
- * Result of authorization where principal is `Jans::Workload`
146
- */
147
- workload?: AuthorizeResultResponse;
148
- /**
149
- * Result of authorization where principal is `Jans::User`
150
- */
151
- person?: AuthorizeResultResponse;
152
- /**
153
- * Get result for a specific principal
267
+ * Cedar authorization response for the request.
154
268
  */
155
- principal(principal: string): AuthorizeResultResponse | undefined;
269
+ response: AuthorizeResultResponse;
156
270
  /**
157
271
  * Result of authorization
158
272
  * true means `ALLOW`
@@ -244,20 +358,99 @@ export class PolicyEvaluationError {
244
358
  */
245
359
  readonly error: string;
246
360
  }
361
+
362
+ /**
363
+ * DataStoreStats
364
+ * ==============
365
+ *
366
+ * Statistics about the DataStore, providing insight into the current state
367
+ * and usage of the data store, including memory usage metrics and capacity information.
368
+ */
369
+ export class DataStoreStats {
370
+ /**
371
+ * Number of entries currently stored
372
+ */
373
+ readonly entry_count: number;
374
+ /**
375
+ * Maximum number of entries allowed (0 = unlimited)
376
+ */
377
+ readonly max_entries: number;
378
+ /**
379
+ * Maximum size per entry in bytes (0 = unlimited)
380
+ */
381
+ readonly max_entry_size: number;
382
+ /**
383
+ * Whether metrics tracking is enabled
384
+ */
385
+ readonly metrics_enabled: boolean;
386
+ /**
387
+ * Total size of all entries in bytes (approximate, based on JSON serialization)
388
+ */
389
+ readonly total_size_bytes: number;
390
+ /**
391
+ * Average size per entry in bytes (0 if no entries)
392
+ */
393
+ readonly avg_entry_size_bytes: number;
394
+ /**
395
+ * Percentage of capacity used (0.0-100.0, based on entry count)
396
+ */
397
+ readonly capacity_usage_percent: number;
398
+ /**
399
+ * Memory usage threshold percentage (from config)
400
+ */
401
+ readonly memory_alert_threshold: number;
402
+ /**
403
+ * Whether memory usage exceeds the alert threshold
404
+ */
405
+ readonly memory_alert_triggered: boolean;
406
+ }
247
407
  ```
248
408
 
249
409
  ## Configuration
250
410
 
251
- ### ID Token Trust Mode
411
+ ### Policy Store Sources
252
412
 
253
- The `CEDARLING_ID_TOKEN_TRUST_MODE` property controls how ID tokens are validated:
413
+ Cedarling supports multiple ways to load policy stores. **In WASM environments, only URL-based loading is available** (no filesystem access).
254
414
 
255
- - **`strict`** (default): Enforces strict validation rules
256
- - ID token `aud` must match access token `client_id`
257
- - If userinfo token is present, its `sub` must match the ID token `sub`
258
- - **`never`**: Disables ID token validation (useful for testing)
259
- - **`always`**: Always validates ID tokens when present
260
- - **`ifpresent`**: Validates ID tokens only if they are provided
415
+ #### WASM-Supported Options
416
+
417
+ ```javascript
418
+ // Option 1: Fetch policy store from URL (simple)
419
+ const BOOTSTRAP_CONFIG = {
420
+ CEDARLING_POLICY_STORE_URI: "https://example.com/policy-store.cjar",
421
+ // ... other config
422
+ };
423
+ const cedarling = await init(BOOTSTRAP_CONFIG);
424
+
425
+ // Option 2: Inline JSON string (for embedded policy stores)
426
+ // policyStoreJson is the policy store JSON as a string
427
+ // See: https://docs.jans.io/stable/cedarling/reference/cedarling-policy-store/
428
+ const policyStoreJson = '{"cedar_version":"4.0","policy_stores":{...}}';
429
+ const BOOTSTRAP_CONFIG = {
430
+ CEDARLING_POLICY_STORE_LOCAL: policyStoreJson,
431
+ // ... other config
432
+ };
433
+ const cedarling = await init(BOOTSTRAP_CONFIG);
434
+
435
+ // Option 3: Custom fetch with auth headers (use init_from_archive_bytes)
436
+ const response = await fetch("https://example.com/policy-store.cjar", {
437
+ headers: { Authorization: `Bearer ${token}` },
438
+ });
439
+ const bytes = new Uint8Array(await response.arrayBuffer());
440
+ const cedarling = await init_from_archive_bytes(BOOTSTRAP_CONFIG, bytes);
441
+ ```
442
+
443
+ > **Note:** Directory-based loading and file-based loading are **NOT supported in WASM** (no filesystem access). Use URL-based loading or `init_from_archive_bytes` for custom fetch scenarios.
444
+
445
+ #### Cedar Archive (.cjar) Format
446
+
447
+ For the new directory-based format in WASM, package the directory structure as a `.cjar` file (ZIP archive):
448
+
449
+ ```bash
450
+ cd policy-store && zip -r ../policy-store.cjar .
451
+ ```
452
+
453
+ See [Policy Store Formats](../../../docs/cedarling/reference/cedarling-policy-store.md#policy-store-formats) for details on the directory structure and metadata.json format.
261
454
 
262
455
  ### Testing Configuration
263
456
 
@@ -267,12 +460,151 @@ For testing scenarios, you may want to disable JWT validation. You can configure
267
460
  const BOOTSTRAP_CONFIG = {
268
461
  CEDARLING_JWT_SIG_VALIDATION: "disabled",
269
462
  CEDARLING_JWT_STATUS_VALIDATION: "disabled",
270
- CEDARLING_ID_TOKEN_TRUST_MODE: "never",
271
463
  };
272
464
  ```
273
465
 
274
- For complete configuration documentation, see [cedarling-properties.md](../../../docs/cedarling/cedarling-properties.md) or on [our page](https://docs.jans.io/stable/cedarling/cedarling-properties/) .
466
+ For complete configuration documentation, see [cedarling-properties.md](../../../docs/cedarling/cedarling-properties.md) or on [our page](https://docs.jans.io/stable/cedarling/cedarling-properties/).
467
+
468
+ ## Context Data API
469
+
470
+ The Context Data API allows you to push external data into the Cedarling evaluation context, making it available in Cedar policies through the `context.data` namespace.
471
+
472
+ ### Push Data
473
+
474
+ Store data with an optional TTL (Time To Live):
475
+
476
+ ```javascript
477
+ // Push data without TTL (uses default from config)
478
+ cedarling.push_data_ctx("user:123", {
479
+ role: ["admin", "editor"],
480
+ country: "US"
481
+ });
482
+
483
+ // Push data with TTL (5 minutes = 300 seconds)
484
+ cedarling.push_data_ctx("config:app", { setting: "value" }, 300);
485
+
486
+ // Push different data types
487
+ cedarling.push_data_ctx("key1", "string_value");
488
+ cedarling.push_data_ctx("key2", 42);
489
+ cedarling.push_data_ctx("key3", [1, 2, 3]);
490
+ cedarling.push_data_ctx("key4", { nested: "data" });
491
+ ```
492
+
493
+ ### Get Data
494
+
495
+ Retrieve stored data:
496
+
497
+ ```javascript
498
+ // Get data by key
499
+ const value = cedarling.get_data_ctx("user:123");
500
+ if (value) {
501
+ console.log(`User roles: ${value.role}`);
502
+ }
503
+ ```
504
+
505
+ ### Get Data Entry with Metadata
506
+
507
+ Get a data entry with full metadata including creation time, expiration, access count, and type:
508
+
509
+ ```javascript
510
+ const entry = cedarling.get_data_entry_ctx("user:123");
511
+ if (entry) {
512
+ console.log(`Key: ${entry.key}`);
513
+ console.log(`Created at: ${entry.created_at}`);
514
+ console.log(`Access count: ${entry.access_count}`);
515
+ console.log(`Data type: ${entry.data_type}`);
516
+ console.log(`Value:`, entry.value);
517
+ }
518
+ ```
519
+
520
+ ### Remove Data
521
+
522
+ Remove a specific entry:
523
+
524
+ ```javascript
525
+ // Remove data by key
526
+ const removed = cedarling.remove_data_ctx("user:123");
527
+ if (removed) {
528
+ console.log("Entry was removed");
529
+ } else {
530
+ console.log("Entry did not exist");
531
+ }
532
+ ```
533
+
534
+ ### Clear All Data
535
+
536
+ Remove all entries from the data store:
275
537
 
538
+ ```javascript
539
+ cedarling.clear_data_ctx();
276
540
  ```
277
541
 
542
+ ### List All Data
543
+
544
+ List all entries with their metadata:
545
+
546
+ ```javascript
547
+ const entries = cedarling.list_data_ctx();
548
+ entries.forEach(entry => {
549
+ console.log(`Key: ${entry.key}, Type: ${entry.data_type}, Created: ${entry.created_at}`);
550
+ });
551
+ ```
552
+
553
+ ### Get Statistics
554
+
555
+ Get statistics about the data store:
556
+
557
+ ```javascript
558
+ const stats = cedarling.get_stats_ctx();
559
+ console.log(`Entries: ${stats.entry_count}/${stats.max_entries}`);
560
+ console.log(`Total size: ${stats.total_size_bytes} bytes`);
561
+ console.log(`Capacity usage: ${stats.capacity_usage_percent}%`);
562
+ ```
563
+
564
+ ### Error Handling
565
+
566
+ The Context Data API methods throw errors for different error conditions:
567
+
568
+ ```javascript
569
+ try {
570
+ cedarling.push_data_ctx("", { data: "value" }); // Empty key
571
+ } catch (error) {
572
+ if (error.message.includes("InvalidKey")) {
573
+ console.log("Invalid key provided");
574
+ }
575
+ }
576
+
577
+ const value = cedarling.get_data_ctx("nonexistent");
578
+ if (value === null) {
579
+ console.log("Key not found");
580
+ }
581
+ ```
582
+
583
+ ### Using Data in Cedar Policies
584
+
585
+ Data pushed via the Context Data API is automatically available in Cedar policies under the `context.data` namespace:
586
+
587
+ ```cedar
588
+ permit(
589
+ principal,
590
+ action == Action::"read",
591
+ resource
592
+ ) when {
593
+ context.data["user:123"].role.contains("admin")
594
+ };
595
+ ```
596
+
597
+ The data is injected into the evaluation context before policy evaluation, allowing policies to make decisions based on dynamically pushed data.
598
+
599
+ ## Trusted Issuer Loading Info
600
+
601
+ When a policy store contains `trusted-issuers/` entries, you can inspect loading status:
602
+
603
+ ```javascript
604
+ const loaded = cedarling.is_trusted_issuer_loaded_by_name("issuer_id");
605
+ const loadedByIss = cedarling.is_trusted_issuer_loaded_by_iss("https://issuer.example.org");
606
+ const total = cedarling.total_issuers();
607
+ const loadedCount = cedarling.loaded_trusted_issuers_count();
608
+ const loadedIds = cedarling.loaded_trusted_issuer_ids();
609
+ const failedIds = cedarling.failed_trusted_issuer_ids();
278
610
  ```