@parmanasystems/governance 1.56.0 → 1.65.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +411 -114
- package/dist/index.d.ts +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,49 +1,288 @@
|
|
|
1
1
|
# @parmanasystems/governance
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Governance lifecycle infrastructure for deterministic policy versioning, validation, bundling, and release management.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@parmanasystems/governance)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Overview
|
|
10
|
+
|
|
11
|
+
`@parmanasystems/governance` provides the governance lifecycle layer for Parmana Systems.
|
|
12
|
+
|
|
13
|
+
It manages:
|
|
14
|
+
|
|
15
|
+
- policy creation
|
|
16
|
+
- policy validation
|
|
17
|
+
- immutable policy lineage
|
|
18
|
+
- governance versioning
|
|
19
|
+
- deterministic governance bundles
|
|
20
|
+
- signed governance artifacts
|
|
21
|
+
- reproducible governance releases
|
|
22
|
+
|
|
23
|
+
Governance policies are treated as immutable, reproducible infrastructure artifacts.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
# Mental Model
|
|
28
|
+
|
|
29
|
+
```txt id="9b6j2m"
|
|
30
|
+
Author Policy
|
|
31
|
+
↓
|
|
32
|
+
Validate Policy
|
|
33
|
+
↓
|
|
34
|
+
Generate Bundle
|
|
35
|
+
↓
|
|
36
|
+
Sign Bundle
|
|
37
|
+
↓
|
|
38
|
+
Release Governance Artifact
|
|
39
|
+
↓
|
|
40
|
+
Execute Governed Decisions
|
|
41
|
+
↓
|
|
42
|
+
Independent Verification
|
|
43
|
+
|
|
44
|
+
The governance layer defines how policies become reproducible, portable, and verifiable governance infrastructure.
|
|
45
|
+
|
|
46
|
+
What this package does
|
|
47
|
+
|
|
48
|
+
The governance package handles:
|
|
49
|
+
|
|
50
|
+
policy scaffolding
|
|
51
|
+
policy validation
|
|
52
|
+
policy version upgrades
|
|
53
|
+
governance bundle generation
|
|
54
|
+
deterministic manifest generation
|
|
55
|
+
governance artifact signing
|
|
56
|
+
immutable policy lineage management
|
|
57
|
+
governance release reproducibility
|
|
58
|
+
|
|
59
|
+
Policies are versioned governance artifacts with deterministic provenance.
|
|
60
|
+
|
|
61
|
+
When to use this package
|
|
62
|
+
|
|
63
|
+
Use this package when:
|
|
64
|
+
|
|
65
|
+
creating governance policies
|
|
66
|
+
versioning deterministic governance logic
|
|
67
|
+
validating governance structure
|
|
68
|
+
generating signed governance bundles
|
|
69
|
+
implementing governed release workflows
|
|
70
|
+
managing immutable governance lineage
|
|
71
|
+
building governance authoring pipelines
|
|
72
|
+
|
|
73
|
+
Do NOT use this package when:
|
|
74
|
+
|
|
75
|
+
executing governed decisions
|
|
76
|
+
independently verifying attestations
|
|
77
|
+
deploying HTTP runtimes
|
|
78
|
+
integrating applications over HTTP
|
|
79
|
+
|
|
80
|
+
In those cases use:
|
|
81
|
+
|
|
82
|
+
Package Responsibility
|
|
83
|
+
@parmanasystems/execution governed execution
|
|
84
|
+
@parmanasystems/verifier independent verification
|
|
85
|
+
@parmanasystems/server deployable runtime
|
|
86
|
+
@parmanasystems/sdk-client HTTP integration
|
|
87
|
+
Features
|
|
88
|
+
Immutable governance versioning
|
|
89
|
+
Deterministic policy validation
|
|
90
|
+
Signed governance bundles
|
|
91
|
+
Canonical manifest generation
|
|
92
|
+
Runtime compatibility requirements
|
|
93
|
+
Portable governance artifacts
|
|
94
|
+
Governance provenance lineage
|
|
95
|
+
Deterministic governance releases
|
|
96
|
+
Fail-closed governance validation
|
|
97
|
+
Installation
|
|
98
|
+
npm install @parmanasystems/governance
|
|
99
|
+
Quick Start
|
|
100
|
+
import {
|
|
101
|
+
createPolicy,
|
|
102
|
+
validatePolicy,
|
|
103
|
+
generateBundle,
|
|
104
|
+
} from "@parmanasystems/governance";
|
|
8
105
|
|
|
9
|
-
|
|
106
|
+
await createPolicy(
|
|
107
|
+
"claims-approval"
|
|
108
|
+
);
|
|
10
109
|
|
|
11
|
-
|
|
110
|
+
await validatePolicy(
|
|
111
|
+
"./policies/claims-approval/v1/policy.json"
|
|
112
|
+
);
|
|
12
113
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
114
|
+
const bundle =
|
|
115
|
+
await generateBundle(
|
|
116
|
+
"claims-approval",
|
|
117
|
+
"v1",
|
|
118
|
+
"./policies/claims-approval/v1"
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
console.log(
|
|
122
|
+
bundle.bundle_hash
|
|
123
|
+
);
|
|
124
|
+
Core Concepts
|
|
125
|
+
Immutable Policy Lineage
|
|
126
|
+
|
|
127
|
+
Policies are immutable governance artifacts.
|
|
128
|
+
|
|
129
|
+
Example lineage:
|
|
130
|
+
|
|
131
|
+
claims-approval/
|
|
132
|
+
v1/
|
|
133
|
+
v2/
|
|
134
|
+
v3/
|
|
135
|
+
|
|
136
|
+
Older policy versions remain immutable after release.
|
|
137
|
+
|
|
138
|
+
New governance behavior requires new versions.
|
|
139
|
+
|
|
140
|
+
This ensures:
|
|
141
|
+
|
|
142
|
+
reproducibility
|
|
143
|
+
auditability
|
|
144
|
+
deterministic governance lineage
|
|
145
|
+
historical governance integrity
|
|
146
|
+
signalsSchema
|
|
16
147
|
|
|
17
|
-
|
|
148
|
+
Policies define governed input structure explicitly.
|
|
18
149
|
|
|
19
|
-
|
|
150
|
+
Example:
|
|
20
151
|
|
|
21
|
-
```json
|
|
22
152
|
{
|
|
153
|
+
"signalsSchema": {
|
|
154
|
+
"risk_score": {
|
|
155
|
+
"type": "integer",
|
|
156
|
+
"required": true
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
Signals are:
|
|
162
|
+
|
|
163
|
+
typed
|
|
164
|
+
deterministic
|
|
165
|
+
explicitly governed
|
|
166
|
+
schema validated
|
|
167
|
+
Governance Bundles
|
|
168
|
+
|
|
169
|
+
Governance bundles package deterministic governance artifacts.
|
|
170
|
+
|
|
171
|
+
Bundles include:
|
|
172
|
+
|
|
173
|
+
policy definition
|
|
174
|
+
canonical manifest
|
|
175
|
+
governance hashes
|
|
176
|
+
signatures
|
|
177
|
+
provenance metadata
|
|
178
|
+
|
|
179
|
+
Bundles are:
|
|
180
|
+
|
|
181
|
+
deterministic
|
|
182
|
+
portable
|
|
183
|
+
reproducible
|
|
184
|
+
independently verifiable
|
|
185
|
+
Bundle Provenance
|
|
186
|
+
|
|
187
|
+
Governance provenance includes:
|
|
188
|
+
|
|
189
|
+
deterministic hashes
|
|
190
|
+
canonical manifests
|
|
191
|
+
cryptographic signatures
|
|
192
|
+
runtime compatibility lineage
|
|
193
|
+
|
|
194
|
+
This enables:
|
|
195
|
+
|
|
196
|
+
reproducible releases
|
|
197
|
+
independent verification
|
|
198
|
+
governance auditability
|
|
199
|
+
portable governance validation
|
|
200
|
+
Fail-Closed Governance
|
|
201
|
+
|
|
202
|
+
Governance validation is fail-closed.
|
|
203
|
+
|
|
204
|
+
Invalid governance artifacts reject execution.
|
|
205
|
+
|
|
206
|
+
Validation failures include:
|
|
207
|
+
|
|
208
|
+
malformed policies
|
|
209
|
+
invalid schemas
|
|
210
|
+
invalid rule structure
|
|
211
|
+
compatibility violations
|
|
212
|
+
signature failures
|
|
213
|
+
Policy Structure
|
|
214
|
+
|
|
215
|
+
Policies live at:
|
|
216
|
+
|
|
217
|
+
policies/{policyId}/{version}/policy.json
|
|
218
|
+
|
|
219
|
+
Example:
|
|
220
|
+
|
|
221
|
+
policies/
|
|
222
|
+
claims-approval/
|
|
223
|
+
v1/
|
|
224
|
+
policy.json
|
|
225
|
+
Example Policy
|
|
226
|
+
{
|
|
227
|
+
"policyId": "claims-approval",
|
|
228
|
+
|
|
229
|
+
"version": "v1",
|
|
230
|
+
|
|
23
231
|
"schemaVersion": "1.0.0",
|
|
232
|
+
|
|
24
233
|
"signalsSchema": {
|
|
25
|
-
|
|
26
|
-
"
|
|
27
|
-
|
|
234
|
+
|
|
235
|
+
"insurance_active": {
|
|
236
|
+
"type": "boolean",
|
|
237
|
+
"required": true
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
"risk_score": {
|
|
241
|
+
"type": "integer",
|
|
242
|
+
"required": true
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
"claim_amount": {
|
|
246
|
+
"type": "integer",
|
|
247
|
+
"required": false
|
|
248
|
+
}
|
|
28
249
|
},
|
|
250
|
+
|
|
29
251
|
"rules": [
|
|
252
|
+
|
|
30
253
|
{
|
|
31
254
|
"id": "rule_low_risk",
|
|
255
|
+
|
|
32
256
|
"condition": {
|
|
33
257
|
"all": [
|
|
34
|
-
|
|
35
|
-
{
|
|
258
|
+
|
|
259
|
+
{
|
|
260
|
+
"signal": "insurance_active",
|
|
261
|
+
"equals": true
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
{
|
|
265
|
+
"signal": "risk_score",
|
|
266
|
+
"less_than": 50
|
|
267
|
+
}
|
|
36
268
|
]
|
|
37
269
|
},
|
|
270
|
+
|
|
38
271
|
"outcome": {
|
|
39
272
|
"action": "approve",
|
|
40
273
|
"requires_override": false,
|
|
41
274
|
"reason": "Low risk profile"
|
|
42
275
|
}
|
|
43
276
|
},
|
|
277
|
+
|
|
44
278
|
{
|
|
45
279
|
"id": "rule_high_risk",
|
|
46
|
-
|
|
280
|
+
|
|
281
|
+
"condition": {
|
|
282
|
+
"signal": "risk_score",
|
|
283
|
+
"greater_than": 80
|
|
284
|
+
},
|
|
285
|
+
|
|
47
286
|
"outcome": {
|
|
48
287
|
"action": "reject",
|
|
49
288
|
"requires_override": false,
|
|
@@ -52,124 +291,182 @@ Policies live at `policies/{policyId}/{version}/policy.json`:
|
|
|
52
291
|
}
|
|
53
292
|
]
|
|
54
293
|
}
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Rules are evaluated in order. The first matching rule determines the outcome. If no rule matches, execution fails closed.
|
|
58
|
-
|
|
59
|
-
## API
|
|
60
294
|
|
|
61
|
-
|
|
295
|
+
Rules are evaluated deterministically in order.
|
|
62
296
|
|
|
63
|
-
|
|
297
|
+
The first matching rule determines the governed outcome.
|
|
64
298
|
|
|
65
|
-
|
|
66
|
-
import { createPolicy } from "@parmanasystems/governance";
|
|
67
|
-
await createPolicy("fraud-detection");
|
|
68
|
-
```
|
|
299
|
+
If no rule matches, evaluation fails closed.
|
|
69
300
|
|
|
70
|
-
|
|
301
|
+
Governance Lifecycle APIs
|
|
302
|
+
createPolicy
|
|
71
303
|
|
|
72
|
-
|
|
304
|
+
Scaffolds a governance policy directory.
|
|
73
305
|
|
|
74
|
-
|
|
75
|
-
|
|
306
|
+
import {
|
|
307
|
+
createPolicy
|
|
308
|
+
} from "@parmanasystems/governance";
|
|
76
309
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
});
|
|
82
|
-
```
|
|
310
|
+
await createPolicy(
|
|
311
|
+
"fraud-detection"
|
|
312
|
+
);
|
|
313
|
+
definePolicy
|
|
83
314
|
|
|
84
|
-
|
|
315
|
+
Creates a policy definition in memory.
|
|
85
316
|
|
|
86
|
-
|
|
317
|
+
import {
|
|
318
|
+
definePolicy
|
|
319
|
+
} from "@parmanasystems/governance";
|
|
87
320
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
validatePolicy(policy);
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### `upgradePolicy(policy, nextVersion): PolicyDefinition`
|
|
94
|
-
|
|
95
|
-
Creates a new version of an existing policy.
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
|
-
import { upgradePolicy } from "@parmanasystems/governance";
|
|
99
|
-
const v2 = upgradePolicy(policyV1, "v2");
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### `generateBundle(policyId, version, directory): Promise<BundleGenerationResult>`
|
|
103
|
-
|
|
104
|
-
Generates `bundle.manifest.json` and signs it as `bundle.sig`.
|
|
105
|
-
|
|
106
|
-
```typescript
|
|
107
|
-
import { generateBundle } from "@parmanasystems/governance";
|
|
108
|
-
|
|
109
|
-
const result = await generateBundle("claims-approval", "v1", "./policies/claims-approval/v1");
|
|
110
|
-
console.log(result.bundle_hash); // SHA-256 of manifest
|
|
111
|
-
console.log(result.signature_path); // path to bundle.sig
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
### `verifyBundle(directory): Promise<boolean>`
|
|
321
|
+
const policy =
|
|
322
|
+
definePolicy({
|
|
115
323
|
|
|
116
|
-
|
|
324
|
+
id:
|
|
325
|
+
"claims-approval",
|
|
117
326
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const ok = await verifyBundle("./policies/claims-approval/v1");
|
|
121
|
-
```
|
|
327
|
+
version:
|
|
328
|
+
"v1",
|
|
122
329
|
|
|
123
|
-
|
|
330
|
+
rules: [],
|
|
331
|
+
});
|
|
332
|
+
validatePolicy
|
|
124
333
|
|
|
125
|
-
|
|
334
|
+
Validates governance structure.
|
|
126
335
|
|
|
127
|
-
|
|
128
|
-
interface PolicyDefinition {
|
|
129
|
-
id: string;
|
|
130
|
-
version: string;
|
|
131
|
-
rules: PolicyRule[];
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
interface PolicyRule {
|
|
135
|
-
id: string;
|
|
136
|
-
condition: string;
|
|
137
|
-
action: string;
|
|
138
|
-
}
|
|
139
|
-
```
|
|
336
|
+
Checks:
|
|
140
337
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
```
|
|
338
|
+
schemaVersion
|
|
339
|
+
signalsSchema
|
|
340
|
+
rules
|
|
341
|
+
outcomes
|
|
342
|
+
deterministic structure
|
|
343
|
+
import {
|
|
344
|
+
validatePolicy
|
|
345
|
+
} from "@parmanasystems/governance";
|
|
151
346
|
|
|
152
|
-
|
|
347
|
+
validatePolicy(policy);
|
|
348
|
+
upgradePolicy
|
|
349
|
+
|
|
350
|
+
Creates immutable next-version governance lineage.
|
|
351
|
+
|
|
352
|
+
import {
|
|
353
|
+
upgradePolicy
|
|
354
|
+
} from "@parmanasystems/governance";
|
|
355
|
+
|
|
356
|
+
const v2 =
|
|
357
|
+
upgradePolicy(
|
|
358
|
+
policyV1,
|
|
359
|
+
"v2"
|
|
360
|
+
);
|
|
361
|
+
generateBundle
|
|
362
|
+
|
|
363
|
+
Generates deterministic governance bundles.
|
|
364
|
+
|
|
365
|
+
Produces:
|
|
366
|
+
|
|
367
|
+
bundle.manifest.json
|
|
368
|
+
bundle.sig
|
|
369
|
+
import {
|
|
370
|
+
generateBundle
|
|
371
|
+
} from "@parmanasystems/governance";
|
|
372
|
+
|
|
373
|
+
const result =
|
|
374
|
+
await generateBundle(
|
|
375
|
+
"claims-approval",
|
|
376
|
+
"v1",
|
|
377
|
+
"./policies/claims-approval/v1"
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
console.log(
|
|
381
|
+
result.bundle_hash
|
|
382
|
+
);
|
|
383
|
+
verifyBundle
|
|
384
|
+
|
|
385
|
+
Verifies governance bundle integrity.
|
|
386
|
+
|
|
387
|
+
Checks:
|
|
388
|
+
|
|
389
|
+
signatures
|
|
390
|
+
hashes
|
|
391
|
+
manifest integrity
|
|
392
|
+
import {
|
|
393
|
+
verifyBundle
|
|
394
|
+
} from "@parmanasystems/governance";
|
|
395
|
+
|
|
396
|
+
const valid =
|
|
397
|
+
await verifyBundle(
|
|
398
|
+
"./policies/claims-approval/v1"
|
|
399
|
+
);
|
|
400
|
+
Governance Bundle Structure
|
|
401
|
+
claims-approval/
|
|
402
|
+
v1/
|
|
403
|
+
policy.json
|
|
404
|
+
bundle.manifest.json
|
|
405
|
+
bundle.sig
|
|
406
|
+
Runtime Requirements
|
|
407
|
+
|
|
408
|
+
Governance bundles may specify runtime compatibility requirements.
|
|
409
|
+
|
|
410
|
+
Example:
|
|
153
411
|
|
|
154
|
-
```typescript
|
|
155
412
|
interface RuntimeRequirements {
|
|
156
|
-
required_capabilities: string[];
|
|
157
|
-
supported_runtime_versions: string[];
|
|
158
|
-
supported_schema_versions: string[];
|
|
159
|
-
}
|
|
160
|
-
```
|
|
161
413
|
|
|
162
|
-
|
|
414
|
+
required_capabilities:
|
|
415
|
+
string[];
|
|
163
416
|
|
|
164
|
-
|
|
417
|
+
supported_runtime_versions:
|
|
418
|
+
string[];
|
|
165
419
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
| `patient-triage` | v1 | Patient triage routing by severity |
|
|
170
|
-
| `fraud-detection` | v1 | Transaction fraud detection |
|
|
171
|
-
| `claims-advanced` | v1 | Advanced claims with multi-condition rules |
|
|
172
|
-
|
|
173
|
-
## License
|
|
420
|
+
supported_schema_versions:
|
|
421
|
+
string[];
|
|
422
|
+
}
|
|
174
423
|
|
|
175
|
-
|
|
424
|
+
This enables deterministic compatibility enforcement.
|
|
425
|
+
|
|
426
|
+
Included Example Policies
|
|
427
|
+
Policy Versions Description
|
|
428
|
+
claims-approval v1, v2 insurance claims governance
|
|
429
|
+
patient-triage v1 healthcare triage routing
|
|
430
|
+
fraud-detection v1 transaction fraud governance
|
|
431
|
+
claims-advanced v1 advanced multi-condition evaluation
|
|
432
|
+
Recommended Architecture
|
|
433
|
+
Governance Authoring
|
|
434
|
+
↓
|
|
435
|
+
Policy Validation
|
|
436
|
+
↓
|
|
437
|
+
Governance Bundle
|
|
438
|
+
↓
|
|
439
|
+
Signed Governance Artifact
|
|
440
|
+
↓
|
|
441
|
+
Governed Runtime Execution
|
|
442
|
+
↓
|
|
443
|
+
Independent Verification
|
|
444
|
+
Relationship to Other Parmana Packages
|
|
445
|
+
Package Responsibility
|
|
446
|
+
@parmanasystems/governance governance lifecycle
|
|
447
|
+
@parmanasystems/execution governed execution
|
|
448
|
+
@parmanasystems/verifier independent verification
|
|
449
|
+
@parmanasystems/bundle canonical governance artifacts
|
|
450
|
+
@parmanasystems/server deployable runtime
|
|
451
|
+
Security Model
|
|
452
|
+
|
|
453
|
+
The governance layer enforces:
|
|
454
|
+
|
|
455
|
+
immutable policy lineage
|
|
456
|
+
deterministic governance structure
|
|
457
|
+
fail-closed validation
|
|
458
|
+
signed governance artifacts
|
|
459
|
+
reproducible governance releases
|
|
460
|
+
canonical manifest integrity
|
|
461
|
+
runtime compatibility enforcement
|
|
462
|
+
|
|
463
|
+
Governance artifacts are designed to be:
|
|
464
|
+
|
|
465
|
+
portable
|
|
466
|
+
reproducible
|
|
467
|
+
independently verifiable
|
|
468
|
+
Most Important Principle
|
|
469
|
+
Governance policies are immutable, reproducible infrastructure artifacts with deterministic lineage.
|
|
470
|
+
License
|
|
471
|
+
|
|
472
|
+
Apache-2.0
|
package/dist/index.d.ts
CHANGED
|
@@ -90,9 +90,9 @@ interface RuntimeRequirements {
|
|
|
90
90
|
/** Runtime capability strings that must appear in the executing runtime's capability list. */
|
|
91
91
|
required_capabilities: string[];
|
|
92
92
|
/** Runtime version strings (e.g. `"1.0.0"`) acceptable to this bundle. */
|
|
93
|
-
|
|
93
|
+
supported_runtimeVersions: string[];
|
|
94
94
|
/** Schema version strings (e.g. `"1.0.0"`) that this bundle's artifacts conform to. */
|
|
95
|
-
|
|
95
|
+
supported_schemaVersions: string[];
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
/**
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/create-policy.ts","../src/generate-bundle.ts","../src/upgrade-policy.ts","../src/validate-policy.ts","../src/define-policy.ts","../src/schema/v1/semantics.ts","../src/schema/v1/operators.ts","../src/schema/v1/evaluator.ts","../src/schema/load-schema-runtime.ts"],"sourcesContent":["import * as fs from \"node:fs\";\r\nimport * as path from \"node:path\";\r\n\r\n/**\r\n * Scaffolds a new policy directory at `./policies/<policyId>/v1/` and writes\r\n * a skeleton `policy.json` to it.\r\n *\r\n * @param policyId - Unique policy identifier. Must not already exist on disk.\r\n * @returns Absolute path of the created `v1` version directory.\r\n * @throws When `./policies/<policyId>` already exists.\r\n */\r\nexport function createPolicy(\r\n policyId: string\r\n): string {\r\n const policyRoot = path.join(\r\n \"./policies\",\r\n policyId\r\n );\r\n\r\n const versionDirectory =\r\n path.join(\r\n policyRoot,\r\n \"v1\"\r\n );\r\n\r\n if (fs.existsSync(policyRoot)) {\r\n throw new Error(\r\n `Policy already exists: ${policyId}`\r\n );\r\n }\r\n\r\n fs.mkdirSync(\r\n versionDirectory,\r\n {\r\n recursive: true,\r\n }\r\n );\r\n\r\n fs.writeFileSync(\r\n path.join(\r\n versionDirectory,\r\n \"policy.json\"\r\n ),\r\n\r\n JSON.stringify(\r\n {\r\n policy: policyId,\r\n version: \"v1\",\r\n },\r\n null,\r\n 2\r\n ),\r\n\r\n \"utf8\"\r\n );\r\n\r\n return versionDirectory;\r\n}\r\n\r\n\r\n\r\n\r\n","import * as path from \"node:path\";\r\n\r\nimport {\r\n generateManifest,\r\n writeManifest,\r\n} from \"@parmanasystems/bundle\";\r\n\r\nimport {\r\n signManifest,\r\n writeSignature,\r\n} from \"@parmanasystems/crypto\";\r\n\r\nimport type {\r\n BundleGenerationResult,\r\n} from \"./types.js\";\r\n\r\n/**\r\n * Generates a signed bundle for `policyId`/`policyVersion` in `policyDirectory`:\r\n * 1. Hashes all artifacts and writes `bundle.manifest.json`.\r\n * 2. Signs the manifest and writes `bundle.sig`.\r\n *\r\n * The signing key is loaded via `loadPrivateKey()` (dev-keys or env injection).\r\n *\r\n * @param policyId - Policy identifier embedded in the manifest.\r\n * @param policyVersion - Policy version string (e.g. `\"v1\"`).\r\n * @param policyDirectory - Path to the directory containing the policy artifacts.\r\n * @returns Paths to the written files and the deterministic bundle hash.\r\n */\r\nexport function generateBundle(\r\n policyId: string,\r\n policyVersion: string,\r\n policyDirectory: string\r\n): BundleGenerationResult {\r\n\r\n const directory =\r\n path.resolve(\r\n policyDirectory\r\n );\r\n\r\n const manifest =\r\n generateManifest(\r\n policyId,\r\n policyVersion,\r\n directory\r\n );\r\n\r\n writeManifest(\r\n manifest,\r\n directory\r\n );\r\n\r\n const manifestPath =\r\n path.join(\r\n directory,\r\n \"bundle.manifest.json\"\r\n );\r\n\r\n const signature =\r\n signManifest(\r\n manifestPath\r\n );\r\n\r\n writeSignature(\r\n signature,\r\n directory\r\n );\r\n\r\n return {\r\n success: true,\r\n\r\n manifest_path:\r\n manifestPath,\r\n\r\n signature_path:\r\n path.join(\r\n directory,\r\n \"bundle.sig\"\r\n ),\r\n\r\n bundle_hash:\r\n manifest.bundle_hash,\r\n };\r\n}\r\n\r\n\r\n\r\n\r\n","import * as fs from \"node:fs\";\r\nimport * as path from \"node:path\";\r\n\r\n/**\r\n * Creates the next version directory for `policyId` by copying the latest\r\n * existing version and incrementing its numeric suffix (e.g. `v1` → `v2`).\r\n * The copied `policy.json` has its `version` field updated to the new version\r\n * string.\r\n *\r\n * @param policyId - An existing policy identifier under `./policies/`.\r\n * @returns Absolute path of the newly created version directory.\r\n * @throws When the policy does not exist on disk.\r\n */\r\nexport function upgradePolicy(\r\n policyId: string\r\n): string {\r\n const policyRoot = path.join(\r\n \"./policies\",\r\n policyId\r\n );\r\n\r\n if (!fs.existsSync(policyRoot)) {\r\n throw new Error(\r\n `Policy does not exist: ${policyId}`\r\n );\r\n }\r\n\r\n const versions = fs\r\n .readdirSync(policyRoot)\r\n .filter((entry) =>\r\n entry.startsWith(\"v\")\r\n )\r\n .sort();\r\n\r\n const latestVersion =\r\n versions[\r\n versions.length - 1\r\n ];\r\n\r\n const latestNumber =\r\n Number(\r\n latestVersion.replace(\"v\", \"\")\r\n );\r\n\r\n const nextVersion =\r\n `v${latestNumber + 1}`;\r\n\r\n const latestDirectory =\r\n path.join(\r\n policyRoot,\r\n latestVersion\r\n );\r\n\r\n const nextDirectory =\r\n path.join(\r\n policyRoot,\r\n nextVersion\r\n );\r\n\r\n fs.cpSync(\r\n latestDirectory,\r\n nextDirectory,\r\n {\r\n recursive: true,\r\n }\r\n );\r\n\r\n const policyFile =\r\n path.join(\r\n nextDirectory,\r\n \"policy.json\"\r\n );\r\n\r\n const content =\r\n JSON.parse(\r\n fs.readFileSync(\r\n policyFile,\r\n \"utf8\"\r\n )\r\n );\r\n\r\n content.version =\r\n nextVersion;\r\n\r\n fs.writeFileSync(\r\n policyFile,\r\n JSON.stringify(\r\n content,\r\n null,\r\n 2\r\n ),\r\n \"utf8\"\r\n );\r\n\r\n return nextDirectory;\r\n}\r\n\r\n\r\n\r\n\r\n","import * as fs from \"node:fs\";\r\nimport * as path from \"node:path\";\r\n\r\nimport {\r\n readManifest,\r\n verifyManifest,\r\n} from \"@parmanasystems/bundle\";\r\n\r\nimport {\r\n readSignature,\r\n verifySignature,\r\n} from \"@parmanasystems/crypto\";\r\n\r\n/**\r\n * Validates every version directory under `./policies/<policyId>` by\r\n * re-verifying all bundle manifests (content hashes) and cryptographic\r\n * signatures (bundle.sig).\r\n *\r\n * Returns `true` only when every version passes all checks.\r\n *\r\n * @param policyId - Policy identifier whose version directories will be checked.\r\n * @throws When the policy directory does not exist.\r\n */\r\nexport function validatePolicy(\r\n policyId: string\r\n): boolean {\r\n\r\n const policyRoot =\r\n path.join(\r\n \"./policies\",\r\n policyId\r\n );\r\n\r\n if (\r\n !fs.existsSync(\r\n policyRoot\r\n )\r\n ) {\r\n throw new Error(\r\n `Policy does not exist: ${policyId}`\r\n );\r\n }\r\n\r\n const versions =\r\n fs\r\n .readdirSync(\r\n policyRoot\r\n )\r\n .filter(\r\n (entry) =>\r\n entry.startsWith(\"v\")\r\n )\r\n .sort();\r\n\r\n for (const version of versions) {\r\n\r\n const versionDirectory =\r\n path.join(\r\n policyRoot,\r\n version\r\n );\r\n\r\n const manifest =\r\n readManifest(\r\n versionDirectory\r\n );\r\n\r\n const manifestResult =\r\n verifyManifest(\r\n manifest,\r\n versionDirectory\r\n );\r\n\r\n if (\r\n !manifestResult.valid\r\n ) {\r\n return false;\r\n }\r\n\r\n const signature =\r\n readSignature(\r\n versionDirectory\r\n );\r\n\r\n const manifestPath =\r\n path.join(\r\n versionDirectory,\r\n \"bundle.manifest.json\"\r\n );\r\n\r\n const signatureValid =\r\n verifySignature(\r\n manifestPath,\r\n signature\r\n );\r\n\r\n if (\r\n !signatureValid\r\n ) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n}\r\n\r\n\r\n\r\n\r\n","import type {\r\n PolicyDefinition,\r\n PolicyRule,\r\n} from \"./types.js\";\r\n\r\n/**\r\n * Constructs a {@link PolicyDefinition} from a plain config object.\r\n * Use this as the first step in the policy-authoring pipeline before\r\n * serializing the policy to disk and calling {@link generateBundle}.\r\n *\r\n * @param config - Policy id, version, and rules.\r\n */\r\nexport function definePolicy(config: {\r\n id: string;\r\n version: string;\r\n rules: PolicyRule[];\r\n}): PolicyDefinition {\r\n\r\n return {\r\n id: config.id,\r\n\r\n version: config.version,\r\n\r\n rules: config.rules,\r\n };\r\n}\r\n","export const schemaV1Semantics = {\r\n\r\n schemaVersion:\r\n \"1.0.0\",\r\n\r\n ruleConditionField:\r\n \"condition\",\r\n\r\n ruleOutcomeField:\r\n \"outcome\",\r\n\r\n signalReferenceField:\r\n \"signal\",\r\n\r\n supportedOperators: [\r\n \"equals\",\r\n \"greater_than\",\r\n \"less_than\",\r\n ],\r\n};","export const schemaV1Operators = {\r\n\r\n equals(\r\n left: unknown,\r\n right: unknown\r\n ): boolean {\r\n\r\n return left === right;\r\n },\r\n\r\n greater_than(\r\n left: number,\r\n right: number\r\n ): boolean {\r\n\r\n return left > right;\r\n },\r\n\r\n less_than(\r\n left: number,\r\n right: number\r\n ): boolean {\r\n\r\n return left < right;\r\n },\r\n};","import type {\r\n DecisionResult\r\n} from \"@parmanasystems/contracts\";\r\n\r\nimport {\r\n schemaV1Operators\r\n} from \"./operators.js\";\r\n\r\ninterface BaseCondition {\r\n signal: string;\r\n equals?: unknown;\r\n greater_than?: number;\r\n less_than?: number;\r\n}\r\n\r\ninterface AllCondition {\r\n all: RuleCondition[];\r\n}\r\n\r\ninterface AnyCondition {\r\n any: RuleCondition[];\r\n}\r\n\r\ntype RuleCondition =\r\n | BaseCondition\r\n | AllCondition\r\n | AnyCondition;\r\n\r\ninterface PolicyRule {\r\n id: string;\r\n\r\n condition: RuleCondition;\r\n\r\n outcome: {\r\n action:\r\n | \"approve\"\r\n | \"reject\";\r\n\r\n requires_override:\r\n boolean;\r\n\r\n reason?: string;\r\n };\r\n}\r\n\r\nexport interface SchemaV1Policy {\r\n schemaVersion: string;\r\n\r\n signalsSchema:\r\n Record<string, unknown>;\r\n\r\n rules: PolicyRule[];\r\n}\r\n\r\nfunction evaluateCondition(\r\n condition: RuleCondition,\r\n signals: Record<string, unknown>\r\n): boolean {\r\n\r\n if (\"all\" in condition) {\r\n return condition.all.every(\r\n c =>\r\n evaluateCondition(\r\n c,\r\n signals\r\n )\r\n );\r\n }\r\n\r\n if (\"any\" in condition) {\r\n return condition.any.some(\r\n c =>\r\n evaluateCondition(\r\n c,\r\n signals\r\n )\r\n );\r\n }\r\n\r\n const {\r\n signal,\r\n equals,\r\n greater_than,\r\n less_than,\r\n } = condition;\r\n\r\n if (!(signal in signals)) {\r\n\r\n throw new Error(\r\n `Signal not found: ${signal}`\r\n );\r\n }\r\n\r\n const actual =\r\n signals[signal];\r\n\r\n if (equals !== undefined) {\r\n\r\n return schemaV1Operators.equals(\r\n actual,\r\n equals\r\n );\r\n }\r\n\r\n if (\r\n greater_than !== undefined\r\n ) {\r\n\r\n return schemaV1Operators.greater_than(\r\n actual as number,\r\n greater_than\r\n );\r\n }\r\n\r\n if (\r\n less_than !== undefined\r\n ) {\r\n\r\n return schemaV1Operators.less_than(\r\n actual as number,\r\n less_than\r\n );\r\n }\r\n\r\n return false;\r\n}\r\n\r\nexport function evaluateSchemaV1(\r\n policy: SchemaV1Policy,\r\n signals: Record<string, unknown>\r\n): DecisionResult {\r\n\r\n for (const rule of policy.rules) {\r\n\r\n const matched =\r\n evaluateCondition(\r\n rule.condition,\r\n signals\r\n );\r\n\r\n if (matched) {\r\n\r\n return {\r\n status: \"decided\",\r\n\r\n outcome:\r\n rule.outcome,\r\n\r\n rule_id:\r\n rule.id,\r\n\r\n source:\r\n \"rule_match\",\r\n };\r\n }\r\n }\r\n\r\n throw new Error(\r\n \"[SYS-006] No rule matched — policy must cover all cases\"\r\n );\r\n}","import type {\r\n DecisionResult\r\n} from \"@parmanasystems/contracts\";\r\n\r\nimport {\r\n evaluateSchemaV1\r\n} from \"./v1/evaluator.js\";\r\n\r\nimport {\r\n schemaV1Operators\r\n} from \"./v1/operators.js\";\r\n\r\nimport {\r\n schemaV1Semantics\r\n} from \"./v1/semantics.js\";\r\n\r\nexport interface SchemaRuntime {\r\n\r\n semantics: unknown;\r\n\r\n operators: unknown;\r\n\r\n evaluate: (\r\n policy: unknown,\r\n signals: Record<string, unknown>\r\n ) => DecisionResult;\r\n}\r\n\r\nexport function loadSchemaRuntime(\r\n schemaVersion: string\r\n): SchemaRuntime {\r\n\r\n const major =\r\n Number(\r\n schemaVersion.split(\".\")[0]\r\n );\r\n\r\n switch (major) {\r\n\r\n case 1:\r\n\r\n return {\r\n\r\n semantics:\r\n schemaV1Semantics,\r\n\r\n operators:\r\n schemaV1Operators,\r\n\r\n evaluate:\r\n evaluateSchemaV1 as (\r\n policy: unknown,\r\n signals: Record<string, unknown>\r\n ) => DecisionResult,\r\n };\r\n\r\n default:\r\n\r\n throw new Error(\r\n `Unsupported schema version: ${schemaVersion}`\r\n );\r\n }\r\n}"],"mappings":"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","names":["path","fs","path","fs","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/create-policy.ts","../src/generate-bundle.ts","../src/upgrade-policy.ts","../src/validate-policy.ts","../src/define-policy.ts","../src/schema/v1/semantics.ts","../src/schema/v1/operators.ts","../src/schema/v1/evaluator.ts","../src/schema/load-schema-runtime.ts"],"sourcesContent":["import * as fs from \"node:fs\";\r\nimport * as path from \"node:path\";\r\n\r\n/**\r\n * Scaffolds a new policy directory at `./policies/<policyId>/v1/` and writes\r\n * a skeleton `policy.json` to it.\r\n *\r\n * @param policyId - Unique policy identifier. Must not already exist on disk.\r\n * @returns Absolute path of the created `v1` version directory.\r\n * @throws When `./policies/<policyId>` already exists.\r\n */\r\nexport function createPolicy(\r\n policyId: string\r\n): string {\r\n const policyRoot = path.join(\r\n \"./policies\",\r\n policyId\r\n );\r\n\r\n const versionDirectory =\r\n path.join(\r\n policyRoot,\r\n \"v1\"\r\n );\r\n\r\n if (fs.existsSync(policyRoot)) {\r\n throw new Error(\r\n `Policy already exists: ${policyId}`\r\n );\r\n }\r\n\r\n fs.mkdirSync(\r\n versionDirectory,\r\n {\r\n recursive: true,\r\n }\r\n );\r\n\r\n fs.writeFileSync(\r\n path.join(\r\n versionDirectory,\r\n \"policy.json\"\r\n ),\r\n\r\n JSON.stringify(\r\n {\r\n policy: policyId,\r\n version: \"v1\",\r\n },\r\n null,\r\n 2\r\n ),\r\n\r\n \"utf8\"\r\n );\r\n\r\n return versionDirectory;\r\n}\r\n\r\n\r\n\r\n\r\n","import * as path from \"node:path\";\r\n\r\nimport {\r\n generateManifest,\r\n writeManifest,\r\n} from \"@parmanasystems/bundle\";\r\n\r\nimport {\r\n signManifest,\r\n writeSignature,\r\n} from \"@parmanasystems/crypto\";\r\n\r\nimport type {\r\n BundleGenerationResult,\r\n} from \"./types.js\";\r\n\r\n/**\r\n * Generates a signed bundle for `policyId`/`policyVersion` in `policyDirectory`:\r\n * 1. Hashes all artifacts and writes `bundle.manifest.json`.\r\n * 2. Signs the manifest and writes `bundle.sig`.\r\n *\r\n * The signing key is loaded via `loadPrivateKey()` (dev-keys or env injection).\r\n *\r\n * @param policyId - Policy identifier embedded in the manifest.\r\n * @param policyVersion - Policy version string (e.g. `\"v1\"`).\r\n * @param policyDirectory - Path to the directory containing the policy artifacts.\r\n * @returns Paths to the written files and the deterministic bundle hash.\r\n */\r\nexport function generateBundle(\r\n policyId: string,\r\n policyVersion: string,\r\n policyDirectory: string\r\n): BundleGenerationResult {\r\n\r\n const directory =\r\n path.resolve(\r\n policyDirectory\r\n );\r\n\r\n const manifest =\r\n generateManifest(\r\n policyId,\r\n policyVersion,\r\n directory\r\n );\r\n\r\n writeManifest(\r\n manifest,\r\n directory\r\n );\r\n\r\n const manifestPath =\r\n path.join(\r\n directory,\r\n \"bundle.manifest.json\"\r\n );\r\n\r\n const signature =\r\n signManifest(\r\n manifestPath\r\n );\r\n\r\n writeSignature(\r\n signature,\r\n directory\r\n );\r\n\r\n return {\r\n success: true,\r\n\r\n manifest_path:\r\n manifestPath,\r\n\r\n signature_path:\r\n path.join(\r\n directory,\r\n \"bundle.sig\"\r\n ),\r\n\r\n bundle_hash:\r\n manifest.bundle_hash,\r\n };\r\n}\r\n\r\n\r\n\r\n\r\n","import * as fs from \"node:fs\";\r\nimport * as path from \"node:path\";\r\n\r\n/**\r\n * Creates the next version directory for `policyId` by copying the latest\r\n * existing version and incrementing its numeric suffix (e.g. `v1` → `v2`).\r\n * The copied `policy.json` has its `version` field updated to the new version\r\n * string.\r\n *\r\n * @param policyId - An existing policy identifier under `./policies/`.\r\n * @returns Absolute path of the newly created version directory.\r\n * @throws When the policy does not exist on disk.\r\n */\r\nexport function upgradePolicy(\r\n policyId: string\r\n): string {\r\n const policyRoot = path.join(\r\n \"./policies\",\r\n policyId\r\n );\r\n\r\n if (!fs.existsSync(policyRoot)) {\r\n throw new Error(\r\n `Policy does not exist: ${policyId}`\r\n );\r\n }\r\n\r\n const versions = fs\r\n .readdirSync(policyRoot)\r\n .filter((entry) =>\r\n entry.startsWith(\"v\")\r\n )\r\n .sort();\r\n\r\n const latestVersion =\r\n versions[\r\n versions.length - 1\r\n ];\r\n\r\n const latestNumber =\r\n Number(\r\n latestVersion.replace(\"v\", \"\")\r\n );\r\n\r\n const nextVersion =\r\n `v${latestNumber + 1}`;\r\n\r\n const latestDirectory =\r\n path.join(\r\n policyRoot,\r\n latestVersion\r\n );\r\n\r\n const nextDirectory =\r\n path.join(\r\n policyRoot,\r\n nextVersion\r\n );\r\n\r\n fs.cpSync(\r\n latestDirectory,\r\n nextDirectory,\r\n {\r\n recursive: true,\r\n }\r\n );\r\n\r\n const policyFile =\r\n path.join(\r\n nextDirectory,\r\n \"policy.json\"\r\n );\r\n\r\n const content =\r\n JSON.parse(\r\n fs.readFileSync(\r\n policyFile,\r\n \"utf8\"\r\n )\r\n );\r\n\r\n content.version =\r\n nextVersion;\r\n\r\n fs.writeFileSync(\r\n policyFile,\r\n JSON.stringify(\r\n content,\r\n null,\r\n 2\r\n ),\r\n \"utf8\"\r\n );\r\n\r\n return nextDirectory;\r\n}\r\n\r\n\r\n\r\n\r\n","import * as fs from \"node:fs\";\r\nimport * as path from \"node:path\";\r\n\r\nimport {\r\n readManifest,\r\n verifyManifest,\r\n} from \"@parmanasystems/bundle\";\r\n\r\nimport {\r\n readSignature,\r\n verifySignature,\r\n} from \"@parmanasystems/crypto\";\r\n\r\n/**\r\n * Validates every version directory under `./policies/<policyId>` by\r\n * re-verifying all bundle manifests (content hashes) and cryptographic\r\n * signatures (bundle.sig).\r\n *\r\n * Returns `true` only when every version passes all checks.\r\n *\r\n * @param policyId - Policy identifier whose version directories will be checked.\r\n * @throws When the policy directory does not exist.\r\n */\r\nexport function validatePolicy(\r\n policyId: string\r\n): boolean {\r\n\r\n const policyRoot =\r\n path.join(\r\n \"./policies\",\r\n policyId\r\n );\r\n\r\n if (\r\n !fs.existsSync(\r\n policyRoot\r\n )\r\n ) {\r\n throw new Error(\r\n `Policy does not exist: ${policyId}`\r\n );\r\n }\r\n\r\n const versions =\r\n fs\r\n .readdirSync(\r\n policyRoot\r\n )\r\n .filter(\r\n (entry) =>\r\n entry.startsWith(\"v\")\r\n )\r\n .sort();\r\n\r\n for (const version of versions) {\r\n\r\n const versionDirectory =\r\n path.join(\r\n policyRoot,\r\n version\r\n );\r\n\r\n const manifest =\r\n readManifest(\r\n versionDirectory\r\n );\r\n\r\n const manifestResult =\r\n verifyManifest(\r\n manifest,\r\n versionDirectory\r\n );\r\n\r\n if (\r\n !manifestResult.valid\r\n ) {\r\n return false;\r\n }\r\n\r\n const signature =\r\n readSignature(\r\n versionDirectory\r\n );\r\n\r\n const manifestPath =\r\n path.join(\r\n versionDirectory,\r\n \"bundle.manifest.json\"\r\n );\r\n\r\n const signatureValid =\r\n verifySignature(\r\n manifestPath,\r\n signature\r\n );\r\n\r\n if (\r\n !signatureValid\r\n ) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n}\r\n\r\n\r\n\r\n\r\n","import type {\r\n PolicyDefinition,\r\n PolicyRule,\r\n} from \"./types.js\";\r\n\r\n/**\r\n * Constructs a {@link PolicyDefinition} from a plain config object.\r\n * Use this as the first step in the policy-authoring pipeline before\r\n * serializing the policy to disk and calling {@link generateBundle}.\r\n *\r\n * @param config - Policy id, version, and rules.\r\n */\r\nexport function definePolicy(config: {\r\n id: string;\r\n version: string;\r\n rules: PolicyRule[];\r\n}): PolicyDefinition {\r\n\r\n return {\r\n id: config.id,\r\n\r\n version: config.version,\r\n\r\n rules: config.rules,\r\n };\r\n}\r\n","export const schemaV1Semantics = {\r\n\r\n schemaVersion:\r\n \"1.0.0\",\r\n\r\n ruleConditionField:\r\n \"condition\",\r\n\r\n ruleOutcomeField:\r\n \"outcome\",\r\n\r\n signalReferenceField:\r\n \"signal\",\r\n\r\n supportedOperators: [\r\n \"equals\",\r\n \"greater_than\",\r\n \"less_than\",\r\n ],\r\n};\r\n","export const schemaV1Operators = {\r\n\r\n equals(\r\n left: unknown,\r\n right: unknown\r\n ): boolean {\r\n\r\n return left === right;\r\n },\r\n\r\n greater_than(\r\n left: number,\r\n right: number\r\n ): boolean {\r\n\r\n return left > right;\r\n },\r\n\r\n less_than(\r\n left: number,\r\n right: number\r\n ): boolean {\r\n\r\n return left < right;\r\n },\r\n};\r\n","import type {\r\n DecisionResult\r\n} from \"@parmanasystems/contracts\";\r\n\r\nimport {\r\n schemaV1Operators\r\n} from \"./operators.js\";\r\n\r\ninterface BaseCondition {\r\n signal: string;\r\n equals?: unknown;\r\n greater_than?: number;\r\n less_than?: number;\r\n}\r\n\r\ninterface AllCondition {\r\n all: RuleCondition[];\r\n}\r\n\r\ninterface AnyCondition {\r\n any: RuleCondition[];\r\n}\r\n\r\ntype RuleCondition =\r\n | BaseCondition\r\n | AllCondition\r\n | AnyCondition;\r\n\r\ninterface PolicyRule {\r\n id: string;\r\n\r\n condition: RuleCondition;\r\n\r\n outcome: {\r\n action:\r\n | \"approve\"\r\n | \"reject\";\r\n\r\n requires_override:\r\n boolean;\r\n\r\n reason?: string;\r\n };\r\n}\r\n\r\nexport interface SchemaV1Policy {\r\n schemaVersion: string;\r\n\r\n signalsSchema:\r\n Record<string, unknown>;\r\n\r\n rules: PolicyRule[];\r\n}\r\n\r\nfunction evaluateCondition(\r\n condition: RuleCondition,\r\n signals: Record<string, unknown>\r\n): boolean {\r\n\r\n if (\"all\" in condition) {\r\n return condition.all.every(\r\n c =>\r\n evaluateCondition(\r\n c,\r\n signals\r\n )\r\n );\r\n }\r\n\r\n if (\"any\" in condition) {\r\n return condition.any.some(\r\n c =>\r\n evaluateCondition(\r\n c,\r\n signals\r\n )\r\n );\r\n }\r\n\r\n const {\r\n signal,\r\n equals,\r\n greater_than,\r\n less_than,\r\n } = condition;\r\n\r\n if (!(signal in signals)) {\r\n\r\n throw new Error(\r\n `Signal not found: ${signal}`\r\n );\r\n }\r\n\r\n const actual =\r\n signals[signal];\r\n\r\n if (equals !== undefined) {\r\n\r\n return schemaV1Operators.equals(\r\n actual,\r\n equals\r\n );\r\n }\r\n\r\n if (\r\n greater_than !== undefined\r\n ) {\r\n\r\n return schemaV1Operators.greater_than(\r\n actual as number,\r\n greater_than\r\n );\r\n }\r\n\r\n if (\r\n less_than !== undefined\r\n ) {\r\n\r\n return schemaV1Operators.less_than(\r\n actual as number,\r\n less_than\r\n );\r\n }\r\n\r\n return false;\r\n}\r\n\r\nexport function evaluateSchemaV1(\r\n policy: SchemaV1Policy,\r\n signals: Record<string, unknown>\r\n): DecisionResult {\r\n\r\n for (const rule of policy.rules) {\r\n\r\n const matched =\r\n evaluateCondition(\r\n rule.condition,\r\n signals\r\n );\r\n\r\n if (matched) {\r\n\r\n return {\r\n status: \"decided\",\r\n\r\n outcome:\r\n rule.outcome,\r\n\r\n rule_id:\r\n rule.id,\r\n\r\n source:\r\n \"rule_match\",\r\n };\r\n }\r\n }\r\n\r\n throw new Error(\r\n \"[SYS-006] No rule matched — policy must cover all cases\"\r\n );\r\n}\r\n","import type {\r\n DecisionResult\r\n} from \"@parmanasystems/contracts\";\r\n\r\nimport {\r\n evaluateSchemaV1\r\n} from \"./v1/evaluator.js\";\r\n\r\nimport {\r\n schemaV1Operators\r\n} from \"./v1/operators.js\";\r\n\r\nimport {\r\n schemaV1Semantics\r\n} from \"./v1/semantics.js\";\r\n\r\nexport interface SchemaRuntime {\r\n\r\n semantics: unknown;\r\n\r\n operators: unknown;\r\n\r\n evaluate: (\r\n policy: unknown,\r\n signals: Record<string, unknown>\r\n ) => DecisionResult;\r\n}\r\n\r\nexport function loadSchemaRuntime(\r\n schemaVersion: string\r\n): SchemaRuntime {\r\n\r\n const major =\r\n Number(\r\n schemaVersion.split(\".\")[0]\r\n );\r\n\r\n switch (major) {\r\n\r\n case 1:\r\n\r\n return {\r\n\r\n semantics:\r\n schemaV1Semantics,\r\n\r\n operators:\r\n schemaV1Operators,\r\n\r\n evaluate:\r\n evaluateSchemaV1 as (\r\n policy: unknown,\r\n signals: Record<string, unknown>\r\n ) => DecisionResult,\r\n };\r\n\r\n default:\r\n\r\n throw new Error(\r\n `Unsupported schema version: ${schemaVersion}`\r\n );\r\n }\r\n}\r\n"],"mappings":"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","names":["path","fs","path","fs","path"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parmanasystems/governance",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.65.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
],
|
|
19
19
|
"sideEffects": false,
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@parmanasystems/bundle": "^1.
|
|
22
|
-
"@parmanasystems/crypto": "^1.
|
|
23
|
-
"@parmanasystems/contracts": "^1.
|
|
21
|
+
"@parmanasystems/bundle": "^1.65.0",
|
|
22
|
+
"@parmanasystems/crypto": "^1.65.0",
|
|
23
|
+
"@parmanasystems/contracts": "^1.65.0"
|
|
24
24
|
},
|
|
25
25
|
"description": "Deterministic governance lifecycle and policy infrastructure for parmanasystems.",
|
|
26
26
|
"license": "Apache-2.0",
|