@unrdf/kgn 5.0.1

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.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +210 -0
  3. package/package.json +90 -0
  4. package/src/MIGRATION_COMPLETE.md +186 -0
  5. package/src/PORT-MAP.md +302 -0
  6. package/src/base/filter-templates.js +479 -0
  7. package/src/base/index.js +92 -0
  8. package/src/base/injection-targets.js +583 -0
  9. package/src/base/macro-templates.js +298 -0
  10. package/src/base/macro-templates.js.bak +461 -0
  11. package/src/base/shacl-templates.js +617 -0
  12. package/src/base/template-base.js +388 -0
  13. package/src/core/attestor.js +381 -0
  14. package/src/core/filters.js +518 -0
  15. package/src/core/index.js +21 -0
  16. package/src/core/kgen-engine.js +372 -0
  17. package/src/core/parser.js +447 -0
  18. package/src/core/post-processor.js +313 -0
  19. package/src/core/renderer.js +469 -0
  20. package/src/doc-generator/cli.mjs +122 -0
  21. package/src/doc-generator/index.mjs +28 -0
  22. package/src/doc-generator/mdx-generator.mjs +71 -0
  23. package/src/doc-generator/nav-generator.mjs +136 -0
  24. package/src/doc-generator/parser.mjs +291 -0
  25. package/src/doc-generator/rdf-builder.mjs +306 -0
  26. package/src/doc-generator/scanner.mjs +189 -0
  27. package/src/engine/index.js +42 -0
  28. package/src/engine/pipeline.js +448 -0
  29. package/src/engine/renderer.js +604 -0
  30. package/src/engine/template-engine.js +566 -0
  31. package/src/filters/array.js +436 -0
  32. package/src/filters/data.js +479 -0
  33. package/src/filters/index.js +270 -0
  34. package/src/filters/rdf.js +264 -0
  35. package/src/filters/text.js +369 -0
  36. package/src/index.js +109 -0
  37. package/src/inheritance/index.js +40 -0
  38. package/src/injection/api.js +260 -0
  39. package/src/injection/atomic-writer.js +327 -0
  40. package/src/injection/constants.js +136 -0
  41. package/src/injection/idempotency-manager.js +295 -0
  42. package/src/injection/index.js +28 -0
  43. package/src/injection/injection-engine.js +378 -0
  44. package/src/injection/integration.js +339 -0
  45. package/src/injection/modes/index.js +341 -0
  46. package/src/injection/rollback-manager.js +373 -0
  47. package/src/injection/target-resolver.js +323 -0
  48. package/src/injection/tests/atomic-writer.test.js +382 -0
  49. package/src/injection/tests/injection-engine.test.js +611 -0
  50. package/src/injection/tests/integration.test.js +392 -0
  51. package/src/injection/tests/run-tests.js +283 -0
  52. package/src/injection/validation-engine.js +547 -0
  53. package/src/linter/determinism-linter.js +473 -0
  54. package/src/linter/determinism.js +410 -0
  55. package/src/linter/index.js +6 -0
  56. package/src/linter/test-doubles.js +475 -0
  57. package/src/parser/frontmatter.js +228 -0
  58. package/src/parser/variables.js +344 -0
  59. package/src/renderer/deterministic.js +245 -0
  60. package/src/renderer/index.js +6 -0
  61. package/src/templates/latex/academic-paper.njk +186 -0
  62. package/src/templates/latex/index.js +104 -0
  63. package/src/templates/nextjs/app-page.njk +66 -0
  64. package/src/templates/nextjs/index.js +80 -0
  65. package/src/templates/office/docx/document.njk +368 -0
  66. package/src/templates/office/index.js +79 -0
  67. package/src/templates/office/word-report.njk +129 -0
  68. package/src/utils/template-utils.js +426 -0
