@parmana/verifier 2.0.1 → 2.0.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/LICENSE +202 -202
- package/NOTICE +1 -1
- package/README.md +263 -241
- package/bin/parmana-verify.mjs +55 -53
- package/package.json +40 -40
- package/src/canonical.mjs +35 -35
- package/src/correspondence.mjs +138 -0
- package/src/timestamp.mjs +65 -65
- package/src/trust.mjs +121 -121
- package/src/verify.mjs +343 -343
package/README.md
CHANGED
|
@@ -1,241 +1,263 @@
|
|
|
1
|
-
# Parmana Verifier
|
|
2
|
-
|
|
3
|
-
[](https://github.com/pavancharak/parmana-verifier/actions/workflows/ci.yml) [](LICENSE) [](package.json)
|
|
4
|
-
|
|
5
|
-
**Parmana makes sure AI agents take only the actions your business has approved, and keeps signed proof of what they did.** This verifier checks that proof using only a record file and the keys you trust. It needs no network access, no account and no dependencies.
|
|
6
|
-
|
|
7
|
-
Parmana signs an **Execution Trust Record** for every action an agent takes through it. The record says what was authorized, what ran, and what the outcome was. This verifier checks that a record has not been changed and that it was signed by keys you chose to trust. It does not contact Parmana's servers, so you do not have to trust them to check a record.
|
|
8
|
-
|
|
9
|
-
The records come from [Parmana](https://github.com/pavancharak/parmana-core), which signs them. The verifier works without the rest of Parmana: it needs only a record and a trust file.
|
|
10
|
-
|
|
11
|
-
Test results, the security review scope and the changelog are indexed under [Reports and evidence](#reports-and-evidence).
|
|
12
|
-
|
|
13
|
-
## Who it is for
|
|
14
|
-
|
|
15
|
-
- **Auditors and reviewers** who need to confirm a record without relying on the system that produced it.
|
|
16
|
-
- **Operators** who want to check records in their own environment, with keys they pinned themselves.
|
|
17
|
-
- **Developers** who want a small, dependency-free reference implementation of the record checks.
|
|
18
|
-
|
|
19
|
-
## Quick start
|
|
20
|
-
|
|
21
|
-
Requires Node.js 24 or later. Ed25519 works on any Node 24 build; post-quantum ML-DSA-65 signatures need OpenSSL 3.5 or later. From a clone of this repository:
|
|
22
|
-
|
|
23
|
-
```sh
|
|
24
|
-
node bin/parmana-verify.mjs test/vectors/record-whole-record-v3.json test/vectors/trust-whole-record.json
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
```json
|
|
28
|
-
{
|
|
29
|
-
"valid": true,
|
|
30
|
-
"coverage": "full",
|
|
31
|
-
"errors": [],
|
|
32
|
-
"checks": {
|
|
33
|
-
"trustRecordHash": true,
|
|
34
|
-
"signature": true,
|
|
35
|
-
"hybridSignatures": true
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
The exit code is `
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
```sh
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
parmana-verify
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
"
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
-
|
|
119
|
-
- the
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
-
|
|
148
|
-
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
-
|
|
169
|
-
-
|
|
170
|
-
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
-
|
|
192
|
-
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
-
|
|
197
|
-
-
|
|
198
|
-
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
- **
|
|
207
|
-
- **
|
|
208
|
-
- **
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
1
|
+
# Parmana Verifier
|
|
2
|
+
|
|
3
|
+
[](https://github.com/pavancharak/parmana-verifier/actions/workflows/ci.yml) [](LICENSE) [](package.json)
|
|
4
|
+
|
|
5
|
+
**Parmana makes sure AI agents take only the actions your business has approved, and keeps signed proof of what they did.** This verifier checks that proof using only a record file and the keys you trust. It needs no network access, no account and no dependencies.
|
|
6
|
+
|
|
7
|
+
Parmana signs an **Execution Trust Record** for every action an agent takes through it. The record says what was authorized, what ran, and what the outcome was. This verifier checks that a record has not been changed and that it was signed by keys you chose to trust. It does not contact Parmana's servers, so you do not have to trust them to check a record.
|
|
8
|
+
|
|
9
|
+
The records come from [Parmana](https://github.com/pavancharak/parmana-core), which signs them. The verifier works without the rest of Parmana: it needs only a record and a trust file.
|
|
10
|
+
|
|
11
|
+
Test results, the security review scope and the changelog are indexed under [Reports and evidence](#reports-and-evidence).
|
|
12
|
+
|
|
13
|
+
## Who it is for
|
|
14
|
+
|
|
15
|
+
- **Auditors and reviewers** who need to confirm a record without relying on the system that produced it.
|
|
16
|
+
- **Operators** who want to check records in their own environment, with keys they pinned themselves.
|
|
17
|
+
- **Developers** who want a small, dependency-free reference implementation of the record checks.
|
|
18
|
+
|
|
19
|
+
## Quick start
|
|
20
|
+
|
|
21
|
+
Requires Node.js 24 or later. Ed25519 works on any Node 24 build; post-quantum ML-DSA-65 signatures need OpenSSL 3.5 or later. From a clone of this repository:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
node bin/parmana-verify.mjs test/vectors/record-whole-record-v3.json test/vectors/trust-whole-record.json
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"valid": true,
|
|
30
|
+
"coverage": "full",
|
|
31
|
+
"errors": [],
|
|
32
|
+
"checks": {
|
|
33
|
+
"trustRecordHash": true,
|
|
34
|
+
"signature": true,
|
|
35
|
+
"hybridSignatures": true
|
|
36
|
+
},
|
|
37
|
+
"correspondence": {
|
|
38
|
+
"status": "not_checked",
|
|
39
|
+
"executions": [
|
|
40
|
+
{ "executionId": "ex_1", "result": { "status": "not_checked", "reason": "no authorization is embedded in the trust record" } }
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The exit code is `0`. The `correspondence` field is a separate report, described in [Execution correspondence](#execution-correspondence). It does not change `valid` or the exit code. This sample record is a trimmed test vector that does not embed its authorization, so there is nothing to compare and its correspondence is reported as `not_checked`, not as a mismatch. A complete record from Parmana embeds the authorization and is checked. A record that has been changed is rejected:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
node bin/parmana-verify.mjs test/vectors/record-tampered-amount.json test/vectors/trust.json
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The exit code is `1`, and the output lists the failed checks. The test vectors are labelled test material; see [test/vectors/README.md](test/vectors/README.md). For real records, pin the keys you trust (see [Pinning a key](#pinning-a-key)).
|
|
53
|
+
|
|
54
|
+
On Windows PowerShell, run the same two commands with Windows paths. Use Node 24 or later:
|
|
55
|
+
|
|
56
|
+
```powershell
|
|
57
|
+
node bin\parmana-verify.mjs test\vectors\record-whole-record-v3.json test\vectors\trust-whole-record.json
|
|
58
|
+
node bin\parmana-verify.mjs test\vectors\record-tampered-amount.json test\vectors\trust.json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The first prints the valid result above and exits with `0`. The second prints `"valid":false` and exits with `1`.
|
|
62
|
+
|
|
63
|
+
## Installation and usage
|
|
64
|
+
|
|
65
|
+
The package is published on npm as [`@parmana/verifier`](https://www.npmjs.com/package/@parmana/verifier). Install it, or run it without installing:
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
npm install -g @parmana/verifier
|
|
69
|
+
parmana-verify <proof.json> <trust.json>
|
|
70
|
+
parmana-verify key-fingerprint <public-key.pem>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
npx @parmana/verifier <proof.json> <trust.json>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
From a clone of this repository, run the same commands with `node bin/parmana-verify.mjs` in place of `parmana-verify`.
|
|
78
|
+
|
|
79
|
+
There is also a Python version in [`python/`](python/README.md). It checks the same records and gives the same results, including ML-DSA-65 (hybrid) signatures when `cryptography` 48.0.0 or later is installed.
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
pip install parmana-verifier
|
|
83
|
+
parmana-verify <proof.json> <trust.json>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- `proof.json` is the Execution Trust Record.
|
|
87
|
+
- `trust.json` is the trust set. It lists each key you accept:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"keys": [
|
|
92
|
+
{
|
|
93
|
+
"keyId": "default",
|
|
94
|
+
"algorithm": "ed25519",
|
|
95
|
+
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n",
|
|
96
|
+
"fingerprint": "sha256:<64 hex digits>",
|
|
97
|
+
"validFrom": "2026-01-01T00:00:00.000Z",
|
|
98
|
+
"validUntil": null,
|
|
99
|
+
"compromised": false
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
- `key-fingerprint` prints the `sha256:` value to pin for a PEM key. To pin a key safely, follow the steps in [Pinning a key](#pinning-a-key).
|
|
106
|
+
|
|
107
|
+
The verify command prints one line of JSON and exits with `0` (valid), `1` (invalid, with reasons), or `2` (usage, missing file, or invalid JSON). The full input and output rules are in [docs/FORMAT.md](docs/FORMAT.md).
|
|
108
|
+
|
|
109
|
+
On Windows PowerShell, use the same commands with Windows paths, for example `node bin\parmana-verify.mjs proof.json trust.json`.
|
|
110
|
+
|
|
111
|
+
## Execution correspondence
|
|
112
|
+
|
|
113
|
+
The output also carries a `correspondence` report: whether what was dispatched is what was authorized. It is checked from the record alone, the same way as the signatures, and it uses the same rules as Parmana's own offline check.
|
|
114
|
+
|
|
115
|
+
For each execution, the record's authorization (its nonce, business transaction hash, policy content hash and authority grant) is compared with the execution's `evidence.correspondence`. Every field must be present and must match, and the dispatched content hash must equal the authorized one. The statuses are:
|
|
116
|
+
|
|
117
|
+
- `passed`: every field is present and matches the authorization.
|
|
118
|
+
- `failed`: a field is missing or different. This is a mismatch that was observed.
|
|
119
|
+
- `not_checked`: the execution has no correspondence fields, no evidence, or the record embeds no authorization to compare with. Nothing was compared, so this is not a mismatch. It is never reported as passed.
|
|
120
|
+
|
|
121
|
+
The report is `passed` only when every execution is checked and corresponds. The verifier reports it and does not decide what it means for your system: a `failed` or `not_checked` report is for you to act on. It is meaningful only for a record whose signatures also verify, so read it together with `valid`.
|
|
122
|
+
|
|
123
|
+
## Pinning a key
|
|
124
|
+
|
|
125
|
+
A signature proves only that a key made it. Before you trust a record, decide which keys you trust, and check that each key is the one its owner published.
|
|
126
|
+
|
|
127
|
+
1. Get the operator's public key PEM and the `sha256:` fingerprint they published. Get the fingerprint from a source other than the one that gave you the key, such as a signed message or a call to a known number.
|
|
128
|
+
2. Run `node bin/parmana-verify.mjs key-fingerprint public-key.pem` on the PEM you received.
|
|
129
|
+
3. Compare the two fingerprints character by character. If they differ, do not use the key.
|
|
130
|
+
4. Only then add the key to your trust file with that fingerprint.
|
|
131
|
+
|
|
132
|
+
## Trust rules
|
|
133
|
+
|
|
134
|
+
A key is used only if all of these hold:
|
|
135
|
+
|
|
136
|
+
- its PEM hashes to the pinned fingerprint (SHA-256 of the SPKI DER encoding);
|
|
137
|
+
- the algorithm named by the signature matches the algorithm in the trust file;
|
|
138
|
+
- it is not marked `compromised`;
|
|
139
|
+
- the record's `createdAt` is at or after `validFrom` and before `validUntil` (if set).
|
|
140
|
+
|
|
141
|
+
A compromised key is rejected whatever the timestamp, so signatures it made stay void.
|
|
142
|
+
|
|
143
|
+
### Records with no hybrid envelope
|
|
144
|
+
|
|
145
|
+
A record with no `signatures` array is a legacy-only record. The verifier refuses it by default. It is accepted only when:
|
|
146
|
+
|
|
147
|
+
- the trust file sets `hybridRequiredFrom` and the record was created before that instant; or
|
|
148
|
+
- the trust file sets `"allowLegacyOnly": true` and does not set `hybridRequiredFrom`.
|
|
149
|
+
|
|
150
|
+
Otherwise the result is invalid, and the error says which setting would accept it. A record with no `schemaVersion`, or with `schemaVersion` 2, is refused unless the trust file sets `"allowLegacyV2": true`, because it signs only seven top-level fields. A record created at or after `hybridRequiredFrom` always needs a valid hybrid envelope, whatever `allowLegacyOnly` says. See [docs/FORMAT.md](docs/FORMAT.md#trust-set-trustjson).
|
|
151
|
+
|
|
152
|
+
## Examples
|
|
153
|
+
|
|
154
|
+
Run every example with:
|
|
155
|
+
|
|
156
|
+
```sh
|
|
157
|
+
npm run examples
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The examples are in `examples/`, and each one prints what it checks:
|
|
161
|
+
|
|
162
|
+
- `01-verify-a-proof.mjs`: verify a record and explain each check.
|
|
163
|
+
- `02-tamper-detection.mjs`: change a signed field, then show that recomputing the hash does not help an attacker.
|
|
164
|
+
- `03-pinned-keys-and-windows.mjs`: how pinned fingerprints, validity windows and compromised keys decide what is accepted.
|
|
165
|
+
- `04-hybrid-envelope.mjs`: the Ed25519 and ML-DSA-65 entries of a hybrid record (needs Node 24).
|
|
166
|
+
- `05-build-and-verify-a-record.mjs`: build, hash, sign, pin and verify a record from scratch, with a runtime test key.
|
|
167
|
+
- `06-command-line.mjs`: the command-line exit codes, and fingerprinting a key for pinning.
|
|
168
|
+
- `07-whole-record-coverage.mjs`: what coverage `full` and `legacy` mean, and that a changed covered field is refused.
|
|
169
|
+
- `08-hybrid-cutover.mjs`: the `hybridRequiredFrom` cutover, and what it adds to a record created after it.
|
|
170
|
+
- `09-unsupported-schema-version.mjs`: a schema version other than 2 or 3 is refused, not guessed at.
|
|
171
|
+
|
|
172
|
+
Each example exits `0` when it behaves as described, so the set runs in CI.
|
|
173
|
+
|
|
174
|
+
## Testing
|
|
175
|
+
|
|
176
|
+
```sh
|
|
177
|
+
npm test
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Run the tests on Node 24. On Node 22 or any runtime without ML-DSA-65, the hybrid tests are skipped. Test keys are generated at run time, labelled "TEST KEY - NOT FOR PRODUCTION", and never written to disk.
|
|
181
|
+
|
|
182
|
+
The suite covers the legacy signature and hash, hybrid signatures, schema version 3 coverage, the trust rules, the test vectors, and the command-line exit codes. Each area has its own file under `test/`.
|
|
183
|
+
|
|
184
|
+
Records from parmana-core are tested in `test/parmana-core-records.test.mjs` and `python/tests/test_parmana_core_records.py`. They use `test/vectors/parmana-core-generated/cases.json`: 22 cases over records exported at parmana-core `7e9a54fb`, with tampered copies and trust-file edits. Both verifiers must agree on every case. The quick-start record in `python/README.md` is tested in `test/quickstart.test.mjs` and `python/tests/test_quickstart.py`.
|
|
185
|
+
|
|
186
|
+
## Limitations
|
|
187
|
+
|
|
188
|
+
- The verifier can only check that a record was signed by the key you pinned. It cannot prove that the key belongs to Parmana. That depends on how you obtained and compared the fingerprint.
|
|
189
|
+
- For records with `schemaVersion` 2, or with no `schemaVersion`, only the fields listed in [docs/FORMAT.md](docs/FORMAT.md) are protected. Any other field can be changed without the verifier noticing. Read decisions only from covered fields. See "Fields not covered by any signature" in that document.
|
|
190
|
+
- For records with `schemaVersion` 3, every field except the signature envelope, `verifications` and `receipts` is protected.
|
|
191
|
+
- `coverage` is `full` only when the hybrid signatures also verify. It does not report the schema version. A schema version 3 record that fails the hybrid check reports `legacy`, and an Ed25519-only failure can report `full` alongside `valid: false`. Read `valid` for the verdict.
|
|
192
|
+
- `checks.signature` is the legacy top-level signature, which covers only the seven legacy fields. A change to `updatedAt` in a schema version 3 record is caught by the hybrid signatures alone, so `checks.signature` stays `true` (pinned by `test/parmana-core-records.test.mjs`).
|
|
193
|
+
- A record with `schemaVersion` 2 can be downgraded by someone who can write to storage, since `schemaVersion` is unsigned. Set `hybridRequiredFrom` in the trust file to reject downgraded records created after a cutover. Records before the cutover stay open to this. With no cutover set, a record with no hybrid envelope is refused unless the trust file sets `allowLegacyOnly` to `true` (see "Records with no hybrid envelope" above).
|
|
194
|
+
- The validity window is checked against the record's `createdAt`, not against the signing time. A record that carries a false `createdAt` is checked against the window for that false time.
|
|
195
|
+
- Keys and fingerprints must be kept current. The verifier does not know about rotations or revocations that you have not written into the trust file.
|
|
196
|
+
- It does not verify the policy the record cites, the authorization decision logic, or the state of any connector or external system.
|
|
197
|
+
- It does not confirm that the action described by the record was executed.
|
|
198
|
+
- The records in `test/vectors/` were produced by the Parmana signing code and are test material only. They show that the checks agree with that code; they are not an independent specification.
|
|
199
|
+
|
|
200
|
+
## Reports and evidence
|
|
201
|
+
|
|
202
|
+
Every report is listed once, here. Start with the question you have.
|
|
203
|
+
|
|
204
|
+
**Test results**
|
|
205
|
+
|
|
206
|
+
- **Live CI runs:** the [CI workflow](https://github.com/pavancharak/parmana-verifier/actions/workflows/ci.yml) runs the tests and examples on every push. The [Python workflow](https://github.com/pavancharak/parmana-verifier/actions/workflows/python.yml) runs the Python package tests.
|
|
207
|
+
- **Test suite:** what it covers, and how to run it on Node 24, is under [Testing](#testing).
|
|
208
|
+
- **Test vectors:** labelled test records and keys, in [test/vectors/](test/vectors/README.md). They are for tests only, not for production use.
|
|
209
|
+
- **Examples:** nine runnable examples that check their own behaviour, run by `npm run examples` ([Examples](#examples)).
|
|
210
|
+
|
|
211
|
+
**Security**
|
|
212
|
+
|
|
213
|
+
- **Security review scope:** [docs/SECURITY-REVIEW.md](docs/SECURITY-REVIEW.md) is written for an external reviewer. It covers what the verifier claims, what to examine, and its known limits.
|
|
214
|
+
- **Security policy:** [SECURITY.md](SECURITY.md) explains how to report a vulnerability privately.
|
|
215
|
+
|
|
216
|
+
**Releases**
|
|
217
|
+
|
|
218
|
+
- **Published versions:** `@parmana/verifier` 1.6.2 on npm and `parmana-verifier` 1.6.2 on PyPI, from release `verifier-v1.6.2`.
|
|
219
|
+
- **Changelog:** [CHANGELOG.md](CHANGELOG.md) lists each change to the record formats and the command-line interface.
|
|
220
|
+
- **Release process:** [RELEASING.md](RELEASING.md) describes how a release is built, checked and published.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Read the Parmana blog
|
|
225
|
+
|
|
226
|
+
The [Parmana blog](https://blog.parmanasystems.com) explains how the verifier fits into the wider product, in plain terms. Read the post for your role:
|
|
227
|
+
|
|
228
|
+
- **Auditors and risk teams:** [Check a record offline, without trusting us](https://blog.parmanasystems.com/2026/10/25/check-a-record-offline/). How to verify a signed record with only a file and a trust file, and what the check does not cover.
|
|
229
|
+
- **Engineers:** [Run the checks in an afternoon](https://blog.parmanasystems.com/2026/10/25/run-the-checks-in-an-afternoon/). Build, test and verify a record from source.
|
|
230
|
+
- **Anyone who wants the honest picture:** [Lessons from the limits we still have](https://blog.parmanasystems.com/2026/10/25/lessons-from-the-limits-we-still-have/). What we got wrong, and what remains open.
|
|
231
|
+
|
|
232
|
+
New posts are published regularly, so check the blog for updates.
|
|
233
|
+
|
|
234
|
+
## Status
|
|
235
|
+
|
|
236
|
+
This is version 1.6.2, released with the SDK packages. Each change to the record formats or the command-line interface is listed in [CHANGELOG.md](CHANGELOG.md).
|
|
237
|
+
|
|
238
|
+
On 2026-10-29, on Node 24.22.1 and Windows PowerShell, the two quick-start commands above returned the output shown, with exit codes `0` and `1`. The release process builds the packages, records their hashes, and attaches build provenance. See [RELEASING.md](RELEASING.md) for the steps.
|
|
239
|
+
|
|
240
|
+
What this version does not do is listed under [Limitations](#limitations).
|
|
241
|
+
|
|
242
|
+
## Repository layout
|
|
243
|
+
|
|
244
|
+
| Path | Contents |
|
|
245
|
+
| ----------- | ---------------------------------------------------------------------- |
|
|
246
|
+
| `bin/` | The `parmana-verify` command-line entry point |
|
|
247
|
+
| `src/` | The checks: canonical JSON, hashing, signatures, trust rules |
|
|
248
|
+
| `test/` | The test suite, and `test/vectors/`, the labelled test records |
|
|
249
|
+
| `examples/` | Nine runnable examples, run by `npm run examples` |
|
|
250
|
+
| `docs/` | `FORMAT.md` (the input and output rules) and `SECURITY-REVIEW.md` |
|
|
251
|
+
| `reports/` | Pointer to the reports index in this README (see Reports and evidence) |
|
|
252
|
+
|
|
253
|
+
## Security
|
|
254
|
+
|
|
255
|
+
Do not open a public issue for a security problem. Report it through GitHub's private vulnerability reporting: open the **Security** tab and choose **Report a vulnerability**. See [SECURITY.md](SECURITY.md). The scope for an external review is in [docs/SECURITY-REVIEW.md](docs/SECURITY-REVIEW.md).
|
|
256
|
+
|
|
257
|
+
## Contributing
|
|
258
|
+
|
|
259
|
+
Read [CONTRIBUTING.md](CONTRIBUTING.md) before you open a pull request. Run `npm test` on Node 24 first. Every commit must carry a `Signed-off-by` line (`git commit -s`), certifying the [Developer Certificate of Origin](https://developercertificate.org). Everyone taking part follows the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
260
|
+
|
|
261
|
+
## License
|
|
262
|
+
|
|
263
|
+
Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
|