@unrdf/kgc-probe 26.4.2
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 +414 -0
- package/package.json +81 -0
- package/src/agents/index.mjs +1402 -0
- package/src/artifact.mjs +405 -0
- package/src/cli.mjs +932 -0
- package/src/config.mjs +115 -0
- package/src/guards.mjs +1213 -0
- package/src/index.mjs +347 -0
- package/src/merge.mjs +196 -0
- package/src/observation.mjs +193 -0
- package/src/orchestrator.mjs +315 -0
- package/src/probe.mjs +58 -0
- package/src/probes/CONCURRENCY-PROBE.md +256 -0
- package/src/probes/README.md +275 -0
- package/src/probes/concurrency.mjs +1175 -0
- package/src/probes/filesystem.mjs +731 -0
- package/src/probes/filesystem.test.mjs +244 -0
- package/src/probes/network.mjs +503 -0
- package/src/probes/performance.mjs +816 -0
- package/src/probes/persistence.mjs +785 -0
- package/src/probes/runtime.mjs +589 -0
- package/src/probes/tooling.mjs +454 -0
- package/src/probes/tooling.test.mjs +372 -0
- package/src/probes/verify-execution.mjs +131 -0
- package/src/probes/verify-guards.mjs +73 -0
- package/src/probes/wasm.mjs +715 -0
- package/src/receipt.mjs +197 -0
- package/src/receipts/index.mjs +813 -0
- package/src/reporter.example.mjs +223 -0
- package/src/reporter.mjs +555 -0
- package/src/reporters/markdown.mjs +355 -0
- package/src/reporters/rdf.mjs +383 -0
- package/src/storage/index.mjs +827 -0
- package/src/types.mjs +1028 -0
- package/src/utils/errors.mjs +397 -0
- package/src/utils/index.mjs +32 -0
- package/src/utils/logger.mjs +236 -0
- package/src/vocabulary.ttl +169 -0
package/src/receipt.mjs
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Receipt generation with hash chains for KGC Probe
|
|
4
|
+
*
|
|
5
|
+
* Receipt = cryptographic proof of observation integrity.
|
|
6
|
+
* Uses BLAKE3 for fast, deterministic hashing.
|
|
7
|
+
*
|
|
8
|
+
* Hash chain: Each receipt includes hash of previous receipt → tamper-evident sequence.
|
|
9
|
+
*
|
|
10
|
+
* Design principles:
|
|
11
|
+
* - Deterministic: Same input → same hash
|
|
12
|
+
* - Tamper-evident: Any modification breaks chain
|
|
13
|
+
* - Fast: BLAKE3 is optimized for speed
|
|
14
|
+
* - Verifiable: Can reconstruct and verify entire chain
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { blake3 } from '@noble/hashes/blake3';
|
|
18
|
+
import { bytesToHex } from '@noble/hashes/utils';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Hash data deterministically using BLAKE3
|
|
22
|
+
*
|
|
23
|
+
* @param {any} data - Data to hash (will be JSON-stringified with stable key order)
|
|
24
|
+
* @returns {string} - Hex-encoded hash
|
|
25
|
+
*/
|
|
26
|
+
export function hashData(data) {
|
|
27
|
+
// Stable JSON serialization (sorted keys)
|
|
28
|
+
const json = JSON.stringify(data, Object.keys(data).sort());
|
|
29
|
+
const bytes = new TextEncoder().encode(json);
|
|
30
|
+
const hash = blake3(bytes);
|
|
31
|
+
return bytesToHex(hash);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create receipt for an observation
|
|
36
|
+
*
|
|
37
|
+
* @param {import('./observation.mjs').Observation} observation - Observation to create receipt for
|
|
38
|
+
* @param {string} [previousHash] - Hash of previous receipt (for chain)
|
|
39
|
+
* @returns {Receipt}
|
|
40
|
+
*
|
|
41
|
+
* @typedef {Object} Receipt
|
|
42
|
+
* @property {string} observationId - ID of observation this receipt covers
|
|
43
|
+
* @property {string} hash - BLAKE3 hash of observation content
|
|
44
|
+
* @property {string} [previousHash] - Hash of previous receipt (chain)
|
|
45
|
+
* @property {number} index - Position in chain (0-indexed)
|
|
46
|
+
* @property {string} timestamp - ISO 8601 timestamp
|
|
47
|
+
*/
|
|
48
|
+
export function createReceipt(observation, previousHash = null) {
|
|
49
|
+
// Create deterministic content for hashing
|
|
50
|
+
const content = {
|
|
51
|
+
id: observation.id,
|
|
52
|
+
category: observation.category,
|
|
53
|
+
severity: observation.severity,
|
|
54
|
+
message: observation.message,
|
|
55
|
+
location: observation.location,
|
|
56
|
+
data: observation.data,
|
|
57
|
+
metadata: observation.metadata,
|
|
58
|
+
tags: observation.tags.slice().sort() // Stable tag order
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const hash = hashData(content);
|
|
62
|
+
|
|
63
|
+
const receipt = {
|
|
64
|
+
observationId: observation.id,
|
|
65
|
+
hash,
|
|
66
|
+
previousHash,
|
|
67
|
+
index: previousHash ? -1 : 0, // Will be set by chain builder
|
|
68
|
+
timestamp: new Date().toISOString()
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return receipt;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Build receipt chain from observations
|
|
76
|
+
*
|
|
77
|
+
* @param {import('./observation.mjs').Observation[]} observations - Observations to chain
|
|
78
|
+
* @returns {Receipt[]} - Receipt chain
|
|
79
|
+
*/
|
|
80
|
+
export function buildReceiptChain(observations) {
|
|
81
|
+
const receipts = [];
|
|
82
|
+
let previousHash = null;
|
|
83
|
+
|
|
84
|
+
for (let i = 0; i < observations.length; i++) {
|
|
85
|
+
const receipt = createReceipt(observations[i], previousHash);
|
|
86
|
+
receipt.index = i;
|
|
87
|
+
receipts.push(receipt);
|
|
88
|
+
previousHash = receipt.hash;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return receipts;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Verify receipt chain integrity
|
|
96
|
+
*
|
|
97
|
+
* @param {Receipt[]} receipts - Receipt chain to verify
|
|
98
|
+
* @returns {boolean} - True if chain is valid
|
|
99
|
+
*/
|
|
100
|
+
export function verifyReceiptChain(receipts) {
|
|
101
|
+
if (receipts.length === 0) {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// First receipt should have no previous hash
|
|
106
|
+
if (receipts[0].previousHash !== null) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Verify chain links
|
|
111
|
+
for (let i = 1; i < receipts.length; i++) {
|
|
112
|
+
if (receipts[i].previousHash !== receipts[i - 1].hash) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
if (receipts[i].index !== i) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Verify observation against receipt
|
|
125
|
+
*
|
|
126
|
+
* @param {import('./observation.mjs').Observation} observation - Observation to verify
|
|
127
|
+
* @param {Receipt} receipt - Receipt to verify against
|
|
128
|
+
* @returns {boolean} - True if observation matches receipt
|
|
129
|
+
*/
|
|
130
|
+
export function verifyObservation(observation, receipt) {
|
|
131
|
+
const recomputedReceipt = createReceipt(observation, receipt.previousHash);
|
|
132
|
+
return recomputedReceipt.hash === receipt.hash;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Create receipt manifest (summary of entire chain)
|
|
137
|
+
*
|
|
138
|
+
* @param {Receipt[]} receipts - Receipt chain
|
|
139
|
+
* @returns {ReceiptManifest}
|
|
140
|
+
*
|
|
141
|
+
* @typedef {Object} ReceiptManifest
|
|
142
|
+
* @property {number} count - Number of receipts in chain
|
|
143
|
+
* @property {string} firstHash - Hash of first receipt
|
|
144
|
+
* @property {string} lastHash - Hash of last receipt
|
|
145
|
+
* @property {string} chainHash - Hash of entire chain
|
|
146
|
+
* @property {string} timestamp - ISO 8601 timestamp
|
|
147
|
+
*/
|
|
148
|
+
export function createManifest(receipts) {
|
|
149
|
+
if (receipts.length === 0) {
|
|
150
|
+
return {
|
|
151
|
+
count: 0,
|
|
152
|
+
firstHash: null,
|
|
153
|
+
lastHash: null,
|
|
154
|
+
chainHash: null,
|
|
155
|
+
timestamp: new Date().toISOString()
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Chain hash = hash of all receipt hashes
|
|
160
|
+
const chainContent = receipts.map(r => r.hash).join('');
|
|
161
|
+
const chainHash = hashData(chainContent);
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
count: receipts.length,
|
|
165
|
+
firstHash: receipts[0].hash,
|
|
166
|
+
lastHash: receipts[receipts.length - 1].hash,
|
|
167
|
+
chainHash,
|
|
168
|
+
timestamp: new Date().toISOString()
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Verify manifest matches receipts
|
|
174
|
+
*
|
|
175
|
+
* @param {ReceiptManifest} manifest - Manifest to verify
|
|
176
|
+
* @param {Receipt[]} receipts - Receipt chain
|
|
177
|
+
* @returns {boolean} - True if manifest is valid
|
|
178
|
+
*/
|
|
179
|
+
export function verifyManifest(manifest, receipts) {
|
|
180
|
+
const recomputed = createManifest(receipts);
|
|
181
|
+
return (
|
|
182
|
+
manifest.count === recomputed.count &&
|
|
183
|
+
manifest.firstHash === recomputed.firstHash &&
|
|
184
|
+
manifest.lastHash === recomputed.lastHash &&
|
|
185
|
+
manifest.chainHash === recomputed.chainHash
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export default {
|
|
190
|
+
hashData,
|
|
191
|
+
createReceipt,
|
|
192
|
+
buildReceiptChain,
|
|
193
|
+
verifyReceiptChain,
|
|
194
|
+
verifyObservation,
|
|
195
|
+
createManifest,
|
|
196
|
+
verifyManifest
|
|
197
|
+
};
|