@@ -0,0 +1,381 @@
1
+ /**
2
+ * KGEN Attestor - Generate cryptographic attestations for deterministic output
3
+ *
4
+ * Provides:
5
+ * - Content integrity verification
6
+ * - Deterministic output attestation
7
+ * - Reproduction proofs
8
+ * - Audit trails
9
+ */
10
+
11
+ import crypto from 'crypto';
12
+
13
+ export class KGenAttestor {
14
+ constructor(options = {}) {
15
+ this.options = {
16
+ enableAttestation: options.enableAttestation !== false,
17
+ algorithm: options.algorithm || 'sha256',
18
+ attestorId: options.attestorId || 'kgen-templates',
19
+ version: options.version || '2.0.0',
20
+ staticBuildTime: options.staticBuildTime || '2024-01-01T00:00:00.000Z',
21
+ deterministicMode: options.deterministicMode !== false,
22
+ includeMetadata: options.includeMetadata !== false,
23
+ ...options
24
+ };
25
+ }
26
+
27
+ /**
28
+ * Generate attestation for rendered content
29
+ */
30
+ async attest(content, context = {}) {
31
+ if (!this.options.enableAttestation) {
32
+ return {
33
+ attested: false,
34
+ reason: 'Attestation disabled'
35
+ };
36
+ }
37
+
38
+ try {
39
+ const attestation = await this.createAttestation(content, context);
40
+
41
+ return {
42
+ attested: true,
43
+ attestation,
44
+ metadata: {
45
+ algorithm: this.options.algorithm,
46
+ attestorId: this.options.attestorId,
47
+ version: this.options.version,
48
+ timestamp: this.getTimestamp()
49
+ }
50
+ };
51
+ } catch (error) {
52
+ return {
53
+ attested: false,
54
+ error: error.message,
55
+ metadata: {
56
+ timestamp: this.getTimestamp()
57
+ }
58
+ };
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Create complete attestation record
64
+ */
65
+ async createAttestation(content, context = {}) {
66
+ const contentHash = this.createContentHash(content);
67
+ const contextHash = context.contextHash || this.createContentHash(JSON.stringify(context));
68
+ const templateHash = context.templateHash || '';
69
+
70
+ const attestationData = {
71
+ // Core hashes
72
+ contentHash,
73
+ contextHash,
74
+ templateHash,
75
+
76
+ // Attestation metadata
77
+ algorithm: this.options.algorithm,
78
+ attestorId: this.options.attestorId,
79
+ version: this.options.version,
80
+ timestamp: this.getTimestamp(),
81
+ deterministicMode: this.options.deterministicMode,
82
+
83
+ // Content metadata
84
+ contentLength: content ? content.length : 0,
85
+ contentType: 'text/plain',
86
+
87
+ // Reproducibility data
88
+ reproducible: this.options.deterministicMode,
89
+ staticBuildTime: this.options.staticBuildTime,
90
+
91
+ // Additional metadata if enabled
92
+ ...(this.options.includeMetadata ? this.getAdditionalMetadata(content, context) : {})
93
+ };
94
+
95
+ // Create attestation signature
96
+ const attestationHash = this.createContentHash(JSON.stringify(attestationData));
97
+
98
+ return {
99
+ ...attestationData,
100
+ attestationHash,
101
+ signature: this.createSignature(attestationData)
102
+ };
103
+ }
104
+
105
+ /**
106
+ * Verify attestation integrity
107
+ */
108
+ async verify(content, attestation) {
109
+ try {
110
+ // Verify content hash
111
+ const currentContentHash = this.createContentHash(content);
112
+ if (currentContentHash !== attestation.contentHash) {
113
+ return {
114
+ valid: false,
115
+ reason: 'Content hash mismatch',
116
+ expected: attestation.contentHash,
117
+ actual: currentContentHash
118
+ };
119
+ }
120
+
121
+ // Verify attestation hash
122
+ const { attestationHash, signature, ...attestationData } = attestation;
123
+ const currentAttestationHash = this.createContentHash(JSON.stringify(attestationData));
124
+
125
+ if (currentAttestationHash !== attestationHash) {
126
+ return {
127
+ valid: false,
128
+ reason: 'Attestation hash mismatch',
129
+ expected: attestationHash,
130
+ actual: currentAttestationHash
131
+ };
132
+ }
133
+
134
+ // Verify signature
135
+ const currentSignature = this.createSignature(attestationData);
136
+ if (currentSignature !== signature) {
137
+ return {
138
+ valid: false,
139
+ reason: 'Signature mismatch',
140
+ expected: signature,
141
+ actual: currentSignature
142
+ };
143
+ }
144
+
145
+ return {
146
+ valid: true,
147
+ contentHash: currentContentHash,
148
+ attestationHash: currentAttestationHash,
149
+ verifiedAt: this.getTimestamp()
150
+ };
151
+ } catch (error) {
152
+ return {
153
+ valid: false,
154
+ reason: 'Verification error',
155
+ error: error.message
156
+ };
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Create reproducibility proof
162
+ */
163
+ async createReproducibilityProof(content, context, iterations = 3) {
164
+ const proofs = [];
165
+ let isReproducible = true;
166
+ const baseHash = this.createContentHash(content);
167
+
168
+ for (let i = 0; i < iterations; i++) {
169
+ const attestation = await this.createAttestation(content, context);
170
+
171
+ proofs.push({
172
+ iteration: i + 1,
173
+ contentHash: attestation.contentHash,
174
+ attestationHash: attestation.attestationHash,
175
+ timestamp: attestation.timestamp
176
+ });
177
+
178
+ // Check if content hash is consistent
179
+ if (attestation.contentHash !== baseHash) {
180
+ isReproducible = false;
181
+ }
182
+ }
183
+
184
+ return {
185
+ reproducible: isReproducible,
186
+ baseHash,
187
+ iterations,
188
+ proofs,
189
+ algorithm: this.options.algorithm,
190
+ deterministicMode: this.options.deterministicMode,
191
+ generatedAt: this.getTimestamp()
192
+ };
193
+ }
194
+
195
+ /**
196
+ * Create audit trail for template execution
197
+ */
198
+ createAuditTrail(steps = []) {
199
+ return {
200
+ trailId: this.createContentHash(Date.now().toString()),
201
+ attestorId: this.options.attestorId,
202
+ version: this.options.version,
203
+ createdAt: this.getTimestamp(),
204
+ deterministicMode: this.options.deterministicMode,
205
+ steps: steps.map((step, index) => ({
206
+ stepId: index + 1,
207
+ ...step,
208
+ hash: this.createContentHash(JSON.stringify(step)),
209
+ timestamp: step.timestamp || this.getTimestamp()
210
+ })),
211
+ trailHash: this.createContentHash(JSON.stringify(steps))
212
+ };
213
+ }
214
+
215
+ /**
216
+ * Compare two attestations
217
+ */
218
+ compareAttestations(attestation1, attestation2) {
219
+ const differences = [];
220
+
221
+ // Compare core hashes
222
+ if (attestation1.contentHash !== attestation2.contentHash) {
223
+ differences.push({
224
+ field: 'contentHash',
225
+ value1: attestation1.contentHash,
226
+ value2: attestation2.contentHash
227
+ });
228
+ }
229
+
230
+ if (attestation1.contextHash !== attestation2.contextHash) {
231
+ differences.push({
232
+ field: 'contextHash',
233
+ value1: attestation1.contextHash,
234
+ value2: attestation2.contextHash
235
+ });
236
+ }
237
+
238
+ if (attestation1.templateHash !== attestation2.templateHash) {
239
+ differences.push({
240
+ field: 'templateHash',
241
+ value1: attestation1.templateHash,
242
+ value2: attestation2.templateHash
243
+ });
244
+ }
245
+
246
+ // Compare metadata
247
+ const metadataFields = ['algorithm', 'version', 'deterministicMode', 'contentLength'];
248
+ metadataFields.forEach(field => {
249
+ if (attestation1[field] !== attestation2[field]) {
250
+ differences.push({
251
+ field,
252
+ value1: attestation1[field],
253
+ value2: attestation2[field]
254
+ });
255
+ }
256
+ });
257
+
258
+ return {
259
+ identical: differences.length === 0,
260
+ differences,
261
+ comparedAt: this.getTimestamp()
262
+ };
263
+ }
264
+
265
+ /**
266
+ * Create content hash using specified algorithm
267
+ */
268
+ createContentHash(content) {
269
+ return crypto.createHash(this.options.algorithm)
270
+ .update(String(content || ''), 'utf8')
271
+ .digest('hex');
272
+ }
273
+
274
+ /**
275
+ * Create signature for attestation data
276
+ */
277
+ createSignature(data) {
278
+ // Simple signature using hash of data + attestor ID
279
+ const signatureInput = JSON.stringify(data) + this.options.attestorId + this.options.version;
280
+ return crypto.createHash(this.options.algorithm)
281
+ .update(signatureInput, 'utf8')
282
+ .digest('hex');
283
+ }
284
+
285
+ /**
286
+ * Get additional metadata if enabled
287
+ */
288
+ getAdditionalMetadata(content, context) {
289
+ return {
290
+ systemInfo: {
291
+ platform: process.platform,
292
+ nodeVersion: process.version,
293
+ architecture: process.arch
294
+ },
295
+ environment: {
296
+ deterministicMode: this.options.deterministicMode,
297
+ staticBuildTime: this.options.staticBuildTime
298
+ },
299
+ contentAnalysis: {
300
+ lineCount: content ? content.split('\n').length : 0,
301
+ charCount: content ? content.length : 0,
302
+ hasUnicodeChars: content ? /[^\x00-\x7F]/.test(content) : false
303
+ }
304
+ };
305
+ }
306
+
307
+ /**
308
+ * Get deterministic or real timestamp
309
+ */
310
+ getTimestamp() {
311
+ return this.options.deterministicMode ?
312
+ this.options.staticBuildTime :
313
+ new Date().toISOString();
314
+ }
315
+
316
+ /**
317
+ * Export attestation in standard format
318
+ */
319
+ exportAttestation(attestation, format = 'json') {
320
+ switch (format.toLowerCase()) {
321
+ case 'json':
322
+ return JSON.stringify(attestation, null, 2);
323
+
324
+ case 'compact':
325
+ return JSON.stringify(attestation);
326
+
327
+ case 'yaml':
328
+ // Basic YAML export (simplified)
329
+ return Object.entries(attestation)
330
+ .map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
331
+ .join('\n');
332
+
333
+ case 'base64':
334
+ return Buffer.from(JSON.stringify(attestation)).toString('base64');
335
+
336
+ default:
337
+ throw new Error(`Unsupported export format: ${format}`);
338
+ }
339
+ }
340
+
341
+ /**
342
+ * Import attestation from standard format
343
+ */
344
+ importAttestation(data, format = 'json') {
345
+ try {
346
+ switch (format.toLowerCase()) {
347
+ case 'json':
348
+ case 'compact':
349
+ return JSON.parse(data);
350
+
351
+ case 'base64':
352
+ const decoded = Buffer.from(data, 'base64').toString('utf8');
353
+ return JSON.parse(decoded);
354
+
355
+ default:
356
+ throw new Error(`Unsupported import format: ${format}`);
357
+ }
358
+ } catch (error) {
359
+ throw new Error(`Failed to import attestation: ${error.message}`);
360
+ }
361
+ }
362
+
363
+ /**
364
+ * Get attestor statistics
365
+ */
366
+ getStats() {
367
+ return {
368
+ ...this.options,
369
+ supportedAlgorithms: ['sha256', 'sha512', 'sha1'],
370
+ supportedFormats: ['json', 'compact', 'yaml', 'base64'],
371
+ features: [
372
+ 'content-attestation',
373
+ 'reproducibility-proof',
374
+ 'audit-trail',
375
+ 'signature-verification'
376
+ ]
377
+ };
378
+ }
379
+ }
380
+
381
+ export default KGenAttestor;