@parmanasystems/governance 1.0.19
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 +175 -0
- package/dist/index.d.ts +109 -0
- package/dist/index.js +222 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# @parmanasystems/governance
|
|
2
|
+
|
|
3
|
+
Policy lifecycle tooling for the parmanasystems deterministic governance runtime.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@parmanasystems/governance)
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
`@parmanasystems/governance` provides the policy management layer — creating, validating, versioning, and bundling governance policies before they enter the deterministic execution runtime.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @parmanasystems/governance
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Policy structure
|
|
18
|
+
|
|
19
|
+
Policies live at `policies/{policyId}/{version}/policy.json`:
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"schemaVersion": "1.0.0",
|
|
24
|
+
"signalsSchema": {
|
|
25
|
+
"insurance_active": { "type": "boolean", "required": true },
|
|
26
|
+
"risk_score": { "type": "integer", "required": true },
|
|
27
|
+
"claim_amount": { "type": "integer", "required": false }
|
|
28
|
+
},
|
|
29
|
+
"rules": [
|
|
30
|
+
{
|
|
31
|
+
"id": "rule_low_risk",
|
|
32
|
+
"condition": {
|
|
33
|
+
"all": [
|
|
34
|
+
{ "signal": "insurance_active", "equals": true },
|
|
35
|
+
{ "signal": "risk_score", "less_than": 50 }
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"outcome": {
|
|
39
|
+
"action": "approve",
|
|
40
|
+
"requires_override": false,
|
|
41
|
+
"reason": "Low risk profile"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"id": "rule_high_risk",
|
|
46
|
+
"condition": { "signal": "risk_score", "greater_than": 80 },
|
|
47
|
+
"outcome": {
|
|
48
|
+
"action": "reject",
|
|
49
|
+
"requires_override": false,
|
|
50
|
+
"reason": "Risk score too high"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
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
|
+
|
|
61
|
+
### `createPolicy(policyId: string): Promise<void>`
|
|
62
|
+
|
|
63
|
+
Scaffolds a new policy directory at `./policies/{policyId}/v1/policy.json`.
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { createPolicy } from "@parmanasystems/governance";
|
|
67
|
+
await createPolicy("fraud-detection");
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### `definePolicy(options): PolicyDefinition`
|
|
71
|
+
|
|
72
|
+
Builds a `PolicyDefinition` object in memory.
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { definePolicy } from "@parmanasystems/governance";
|
|
76
|
+
|
|
77
|
+
const policy = definePolicy({
|
|
78
|
+
id: "claims-approval",
|
|
79
|
+
version: "v1",
|
|
80
|
+
rules: [...],
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `validatePolicy(policy): void`
|
|
85
|
+
|
|
86
|
+
Validates policy structure. Throws on missing `schemaVersion`, invalid `signalsSchema`, missing `rules`, or malformed `outcome` fields.
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { validatePolicy } from "@parmanasystems/governance";
|
|
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>`
|
|
115
|
+
|
|
116
|
+
Verifies the `bundle.manifest.json` signature and hash integrity.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { verifyBundle } from "@parmanasystems/governance";
|
|
120
|
+
const ok = await verifyBundle("./policies/claims-approval/v1");
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Types
|
|
124
|
+
|
|
125
|
+
### PolicyDefinition
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
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
|
+
```
|
|
140
|
+
|
|
141
|
+
### BundleGenerationResult
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
interface BundleGenerationResult {
|
|
145
|
+
success: boolean;
|
|
146
|
+
manifest_path: string;
|
|
147
|
+
signature_path: string;
|
|
148
|
+
bundle_hash: string;
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### RuntimeRequirements
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
interface RuntimeRequirements {
|
|
156
|
+
required_capabilities: string[];
|
|
157
|
+
supported_runtime_versions: string[];
|
|
158
|
+
supported_schema_versions: string[];
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Included policies
|
|
163
|
+
|
|
164
|
+
The repository ships with example policies under `policies/`:
|
|
165
|
+
|
|
166
|
+
| Policy | Versions | Description |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| `claims-approval` | v1, v2 | Insurance claim approval with risk scoring |
|
|
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
|
|
174
|
+
|
|
175
|
+
Apache-2.0
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scaffolds a new policy directory at `./policies/<policyId>/v1/` and writes
|
|
3
|
+
* a skeleton `policy.json` to it.
|
|
4
|
+
*
|
|
5
|
+
* @param policyId - Unique policy identifier. Must not already exist on disk.
|
|
6
|
+
* @returns Absolute path of the created `v1` version directory.
|
|
7
|
+
* @throws When `./policies/<policyId>` already exists.
|
|
8
|
+
*/
|
|
9
|
+
declare function createPolicy(policyId: string): string;
|
|
10
|
+
|
|
11
|
+
/** Outcome of a {@link generateBundle} call. */
|
|
12
|
+
interface BundleGenerationResult {
|
|
13
|
+
/** `true` when the manifest was generated and signed successfully. */
|
|
14
|
+
success: boolean;
|
|
15
|
+
/** Absolute path of the written `bundle.manifest.json` file. */
|
|
16
|
+
manifest_path: string;
|
|
17
|
+
/** Absolute path of the written `bundle.sig` file. */
|
|
18
|
+
signature_path: string;
|
|
19
|
+
/** Deterministic bundle hash embedded in the manifest. */
|
|
20
|
+
bundle_hash: string;
|
|
21
|
+
}
|
|
22
|
+
/** A single rule within a {@link PolicyDefinition}. */
|
|
23
|
+
interface PolicyRule {
|
|
24
|
+
/** Unique rule identifier. */
|
|
25
|
+
id: string;
|
|
26
|
+
/** Condition expression that must evaluate to true for the rule to apply. */
|
|
27
|
+
condition: string;
|
|
28
|
+
/** Action to take when the condition is satisfied. */
|
|
29
|
+
action: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* An in-memory policy definition constructed by {@link definePolicy} before
|
|
33
|
+
* being serialized and passed to {@link generateBundle}.
|
|
34
|
+
*/
|
|
35
|
+
interface PolicyDefinition {
|
|
36
|
+
/** Policy identifier. */
|
|
37
|
+
id: string;
|
|
38
|
+
/** Semantic version string (e.g. `"v1"`). */
|
|
39
|
+
version: string;
|
|
40
|
+
/** Ordered list of rules that make up the policy. */
|
|
41
|
+
rules: PolicyRule[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Generates a signed bundle for `policyId`/`policyVersion` in `policyDirectory`:
|
|
46
|
+
* 1. Hashes all artifacts and writes `bundle.manifest.json`.
|
|
47
|
+
* 2. Signs the manifest and writes `bundle.sig`.
|
|
48
|
+
*
|
|
49
|
+
* The signing key is loaded via `loadPrivateKey()` (dev-keys or env injection).
|
|
50
|
+
*
|
|
51
|
+
* @param policyId - Policy identifier embedded in the manifest.
|
|
52
|
+
* @param policyVersion - Policy version string (e.g. `"v1"`).
|
|
53
|
+
* @param policyDirectory - Path to the directory containing the policy artifacts.
|
|
54
|
+
* @returns Paths to the written files and the deterministic bundle hash.
|
|
55
|
+
*/
|
|
56
|
+
declare function generateBundle(policyId: string, policyVersion: string, policyDirectory: string): BundleGenerationResult;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Creates the next version directory for `policyId` by copying the latest
|
|
60
|
+
* existing version and incrementing its numeric suffix (e.g. `v1` → `v2`).
|
|
61
|
+
* The copied `policy.json` has its `version` field updated to the new version
|
|
62
|
+
* string.
|
|
63
|
+
*
|
|
64
|
+
* @param policyId - An existing policy identifier under `./policies/`.
|
|
65
|
+
* @returns Absolute path of the newly created version directory.
|
|
66
|
+
* @throws When the policy does not exist on disk.
|
|
67
|
+
*/
|
|
68
|
+
declare function upgradePolicy(policyId: string): string;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Validates every version directory under `./policies/<policyId>` by
|
|
72
|
+
* re-verifying all bundle manifests (content hashes) and cryptographic
|
|
73
|
+
* signatures (bundle.sig).
|
|
74
|
+
*
|
|
75
|
+
* Returns `true` only when every version passes all checks.
|
|
76
|
+
*
|
|
77
|
+
* @param policyId - Policy identifier whose version directories will be checked.
|
|
78
|
+
* @throws When the policy directory does not exist.
|
|
79
|
+
*/
|
|
80
|
+
declare function validatePolicy(policyId: string): boolean;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Capability and version constraints that a runtime must satisfy before it is
|
|
84
|
+
* permitted to execute a bundle. Stored inside every {@link BundleManifest}
|
|
85
|
+
* and re-validated at execution time.
|
|
86
|
+
*/
|
|
87
|
+
interface RuntimeRequirements {
|
|
88
|
+
/** Runtime capability strings that must appear in the executing runtime's capability list. */
|
|
89
|
+
required_capabilities: string[];
|
|
90
|
+
/** Runtime version strings (e.g. `"1.0.0"`) acceptable to this bundle. */
|
|
91
|
+
supported_runtime_versions: string[];
|
|
92
|
+
/** Schema version strings (e.g. `"1.0.0"`) that this bundle's artifacts conform to. */
|
|
93
|
+
supported_schema_versions: string[];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Constructs a {@link PolicyDefinition} from a plain config object.
|
|
98
|
+
* Use this as the first step in the policy-authoring pipeline before
|
|
99
|
+
* serializing the policy to disk and calling {@link generateBundle}.
|
|
100
|
+
*
|
|
101
|
+
* @param config - Policy id, version, and rules.
|
|
102
|
+
*/
|
|
103
|
+
declare function definePolicy(config: {
|
|
104
|
+
id: string;
|
|
105
|
+
version: string;
|
|
106
|
+
rules: PolicyRule[];
|
|
107
|
+
}): PolicyDefinition;
|
|
108
|
+
|
|
109
|
+
export { type BundleGenerationResult, type PolicyDefinition, type PolicyRule, type RuntimeRequirements, createPolicy, definePolicy, generateBundle, upgradePolicy, validatePolicy };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
// src/create-policy.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
function createPolicy(policyId) {
|
|
5
|
+
const policyRoot = path.join(
|
|
6
|
+
"./policies",
|
|
7
|
+
policyId
|
|
8
|
+
);
|
|
9
|
+
const versionDirectory = path.join(
|
|
10
|
+
policyRoot,
|
|
11
|
+
"v1"
|
|
12
|
+
);
|
|
13
|
+
if (fs.existsSync(policyRoot)) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
`Policy already exists: ${policyId}`
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
fs.mkdirSync(
|
|
19
|
+
versionDirectory,
|
|
20
|
+
{
|
|
21
|
+
recursive: true
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
fs.writeFileSync(
|
|
25
|
+
path.join(
|
|
26
|
+
versionDirectory,
|
|
27
|
+
"policy.json"
|
|
28
|
+
),
|
|
29
|
+
JSON.stringify(
|
|
30
|
+
{
|
|
31
|
+
policy: policyId,
|
|
32
|
+
version: "v1"
|
|
33
|
+
},
|
|
34
|
+
null,
|
|
35
|
+
2
|
|
36
|
+
),
|
|
37
|
+
"utf8"
|
|
38
|
+
);
|
|
39
|
+
return versionDirectory;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/generate-bundle.ts
|
|
43
|
+
import path2 from "path";
|
|
44
|
+
import {
|
|
45
|
+
generateManifest,
|
|
46
|
+
writeManifest
|
|
47
|
+
} from "@parmanasystems/bundle";
|
|
48
|
+
import {
|
|
49
|
+
signManifest,
|
|
50
|
+
writeSignature
|
|
51
|
+
} from "@parmanasystems/crypto";
|
|
52
|
+
function generateBundle(policyId, policyVersion, policyDirectory) {
|
|
53
|
+
const directory = path2.resolve(
|
|
54
|
+
policyDirectory
|
|
55
|
+
);
|
|
56
|
+
const manifest = generateManifest(
|
|
57
|
+
policyId,
|
|
58
|
+
policyVersion,
|
|
59
|
+
directory
|
|
60
|
+
);
|
|
61
|
+
writeManifest(
|
|
62
|
+
manifest,
|
|
63
|
+
directory
|
|
64
|
+
);
|
|
65
|
+
const manifestPath = path2.join(
|
|
66
|
+
directory,
|
|
67
|
+
"bundle.manifest.json"
|
|
68
|
+
);
|
|
69
|
+
const signature = signManifest(
|
|
70
|
+
manifestPath
|
|
71
|
+
);
|
|
72
|
+
writeSignature(
|
|
73
|
+
signature,
|
|
74
|
+
directory
|
|
75
|
+
);
|
|
76
|
+
return {
|
|
77
|
+
success: true,
|
|
78
|
+
manifest_path: manifestPath,
|
|
79
|
+
signature_path: path2.join(
|
|
80
|
+
directory,
|
|
81
|
+
"bundle.sig"
|
|
82
|
+
),
|
|
83
|
+
bundle_hash: manifest.bundle_hash
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/upgrade-policy.ts
|
|
88
|
+
import fs2 from "fs";
|
|
89
|
+
import path3 from "path";
|
|
90
|
+
function upgradePolicy(policyId) {
|
|
91
|
+
const policyRoot = path3.join(
|
|
92
|
+
"./policies",
|
|
93
|
+
policyId
|
|
94
|
+
);
|
|
95
|
+
if (!fs2.existsSync(policyRoot)) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
`Policy does not exist: ${policyId}`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
const versions = fs2.readdirSync(policyRoot).filter(
|
|
101
|
+
(entry) => entry.startsWith("v")
|
|
102
|
+
).sort();
|
|
103
|
+
const latestVersion = versions[versions.length - 1];
|
|
104
|
+
const latestNumber = Number(
|
|
105
|
+
latestVersion.replace("v", "")
|
|
106
|
+
);
|
|
107
|
+
const nextVersion = `v${latestNumber + 1}`;
|
|
108
|
+
const latestDirectory = path3.join(
|
|
109
|
+
policyRoot,
|
|
110
|
+
latestVersion
|
|
111
|
+
);
|
|
112
|
+
const nextDirectory = path3.join(
|
|
113
|
+
policyRoot,
|
|
114
|
+
nextVersion
|
|
115
|
+
);
|
|
116
|
+
fs2.cpSync(
|
|
117
|
+
latestDirectory,
|
|
118
|
+
nextDirectory,
|
|
119
|
+
{
|
|
120
|
+
recursive: true
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
const policyFile = path3.join(
|
|
124
|
+
nextDirectory,
|
|
125
|
+
"policy.json"
|
|
126
|
+
);
|
|
127
|
+
const content = JSON.parse(
|
|
128
|
+
fs2.readFileSync(
|
|
129
|
+
policyFile,
|
|
130
|
+
"utf8"
|
|
131
|
+
)
|
|
132
|
+
);
|
|
133
|
+
content.version = nextVersion;
|
|
134
|
+
fs2.writeFileSync(
|
|
135
|
+
policyFile,
|
|
136
|
+
JSON.stringify(
|
|
137
|
+
content,
|
|
138
|
+
null,
|
|
139
|
+
2
|
|
140
|
+
),
|
|
141
|
+
"utf8"
|
|
142
|
+
);
|
|
143
|
+
return nextDirectory;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// src/validate-policy.ts
|
|
147
|
+
import fs3 from "fs";
|
|
148
|
+
import path4 from "path";
|
|
149
|
+
import {
|
|
150
|
+
readManifest,
|
|
151
|
+
verifyManifest
|
|
152
|
+
} from "@parmanasystems/bundle";
|
|
153
|
+
import {
|
|
154
|
+
readSignature,
|
|
155
|
+
verifySignature
|
|
156
|
+
} from "@parmanasystems/crypto";
|
|
157
|
+
function validatePolicy(policyId) {
|
|
158
|
+
const policyRoot = path4.join(
|
|
159
|
+
"./policies",
|
|
160
|
+
policyId
|
|
161
|
+
);
|
|
162
|
+
if (!fs3.existsSync(
|
|
163
|
+
policyRoot
|
|
164
|
+
)) {
|
|
165
|
+
throw new Error(
|
|
166
|
+
`Policy does not exist: ${policyId}`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
const versions = fs3.readdirSync(
|
|
170
|
+
policyRoot
|
|
171
|
+
).filter(
|
|
172
|
+
(entry) => entry.startsWith("v")
|
|
173
|
+
).sort();
|
|
174
|
+
for (const version of versions) {
|
|
175
|
+
const versionDirectory = path4.join(
|
|
176
|
+
policyRoot,
|
|
177
|
+
version
|
|
178
|
+
);
|
|
179
|
+
const manifest = readManifest(
|
|
180
|
+
versionDirectory
|
|
181
|
+
);
|
|
182
|
+
const manifestResult = verifyManifest(
|
|
183
|
+
manifest,
|
|
184
|
+
versionDirectory
|
|
185
|
+
);
|
|
186
|
+
if (!manifestResult.valid) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
const signature = readSignature(
|
|
190
|
+
versionDirectory
|
|
191
|
+
);
|
|
192
|
+
const manifestPath = path4.join(
|
|
193
|
+
versionDirectory,
|
|
194
|
+
"bundle.manifest.json"
|
|
195
|
+
);
|
|
196
|
+
const signatureValid = verifySignature(
|
|
197
|
+
manifestPath,
|
|
198
|
+
signature
|
|
199
|
+
);
|
|
200
|
+
if (!signatureValid) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// src/define-policy.ts
|
|
208
|
+
function definePolicy(config) {
|
|
209
|
+
return {
|
|
210
|
+
id: config.id,
|
|
211
|
+
version: config.version,
|
|
212
|
+
rules: config.rules
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
export {
|
|
216
|
+
createPolicy,
|
|
217
|
+
definePolicy,
|
|
218
|
+
generateBundle,
|
|
219
|
+
upgradePolicy,
|
|
220
|
+
validatePolicy
|
|
221
|
+
};
|
|
222
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\n\n/**\n * Scaffolds a new policy directory at `./policies/<policyId>/v1/` and writes\n * a skeleton `policy.json` to it.\n *\n * @param policyId - Unique policy identifier. Must not already exist on disk.\n * @returns Absolute path of the created `v1` version directory.\n * @throws When `./policies/<policyId>` already exists.\n */\nexport function createPolicy(\n policyId: string\n): string {\n const policyRoot = path.join(\n \"./policies\",\n policyId\n );\n\n const versionDirectory =\n path.join(\n policyRoot,\n \"v1\"\n );\n\n if (fs.existsSync(policyRoot)) {\n throw new Error(\n `Policy already exists: ${policyId}`\n );\n }\n\n fs.mkdirSync(\n versionDirectory,\n {\n recursive: true,\n }\n );\n\n fs.writeFileSync(\n path.join(\n versionDirectory,\n \"policy.json\"\n ),\n\n JSON.stringify(\n {\n policy: policyId,\n version: \"v1\",\n },\n null,\n 2\n ),\n\n \"utf8\"\n );\n\n return versionDirectory;\n}\n\n\n\n\n","import path from \"path\";\n\nimport {\n generateManifest,\n writeManifest,\n} from \"@parmanasystems/bundle\";\n\nimport {\n signManifest,\n writeSignature,\n} from \"@parmanasystems/crypto\";\n\nimport type {\n BundleGenerationResult,\n} from \"./types\";\n\n/**\n * Generates a signed bundle for `policyId`/`policyVersion` in `policyDirectory`:\n * 1. Hashes all artifacts and writes `bundle.manifest.json`.\n * 2. Signs the manifest and writes `bundle.sig`.\n *\n * The signing key is loaded via `loadPrivateKey()` (dev-keys or env injection).\n *\n * @param policyId - Policy identifier embedded in the manifest.\n * @param policyVersion - Policy version string (e.g. `\"v1\"`).\n * @param policyDirectory - Path to the directory containing the policy artifacts.\n * @returns Paths to the written files and the deterministic bundle hash.\n */\nexport function generateBundle(\n policyId: string,\n policyVersion: string,\n policyDirectory: string\n): BundleGenerationResult {\n\n const directory =\n path.resolve(\n policyDirectory\n );\n\n const manifest =\n generateManifest(\n policyId,\n policyVersion,\n directory\n );\n\n writeManifest(\n manifest,\n directory\n );\n\n const manifestPath =\n path.join(\n directory,\n \"bundle.manifest.json\"\n );\n\n const signature =\n signManifest(\n manifestPath\n );\n\n writeSignature(\n signature,\n directory\n );\n\n return {\n success: true,\n\n manifest_path:\n manifestPath,\n\n signature_path:\n path.join(\n directory,\n \"bundle.sig\"\n ),\n\n bundle_hash:\n manifest.bundle_hash,\n };\n}\n\n\n\n\n","import fs from \"fs\";\nimport path from \"path\";\n\n/**\n * Creates the next version directory for `policyId` by copying the latest\n * existing version and incrementing its numeric suffix (e.g. `v1` → `v2`).\n * The copied `policy.json` has its `version` field updated to the new version\n * string.\n *\n * @param policyId - An existing policy identifier under `./policies/`.\n * @returns Absolute path of the newly created version directory.\n * @throws When the policy does not exist on disk.\n */\nexport function upgradePolicy(\n policyId: string\n): string {\n const policyRoot = path.join(\n \"./policies\",\n policyId\n );\n\n if (!fs.existsSync(policyRoot)) {\n throw new Error(\n `Policy does not exist: ${policyId}`\n );\n }\n\n const versions = fs\n .readdirSync(policyRoot)\n .filter((entry) =>\n entry.startsWith(\"v\")\n )\n .sort();\n\n const latestVersion =\n versions[\n versions.length - 1\n ];\n\n const latestNumber =\n Number(\n latestVersion.replace(\"v\", \"\")\n );\n\n const nextVersion =\n `v${latestNumber + 1}`;\n\n const latestDirectory =\n path.join(\n policyRoot,\n latestVersion\n );\n\n const nextDirectory =\n path.join(\n policyRoot,\n nextVersion\n );\n\n fs.cpSync(\n latestDirectory,\n nextDirectory,\n {\n recursive: true,\n }\n );\n\n const policyFile =\n path.join(\n nextDirectory,\n \"policy.json\"\n );\n\n const content =\n JSON.parse(\n fs.readFileSync(\n policyFile,\n \"utf8\"\n )\n );\n\n content.version =\n nextVersion;\n\n fs.writeFileSync(\n policyFile,\n JSON.stringify(\n content,\n null,\n 2\n ),\n \"utf8\"\n );\n\n return nextDirectory;\n}\n\n\n\n\n","import fs from \"fs\";\nimport path from \"path\";\n\nimport {\n readManifest,\n verifyManifest,\n} from \"@parmanasystems/bundle\";\n\nimport {\n readSignature,\n verifySignature,\n} from \"@parmanasystems/crypto\";\n\n/**\n * Validates every version directory under `./policies/<policyId>` by\n * re-verifying all bundle manifests (content hashes) and cryptographic\n * signatures (bundle.sig).\n *\n * Returns `true` only when every version passes all checks.\n *\n * @param policyId - Policy identifier whose version directories will be checked.\n * @throws When the policy directory does not exist.\n */\nexport function validatePolicy(\n policyId: string\n): boolean {\n\n const policyRoot =\n path.join(\n \"./policies\",\n policyId\n );\n\n if (\n !fs.existsSync(\n policyRoot\n )\n ) {\n throw new Error(\n `Policy does not exist: ${policyId}`\n );\n }\n\n const versions =\n fs\n .readdirSync(\n policyRoot\n )\n .filter(\n (entry) =>\n entry.startsWith(\"v\")\n )\n .sort();\n\n for (const version of versions) {\n\n const versionDirectory =\n path.join(\n policyRoot,\n version\n );\n\n const manifest =\n readManifest(\n versionDirectory\n );\n\n const manifestResult =\n verifyManifest(\n manifest,\n versionDirectory\n );\n\n if (\n !manifestResult.valid\n ) {\n return false;\n }\n\n const signature =\n readSignature(\n versionDirectory\n );\n\n const manifestPath =\n path.join(\n versionDirectory,\n \"bundle.manifest.json\"\n );\n\n const signatureValid =\n verifySignature(\n manifestPath,\n signature\n );\n\n if (\n !signatureValid\n ) {\n return false;\n }\n }\n\n return true;\n}\n\n\n\n\n","import type {\n PolicyDefinition,\n PolicyRule,\n} from \"./types\";\n\n/**\n * Constructs a {@link PolicyDefinition} from a plain config object.\n * Use this as the first step in the policy-authoring pipeline before\n * serializing the policy to disk and calling {@link generateBundle}.\n *\n * @param config - Policy id, version, and rules.\n */\nexport function definePolicy(config: {\n id: string;\n version: string;\n rules: PolicyRule[];\n}): PolicyDefinition {\n\n return {\n id: config.id,\n\n version: config.version,\n\n rules: config.rules,\n };\n}\n"],"mappings":"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","names":["path","fs","path","fs","path"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@parmanasystems/governance",
|
|
3
|
+
"version": "1.0.19",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsup"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@parmanasystems/bundle": "^1.0.19",
|
|
22
|
+
"@parmanasystems/crypto": "^1.0.19"
|
|
23
|
+
},
|
|
24
|
+
"description": "Deterministic governance lifecycle and policy infrastructure for parmanasystems.",
|
|
25
|
+
"license": "Apache-2.0",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/pavancharak/parmanasystems-core.git"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/pavancharak/parmanasystems-core",
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/pavancharak/parmanasystems-core/issues"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=20"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"governance",
|
|
39
|
+
"policy",
|
|
40
|
+
"deterministic",
|
|
41
|
+
"compliance",
|
|
42
|
+
"runtime",
|
|
43
|
+
"workflow"
|
|
44
|
+
],
|
|
45
|
+
"main": "./dist/index.js",
|
|
46
|
+
"types": "./dist/index.d.ts"
|
|
47
|
+
}
|