progmune-runtime 2.1.6 → 3.2.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 +108 -468
- package/dist/ablation-study.js +144 -0
- package/dist/ablation-study.test.js +18 -0
- package/dist/action-runtime.js +3 -1
- package/dist/active-learning.js +211 -0
- package/dist/analytics.js +139 -0
- package/dist/asset-factory.js +309 -0
- package/dist/asset-growth.js +244 -0
- package/dist/asset-promotion.js +382 -0
- package/dist/asset-quality.js +550 -0
- package/dist/audit/business-translator.js +285 -0
- package/dist/audit/cli.js +66 -0
- package/dist/audit/formatters/html.js +379 -0
- package/dist/audit/formatters/json.js +11 -0
- package/dist/audit/formatters/markdown.js +192 -0
- package/dist/audit/formatters/terminal.js +189 -0
- package/dist/audit/index.js +25 -0
- package/dist/audit/report-builder.js +318 -0
- package/dist/audit/types.js +8 -0
- package/dist/audit.js +3 -3
- package/dist/auto-benchmark-generator.js +137 -0
- package/dist/auto-benchmark-generator.test.js +45 -0
- package/dist/auto-protocol-synthesizer.js +362 -0
- package/dist/auto-protocol-synthesizer.test.js +82 -0
- package/dist/autonomous-patch.js +175 -0
- package/dist/autonomous-patch.test.js +128 -0
- package/dist/badge/badge-server.js +98 -0
- package/dist/behavior-miner.js +442 -0
- package/dist/belief-layer.js +475 -0
- package/dist/benchmark-count.js +5 -0
- package/dist/benchmark-generator.js +211 -0
- package/dist/benchmark-harness.js +201 -0
- package/dist/benchmark-pass-rate.js +7 -0
- package/dist/benchmark-report.js +8 -3
- package/dist/benchmark-save.js +14 -1
- package/dist/bootstrap-validation.js +197 -0
- package/dist/bootstrap-validation.test.js +51 -0
- package/dist/branch-ledger.js +1 -1
- package/dist/capability-gap.js +130 -0
- package/dist/certify-html.js +351 -0
- package/dist/certify.js +326 -0
- package/dist/check.js +4 -4
- package/dist/compliance-miner.js +447 -0
- package/dist/continuous-benchmark.js +194 -0
- package/dist/continuous-benchmark.test.js +116 -0
- package/dist/corpus-stats.js +173 -0
- package/dist/counterfactual-engine.js +288 -0
- package/dist/coverage-dashboard.js +109 -0
- package/dist/coverage-system.test.js +205 -0
- package/dist/cross-repo-precision.js +352 -0
- package/dist/cve-benchmark.js +180 -0
- package/dist/cve-benchmark.test.js +28 -0
- package/dist/cve-collector.js +73 -0
- package/dist/data-quality.js +141 -0
- package/dist/decision-engine.js +388 -0
- package/dist/derive-metadata.js +250 -0
- package/dist/difficulty-active.test.js +198 -0
- package/dist/difficulty-map.js +244 -0
- package/dist/discovery-analytics.js +125 -0
- package/dist/discovery-model.js +149 -0
- package/dist/discovery-optimize.test.js +199 -0
- package/dist/discovery-trace.js +276 -0
- package/dist/discovery-trace.test.js +97 -0
- package/dist/emitter.js +83 -1
- package/dist/enterprise-dashboard.js +405 -0
- package/dist/eval-hardening.js +297 -0
- package/dist/eval-hardening.test.js +85 -0
- package/dist/evaluation-campaign.js +359 -0
- package/dist/evaluation-campaign.test.js +181 -0
- package/dist/evidence-growth.js +143 -0
- package/dist/evidence-repository.js +209 -0
- package/dist/evidence-system.js +441 -0
- package/dist/execute.js +15 -7
- package/dist/experimental/software-physics.js +291 -0
- package/dist/experimental/state-inference.js +516 -0
- package/dist/experimental/unsupervised-physics.js +230 -0
- package/dist/extract-ir-python.js +54 -7
- package/dist/extract-ir.js +376 -12
- package/dist/failure-collector.js +2 -2
- package/dist/failure-corpus.js +322 -9
- package/dist/feedback.js +16 -5
- package/dist/feedback.test.js +49 -0
- package/dist/file-lock.js +1 -1
- package/dist/flywheel-batch.js +292 -0
- package/dist/frameworks/express-cli.js +237 -0
- package/dist/frameworks/express-detector.js +445 -0
- package/dist/frameworks/express-detector.test.js +206 -0
- package/dist/frameworks/index.js +30 -0
- package/dist/frameworks/nestjs-detector.js +302 -0
- package/dist/frameworks/trpc-detector.js +161 -0
- package/dist/frameworks/version-awareness.js +179 -0
- package/dist/function-synonyms.js +164 -0
- package/dist/function-synonyms.test.js +68 -0
- package/dist/generalization.test.js +352 -0
- package/dist/goal-annotator.js +113 -0
- package/dist/goal-planner.js +563 -0
- package/dist/gold-cve.js +164 -0
- package/dist/gold-cve.test.js +104 -0
- package/dist/gold-quality.js +206 -0
- package/dist/gold-tiers.js +241 -0
- package/dist/governance-dashboard.js +327 -0
- package/dist/graph-viz.js +240 -0
- package/dist/guided-frontier.js +195 -0
- package/dist/hierarchical-planner.js +148 -0
- package/dist/identifier-parser.js +260 -0
- package/dist/immune-metrics.js +93 -0
- package/dist/immune-receiver.js +158 -0
- package/dist/immune-reporter.js +1 -1
- package/dist/improvement-orchestrator.js +206 -0
- package/dist/inject-p0-vocabulary.js +300 -0
- package/dist/intent-parser.js +218 -0
- package/dist/invariant-algebra.js +476 -0
- package/dist/invariant-calculus.js +533 -0
- package/dist/ir-utils.js +70 -0
- package/dist/ir-utils.test.js +50 -0
- package/dist/knowledge-api.js +312 -0
- package/dist/knowledge-evolution.js +452 -0
- package/dist/knowledge-explorer.js +506 -0
- package/dist/knowledge-flywheel.js +274 -0
- package/dist/knowledge-governance.js +338 -0
- package/dist/knowledge-governance.test.js +150 -0
- package/dist/knowledge-graph.js +181 -0
- package/dist/knowledge-guided-synth.js +246 -0
- package/dist/knowledge-loop.test.js +77 -0
- package/dist/knowledge-object.js +316 -0
- package/dist/knowledge-package.js +98 -0
- package/dist/kpi-dashboard.js +561 -0
- package/dist/l3-cross-function.js +280 -0
- package/dist/learning-ranker.js +148 -0
- package/dist/learning-ranker.test.js +291 -0
- package/dist/ledger/accountability.js +322 -0
- package/dist/ledger/chain-builder.js +185 -0
- package/dist/ledger/cli.js +222 -0
- package/dist/ledger/index.js +13 -0
- package/dist/ledger/signatures.js +193 -0
- package/dist/ledger/types.js +9 -0
- package/dist/llm.js +74 -3
- package/dist/load-benchmarks.js +8 -3
- package/dist/logger.js +66 -0
- package/dist/logger.test.js +37 -0
- package/dist/logistic-reward.js +339 -0
- package/dist/logistic-reward.test.js +180 -0
- package/dist/macro-graph.js +193 -0
- package/dist/macro-repair.js +183 -0
- package/dist/mcp-server.mjs +1202 -483
- package/dist/memory-layer.js +42 -5
- package/dist/multi-repo-precision.js +422 -0
- package/dist/name-free-protocol.js +425 -0
- package/dist/name-free-protocol.test.js +170 -0
- package/dist/name-scrambling.js +138 -0
- package/dist/name-scrambling.test.js +16 -0
- package/dist/p3-observability.test.js +281 -0
- package/dist/p5-orchestrator.test.js +225 -0
- package/dist/pairwise-preference.js +294 -0
- package/dist/pairwise-preference.test.js +140 -0
- package/dist/planner-constraints.js +104 -0
- package/dist/planner-prompts.js +155 -0
- package/dist/planner-telemetry.js +415 -0
- package/dist/planner-trace.js +214 -0
- package/dist/planner.js +162 -167
- package/dist/plsb/artifact.js +116 -0
- package/dist/plsb/cli.js +71 -0
- package/dist/plsb/index.js +19 -0
- package/dist/plsb/leaderboard.js +249 -0
- package/dist/plsb/report-md.js +156 -0
- package/dist/plsb/schema.js +179 -0
- package/dist/plsb-benchmark.js +284 -0
- package/dist/plsb-benchmark.test.js +119 -0
- package/dist/policy/cli.js +134 -0
- package/dist/policy/engine.js +333 -0
- package/dist/policy/index.js +12 -0
- package/dist/policy/types.js +59 -0
- package/dist/policy-miner.js +505 -0
- package/dist/precision-analyze.js +229 -0
- package/dist/precision-benchmark.js +147 -0
- package/dist/precision-label-c.js +134 -0
- package/dist/precision-label.js +193 -0
- package/dist/precision-report-c.js +149 -0
- package/dist/precision-report.js +246 -0
- package/dist/progmune-status.js +108 -0
- package/dist/proof-engine.js +479 -0
- package/dist/proof-provenance.js +315 -0
- package/dist/protocol-coverage.js +294 -0
- package/dist/protocol-detector.js +1189 -0
- package/dist/protocol-embedding-expanded.js +297 -0
- package/dist/protocol-embedding-expanded.test.js +97 -0
- package/dist/protocol-embedding.js +195 -0
- package/dist/protocol-embedding.test.js +82 -0
- package/dist/protocol-extractor-v2.js +354 -0
- package/dist/protocol-extractor-v2.test.js +140 -0
- package/dist/protocol-extractor.js +310 -0
- package/dist/protocol-extractor.test.js +113 -0
- package/dist/protocol-foundation.js +322 -0
- package/dist/protocol-foundation.test.js +163 -0
- package/dist/protocol-frontier.js +243 -0
- package/dist/protocol-frontier.test.js +92 -0
- package/dist/protocol-gap-analyzer.js +228 -0
- package/dist/protocol-gap-analyzer.test.js +49 -0
- package/dist/protocol-invariants.js +276 -0
- package/dist/protocol-invariants.test.js +111 -0
- package/dist/protocol-knowledge.js +464 -0
- package/dist/protocol-miner.js +343 -0
- package/dist/protocol-mining.js +207 -0
- package/dist/protocol-mining.test.js +37 -0
- package/dist/protocol-registry.js +1 -1
- package/dist/protocol-security-benchmark.js +222 -0
- package/dist/protocol-vulnerability.js +257 -0
- package/dist/protocol-vulnerability.test.js +60 -0
- package/dist/python-benchmark.js +120 -0
- package/dist/python-emitter.js +163 -45
- package/dist/python-protocol-extractor.js +187 -0
- package/dist/python-protocol-extractor.test.js +116 -0
- package/dist/realworld-benchmark.js +646 -0
- package/dist/realworld-benchmark.test.js +36 -0
- package/dist/repair-arch.test.js +411 -0
- package/dist/repair-evolution.test.js +454 -0
- package/dist/repair-executor.js +719 -0
- package/dist/repair-proposal.js +4 -4
- package/dist/repair-ranker.js +141 -0
- package/dist/repair-strategies.js +419 -0
- package/dist/repair-taxonomy.js +234 -0
- package/dist/repair-types.js +12 -0
- package/dist/repo-evaluator.js +250 -0
- package/dist/repo-evaluator.test.js +128 -0
- package/dist/resource-abstraction.js +242 -0
- package/dist/resource-detector.js +211 -0
- package/dist/result.test.js +43 -0
- package/dist/reward-system.js +411 -0
- package/dist/reward-system.test.js +175 -0
- package/dist/risk-model.js +215 -0
- package/dist/rule-miner.js +234 -7
- package/dist/rule-specificity.js +254 -0
- package/dist/runtime-types.js +27 -0
- package/dist/scaffold.js +208 -0
- package/dist/scale-collector.test.js +101 -0
- package/dist/scale-trajectory-collector.js +128 -0
- package/dist/sdk.js +250 -0
- package/dist/search-planner.js +4 -41
- package/dist/semantic-snapshot.js +1 -1
- package/dist/semantic-topology.js +121 -0
- package/dist/semantic-trace.js +310 -317
- package/dist/sequence-extractor.js +343 -0
- package/dist/skill-library.js +245 -0
- package/dist/skill-planner.test.js +189 -0
- package/dist/software-physics.js +291 -0
- package/dist/software-physics.test.js +81 -0
- package/dist/ssg-precision.js +478 -0
- package/dist/ssg-validator.js +71 -21
- package/dist/state-inference-doubleblind.test.js +160 -0
- package/dist/state-inference.js +516 -0
- package/dist/state-inference.test.js +115 -0
- package/dist/state-machine-fingerprint.js +345 -0
- package/dist/state-machine-fingerprint.test.js +120 -0
- package/dist/state-miner.js +386 -0
- package/dist/state-name-inference.js +213 -0
- package/dist/state-name-inference.test.js +69 -0
- package/dist/strategy-planner.js +262 -96
- package/dist/strategy-planner.test.js +135 -0
- package/dist/telemetry-analytics.test.js +402 -0
- package/dist/terminal-format.js +68 -0
- package/dist/terminal-format.test.js +83 -0
- package/dist/topology-factory.js +196 -0
- package/dist/topology-representation.js +242 -0
- package/dist/topology-representation.test.js +27 -0
- package/dist/trajectory-augmentation.js +254 -0
- package/dist/trajectory-augmentation.test.js +63 -0
- package/dist/trajectory-corpus.js +440 -0
- package/dist/trajectory-corpus.test.js +32 -0
- package/dist/trajectory-feedback.test.js +116 -0
- package/dist/transition-synthesizer.js +286 -0
- package/dist/transition-synthesizer.test.js +123 -0
- package/dist/trust/api-semantic-mapper.js +809 -0
- package/dist/trust/call-graph-propagator.js +225 -0
- package/dist/trust/cli.js +122 -0
- package/dist/trust/compliance-scorer.js +283 -0
- package/dist/trust/confidence-calculator.js +261 -0
- package/dist/trust/engine.js +1145 -0
- package/dist/trust/explainability.js +85 -0
- package/dist/trust/formatters/ci.js +42 -0
- package/dist/trust/formatters/json.js +11 -0
- package/dist/trust/formatters/terminal.js +152 -0
- package/dist/trust/index.js +39 -0
- package/dist/trust/phase1-verify.js +171 -0
- package/dist/trust/protocol-domain-validator.js +697 -0
- package/dist/trust/score-calculator.js +282 -0
- package/dist/trust/ssg-bridge.js +641 -0
- package/dist/trust/ssg-bridge.test.js +269 -0
- package/dist/trust/types.js +67 -0
- package/dist/trust/violation-trace.js +335 -0
- package/dist/trust-api.js +179 -0
- package/dist/trust-calibration.js +279 -0
- package/dist/unknown-protocol-discovery.js +339 -0
- package/dist/unknown-protocol-discovery.test.js +102 -0
- package/dist/unsupervised-physics.js +230 -0
- package/dist/unsupervised-physics.test.js +95 -0
- package/dist/utils.test.js +37 -0
- package/dist/validator.js +187 -10
- package/dist/verification-intelligence.js +475 -0
- package/dist/verify-api.js +432 -0
- package/dist/vi-impact-report.js +293 -0
- package/dist/wl-fingerprint.js +162 -0
- package/dist/wl-fingerprint.test.js +130 -0
- package/dist/zeroshot-strategy.js +139 -0
- package/docs/Progmune_/346/212/225/350/265/204/344/272/272/347/231/275/347/232/256/344/271/246_v2.0.html +576 -0
- package/docs/Progmune_/351/241/271/347/233/256/345/205/250/350/247/243.html +710 -0
- package/package.json +74 -7
- package/protocols.json +1956 -50
- package/.dockerignore +0 -14
- package/.mcp.json +0 -11
- package/.progmune_allowlist +0 -50
- package/.test_report/test_report.md +0 -87
- package/Dockerfile +0 -9
- package/FAQ.md +0 -167
- package/WHITEPAPER.md +0 -540
- package/demo-project/auth.ts +0 -55
- package/demo-project/tsconfig.json +0 -8
- package/dist/acl-breakdown.js +0 -13
- package/dist/all-sessions.js +0 -11
- package/dist/antibody-stats.js +0 -11
- package/dist/branch-tree-count.js +0 -14
- package/dist/common-fixpath.js +0 -12
- package/dist/constraint-types.js +0 -12
- package/dist/exec-metrics.js +0 -11
- package/dist/failure-report.js +0 -11
- package/dist/fast-path-hits.js +0 -13
- package/dist/fingerprint-list.js +0 -15
- package/dist/gen-history-log.js +0 -13
- package/dist/heatmap-data.js +0 -11
- package/dist/recent-session.js +0 -12
- package/dist/svl-distribution.js +0 -11
- package/dist/terminal-status.js +0 -11
- package/dist/token-savings.js +0 -11
- package/dist/total-repairs.js +0 -12
- package/dist/unresolved-count.js +0 -12
- package/dist/valid-fingerprints.js +0 -13
- package/dist/verify-ledgers.js +0 -11
- package/docs/whitepaper-style.css +0 -77
- package/docs/whitepaper-v2.1.md +0 -609
- package/docs/whitepaper-v2.2.md +0 -1064
- package/docs/whitepaper-v2.2.pdf +0 -0
- package/fly.toml +0 -31
- package/public/dashboard.html +0 -119
- package/server/hub.js +0 -116
- package/test/replay-golden/sess_1780063202050_mgeld.json +0 -9
- package/test/replay-golden/sess_1780064032560_gocld.json +0 -354
- package/test/replay-golden/sess_1780064413331_s2709.json +0 -606
- package/test/replay-golden/sess_1780064792710_y3avo.json +0 -614
- package/test/replay-golden.ts +0 -84
- package/test_benchmark.js +0 -165
- package/test_comprehensive.mjs +0 -638
- package/test_concurrency.js +0 -129
- package/test_ir_robustness.js +0 -85
- package/test_semantic_contracts.js +0 -269
- package/test_ssg_stress.js +0 -156
- package/test_svl3.js +0 -58
- package/tsconfig.json +0 -17
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase 9: Provenance Chain Builder
|
|
4
|
+
*
|
|
5
|
+
* Constructs an end-to-end provenance chain for a session.
|
|
6
|
+
* Reads session data from the corpus and builds a timeline of
|
|
7
|
+
* every generation, validation, repair, and deployment event.
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.buildProvenanceChain = buildProvenanceChain;
|
|
44
|
+
const crypto = __importStar(require("crypto"));
|
|
45
|
+
function shortHash(data) {
|
|
46
|
+
return crypto.createHash("sha256").update(data).digest("hex").slice(0, 16);
|
|
47
|
+
}
|
|
48
|
+
/** Compute event hash = SHA256(index + step + artifact + prevHash + timestamp + result) */
|
|
49
|
+
function hashEvent(index, step, artifact, prevHash, timestamp, result) {
|
|
50
|
+
return shortHash(`${index}|${step}|${artifact}|${prevHash}|${timestamp}|${result}`);
|
|
51
|
+
}
|
|
52
|
+
/** Compute chain root hash = SHA256(all event hashes concatenated) */
|
|
53
|
+
function computeChainHash(events) {
|
|
54
|
+
return shortHash(events.map((e) => e.hash).join(""));
|
|
55
|
+
}
|
|
56
|
+
function buildProvenanceChain(sessionId) {
|
|
57
|
+
// Load session
|
|
58
|
+
const { getAllSessions } = require("../failure-corpus");
|
|
59
|
+
const sessions = getAllSessions();
|
|
60
|
+
const session = sessions.find((s) => s.sessionId === sessionId || s.sessionId?.startsWith(sessionId));
|
|
61
|
+
if (!session) {
|
|
62
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
63
|
+
}
|
|
64
|
+
const events = [];
|
|
65
|
+
let allTransitions = [];
|
|
66
|
+
let repairCount = 0;
|
|
67
|
+
let prevHash = ""; // Genesis block — first event has empty prevHash
|
|
68
|
+
for (const attempt of session.attempts || []) {
|
|
69
|
+
const trans = attempt.transitions || [];
|
|
70
|
+
const ts = new Date(attempt.timestamp || Date.now()).toISOString();
|
|
71
|
+
// Generation events — one per transition
|
|
72
|
+
for (const t of trans) {
|
|
73
|
+
const fn = t.function || "unknown";
|
|
74
|
+
const result = t.valid !== false ? "passed" : "failed";
|
|
75
|
+
const eventHash = hashEvent(events.length, "generation", fn, prevHash, ts, result);
|
|
76
|
+
events.push({
|
|
77
|
+
index: events.length,
|
|
78
|
+
step: "generation",
|
|
79
|
+
timestamp: ts,
|
|
80
|
+
actor: attempt.plannerSeed?.includes("fallback") ? "planner" : "llm",
|
|
81
|
+
artifact: fn,
|
|
82
|
+
hash: eventHash,
|
|
83
|
+
prevHash,
|
|
84
|
+
result: result,
|
|
85
|
+
detail: t.valid !== false ? undefined : "SSG protocol violation",
|
|
86
|
+
});
|
|
87
|
+
prevHash = eventHash;
|
|
88
|
+
}
|
|
89
|
+
// Validation event — per attempt
|
|
90
|
+
if (trans.length > 0) {
|
|
91
|
+
const hasViolations = (attempt.violations || []).length > 0;
|
|
92
|
+
const result = hasViolations ? "failed" : "passed";
|
|
93
|
+
const eventHash = hashEvent(events.length, "validation", `${trans.length} transitions`, prevHash, ts, result);
|
|
94
|
+
events.push({
|
|
95
|
+
index: events.length,
|
|
96
|
+
step: "validation",
|
|
97
|
+
timestamp: ts,
|
|
98
|
+
actor: attempt.plannerSeed?.includes("fallback") ? "planner" : "validator",
|
|
99
|
+
artifact: `${trans.length} transitions`,
|
|
100
|
+
hash: eventHash,
|
|
101
|
+
prevHash,
|
|
102
|
+
result: result,
|
|
103
|
+
detail: hasViolations
|
|
104
|
+
? `${attempt.violations.length} violation(s): ${attempt.violations.map((v) => v.description).join("; ")}`
|
|
105
|
+
: "All constraints satisfied",
|
|
106
|
+
});
|
|
107
|
+
prevHash = eventHash;
|
|
108
|
+
}
|
|
109
|
+
// Repair events
|
|
110
|
+
if (attempt.outcome === "constraint_violation" && attempt.violations?.length > 0) {
|
|
111
|
+
for (const v of attempt.violations || []) {
|
|
112
|
+
const eventHash = hashEvent(events.length, "repair", v.violatedConstraint || "unknown", prevHash, ts, "repaired");
|
|
113
|
+
events.push({
|
|
114
|
+
index: events.length,
|
|
115
|
+
step: "repair",
|
|
116
|
+
timestamp: ts,
|
|
117
|
+
actor: "planner",
|
|
118
|
+
artifact: v.violatedConstraint || "unknown",
|
|
119
|
+
hash: eventHash,
|
|
120
|
+
prevHash,
|
|
121
|
+
result: "repaired",
|
|
122
|
+
detail: `SVL-${v.svl || "?"}: ${v.description || ""}`,
|
|
123
|
+
});
|
|
124
|
+
prevHash = eventHash;
|
|
125
|
+
repairCount++;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
allTransitions = allTransitions.concat(trans);
|
|
129
|
+
}
|
|
130
|
+
// Deploy event (fingerprint registration)
|
|
131
|
+
let storedHash = "";
|
|
132
|
+
try {
|
|
133
|
+
const { getFingerprint } = require("../ledger-registry");
|
|
134
|
+
const fp = getFingerprint(session.sessionId);
|
|
135
|
+
if (fp) {
|
|
136
|
+
storedHash = fp.ledgerHash || "";
|
|
137
|
+
const ts = new Date(fp.timestamp || Date.now()).toISOString();
|
|
138
|
+
const eventHash = hashEvent(events.length, "deploy", `fingerprint: ${fp.ledgerHash?.slice(0, 12)}`, prevHash, ts, "approved");
|
|
139
|
+
events.push({
|
|
140
|
+
index: events.length,
|
|
141
|
+
step: "deploy",
|
|
142
|
+
timestamp: ts,
|
|
143
|
+
actor: "system",
|
|
144
|
+
artifact: `fingerprint: ${fp.ledgerHash?.slice(0, 12)}`,
|
|
145
|
+
hash: eventHash,
|
|
146
|
+
prevHash,
|
|
147
|
+
result: "approved",
|
|
148
|
+
detail: `${fp.transitionCount} transitions registered`,
|
|
149
|
+
});
|
|
150
|
+
prevHash = eventHash;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch { /* no fingerprint */ }
|
|
154
|
+
// Compute chain hash — root hash covering all events
|
|
155
|
+
const chainHash = computeChainHash(events);
|
|
156
|
+
// Compute integrity: check both fingerprint match and chain self-consistency
|
|
157
|
+
const finalHash = shortHash(JSON.stringify(allTransitions));
|
|
158
|
+
const fingerprintMatch = !storedHash || storedHash === finalHash;
|
|
159
|
+
// Self-check: recompute chain and verify it matches
|
|
160
|
+
let chainSelfCheck = true;
|
|
161
|
+
let checkPrev = "";
|
|
162
|
+
for (const e of events) {
|
|
163
|
+
const recomputed = hashEvent(e.index, e.step, e.artifact, checkPrev, e.timestamp, e.result);
|
|
164
|
+
if (recomputed !== e.hash) {
|
|
165
|
+
chainSelfCheck = false;
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
checkPrev = e.hash;
|
|
169
|
+
}
|
|
170
|
+
const integrity = fingerprintMatch && chainSelfCheck ? "intact" : "broken";
|
|
171
|
+
const validTrans = allTransitions.filter((t) => t.valid !== false).length;
|
|
172
|
+
return {
|
|
173
|
+
sessionId: session.sessionId,
|
|
174
|
+
intent: session.intent || "",
|
|
175
|
+
events,
|
|
176
|
+
chainHash,
|
|
177
|
+
integrity,
|
|
178
|
+
finalLedgerHash: finalHash,
|
|
179
|
+
storedFingerprintHash: storedHash,
|
|
180
|
+
totalTransitions: allTransitions.length,
|
|
181
|
+
validTransitions: validTrans,
|
|
182
|
+
invalidTransitions: allTransitions.length - validTrans,
|
|
183
|
+
repairCount,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase 9-10: Provenance & Accountability CLI
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx ts-node src/ledger/cli.ts replay <sessionId>
|
|
7
|
+
* npx ts-node src/ledger/cli.ts accountability <sessionId>
|
|
8
|
+
* npx ts-node src/ledger/cli.ts accountability <sessionId> --author alice@example.com
|
|
9
|
+
* npx ts-node src/ledger/cli.ts --json replay <sessionId>
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const chain_builder_1 = require("./chain-builder");
|
|
13
|
+
const accountability_1 = require("./accountability");
|
|
14
|
+
const C = {
|
|
15
|
+
reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m",
|
|
16
|
+
green: "\x1b[32m", red: "\x1b[31m", cyan: "\x1b[36m",
|
|
17
|
+
yellow: "\x1b[33m", magenta: "\x1b[35m", blue: "\x1b[34m",
|
|
18
|
+
};
|
|
19
|
+
const args = process.argv.slice(2);
|
|
20
|
+
// ── Help ──
|
|
21
|
+
if (args.includes("--help") || args.includes("-h") || args.length === 0) {
|
|
22
|
+
console.log(`
|
|
23
|
+
Progmune Provenance & Accountability CLI
|
|
24
|
+
|
|
25
|
+
Usage:
|
|
26
|
+
npx ts-node src/ledger/cli.ts replay <sessionId>
|
|
27
|
+
npx ts-node src/ledger/cli.ts accountability <sessionId> [options]
|
|
28
|
+
|
|
29
|
+
Options (accountability):
|
|
30
|
+
--author <email> Human who initiated generation
|
|
31
|
+
--reviewer <email> Human who reviewed (repeatable)
|
|
32
|
+
--approver <email> Human who approved deployment
|
|
33
|
+
--deployer <id> CI/CD system that deployed
|
|
34
|
+
--json Output as JSON
|
|
35
|
+
|
|
36
|
+
Examples:
|
|
37
|
+
npx ts-node src/ledger/cli.ts replay sess_abc123
|
|
38
|
+
npx ts-node src/ledger/cli.ts accountability sess_abc123
|
|
39
|
+
npx ts-node src/ledger/cli.ts accountability sess_abc123 \\
|
|
40
|
+
--author alice@example.com --reviewer bob@example.com --deployer github-actions
|
|
41
|
+
`);
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
// ── Parse ──
|
|
45
|
+
const useJson = args.includes("--json");
|
|
46
|
+
const cmd = args[0]; // "replay" | "accountability"
|
|
47
|
+
const sessionId = args[1]?.startsWith("--") ? undefined : args[1];
|
|
48
|
+
// Parse actor options
|
|
49
|
+
function parseHumanOpt(flag) {
|
|
50
|
+
const idx = args.indexOf(flag);
|
|
51
|
+
if (idx < 0 || !args[idx + 1] || args[idx + 1].startsWith("--"))
|
|
52
|
+
return undefined;
|
|
53
|
+
const email = args[idx + 1];
|
|
54
|
+
return { id: email, name: email.split("@")[0], role: flag.slice(2) };
|
|
55
|
+
}
|
|
56
|
+
const author = parseHumanOpt("--author");
|
|
57
|
+
const reviewer = parseHumanOpt("--reviewer");
|
|
58
|
+
const approver = parseHumanOpt("--approver");
|
|
59
|
+
const deployerOpt = (() => {
|
|
60
|
+
const idx = args.indexOf("--deployer");
|
|
61
|
+
if (idx < 0 || !args[idx + 1])
|
|
62
|
+
return undefined;
|
|
63
|
+
const id = args[idx + 1];
|
|
64
|
+
return { id, name: id };
|
|
65
|
+
})();
|
|
66
|
+
// ── Dispatch ──
|
|
67
|
+
if (cmd === "replay") {
|
|
68
|
+
if (!sessionId) {
|
|
69
|
+
console.error("❌ sessionId required");
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const chain = (0, chain_builder_1.buildProvenanceChain)(sessionId);
|
|
74
|
+
console.log(useJson ? JSON.stringify(chain, null, 2) : formatProvenanceChain(chain));
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
console.error(`❌ ${e.message}`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else if (cmd === "accountability") {
|
|
82
|
+
if (!sessionId) {
|
|
83
|
+
console.error("❌ sessionId required");
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
const chain = (0, accountability_1.buildAccountabilityChain)(sessionId, {
|
|
88
|
+
author,
|
|
89
|
+
reviewers: reviewer ? [reviewer] : undefined,
|
|
90
|
+
approver,
|
|
91
|
+
deployer: deployerOpt,
|
|
92
|
+
});
|
|
93
|
+
if (useJson) {
|
|
94
|
+
console.log(JSON.stringify(chain, null, 2));
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
console.log(formatAccountabilityChain(chain));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
console.error(`❌ ${e.message}`);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
console.error(`❌ Unknown command: ${cmd}. Use "replay" or "accountability".`);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
// ═══════════════════════════════════════════════════════════════
|
|
110
|
+
// Provenance Chain Formatter
|
|
111
|
+
// ═══════════════════════════════════════════════════════════════
|
|
112
|
+
function stepLabel(step) {
|
|
113
|
+
const labels = {
|
|
114
|
+
generation: `${C.cyan}gen${C.reset} `,
|
|
115
|
+
validation: `${C.yellow}val${C.reset} `,
|
|
116
|
+
repair: `${C.red}repair${C.reset} `,
|
|
117
|
+
approval: `${C.green}approve${C.reset} `,
|
|
118
|
+
deploy: `${C.bold}deploy${C.reset} `,
|
|
119
|
+
};
|
|
120
|
+
return labels[step] || step.padEnd(8);
|
|
121
|
+
}
|
|
122
|
+
function resultIcon(r) {
|
|
123
|
+
if (r === "passed" || r === "approved")
|
|
124
|
+
return `${C.green}✓${C.reset}`;
|
|
125
|
+
if (r === "failed")
|
|
126
|
+
return `${C.red}✗${C.reset}`;
|
|
127
|
+
return `${C.yellow}↻${C.reset}`;
|
|
128
|
+
}
|
|
129
|
+
function formatProvenanceChain(chain) {
|
|
130
|
+
const lines = [];
|
|
131
|
+
lines.push("");
|
|
132
|
+
lines.push(`${C.bold}${C.cyan}Provenance Chain${C.reset}`);
|
|
133
|
+
lines.push(` Session: ${chain.sessionId}`);
|
|
134
|
+
lines.push(` Intent: ${chain.intent}`);
|
|
135
|
+
lines.push(` Integrity: ${chain.integrity === "intact" ? `${C.green}INTACT${C.reset}` : `${C.red}BROKEN${C.reset}`}`);
|
|
136
|
+
lines.push(` Chain hash: ${C.bold}${chain.chainHash}${C.reset} ${C.dim}(root — tampering breaks this)${C.reset}`);
|
|
137
|
+
lines.push(` Ledger: ${chain.finalLedgerHash} (stored: ${chain.storedFingerprintHash || "none"})`);
|
|
138
|
+
lines.push(` Stats: ${chain.totalTransitions} transitions (${chain.validTransitions} valid, ${chain.invalidTransitions} invalid), ${chain.repairCount} repairs`);
|
|
139
|
+
lines.push("");
|
|
140
|
+
lines.push(` ${C.dim}idx step result artifact eventHash prevHash${C.reset}`);
|
|
141
|
+
lines.push(` ${C.dim}─── ──────── ────── ──────────────────────────── ──────────────── ────────────────${C.reset}`);
|
|
142
|
+
for (let i = 0; i < chain.events.length; i++) {
|
|
143
|
+
const e = chain.events[i];
|
|
144
|
+
const prev = e.prevHash ? e.prevHash.slice(0, 14) : "· (genesis)";
|
|
145
|
+
lines.push(` ${String(i).padStart(2, "0")} ${stepLabel(e.step)} ${resultIcon(e.result)} ${e.artifact.padEnd(28).slice(0, 28)} ${e.hash} ${C.dim}←${prev}${C.reset}`);
|
|
146
|
+
if (e.detail)
|
|
147
|
+
lines.push(` ${C.dim}${e.detail.slice(0, 80)}${C.reset}`);
|
|
148
|
+
}
|
|
149
|
+
lines.push("");
|
|
150
|
+
lines.push(` ${C.dim}Chain: ${chain.events.map(e => e.hash).join(" → ")}${C.reset}`);
|
|
151
|
+
lines.push(` ${C.dim}Root: ${chain.chainHash}${C.reset}`);
|
|
152
|
+
lines.push("");
|
|
153
|
+
return lines.join("\n");
|
|
154
|
+
}
|
|
155
|
+
// ═══════════════════════════════════════════════════════════════
|
|
156
|
+
// Accountability Chain Formatter
|
|
157
|
+
// ═══════════════════════════════════════════════════════════════
|
|
158
|
+
function actorTypeIcon(t) {
|
|
159
|
+
const icons = {
|
|
160
|
+
human: `${C.blue}👤${C.reset}`,
|
|
161
|
+
llm: `${C.magenta}🤖${C.reset}`,
|
|
162
|
+
validator: `${C.cyan}⚙${C.reset}`,
|
|
163
|
+
reviewer: `${C.green}✅${C.reset}`,
|
|
164
|
+
deployer: `${C.bold}🚀${C.reset}`,
|
|
165
|
+
};
|
|
166
|
+
return icons[t] || " ";
|
|
167
|
+
}
|
|
168
|
+
function formatAccountabilityChain(chain) {
|
|
169
|
+
const lines = [];
|
|
170
|
+
const integrityIcon = chain.integrity === "intact"
|
|
171
|
+
? `${C.green}INTACT${C.reset}`
|
|
172
|
+
: `${C.red}BROKEN${C.reset}`;
|
|
173
|
+
const custodyIcon = chain.custodyGap
|
|
174
|
+
? `${C.yellow}⚠ GAPS DETECTED${C.reset}`
|
|
175
|
+
: `${C.green}VERIFIED${C.reset}`;
|
|
176
|
+
lines.push("");
|
|
177
|
+
lines.push(`${C.bold}${C.cyan}╔══════════════════════════════════════════════════════════════╗${C.reset}`);
|
|
178
|
+
lines.push(`${C.bold}${C.cyan}║${C.reset} ${C.bold}Accountability Ledger — AI Code Supply Chain${C.reset} ${C.bold}${C.cyan}║${C.reset}`);
|
|
179
|
+
lines.push(`${C.bold}${C.cyan}╚══════════════════════════════════════════════════════════════╝${C.reset}`);
|
|
180
|
+
lines.push("");
|
|
181
|
+
lines.push(` Session: ${chain.sessionId}`);
|
|
182
|
+
lines.push(` Intent: ${chain.intent}`);
|
|
183
|
+
lines.push(` Chain hash: ${C.bold}${chain.chainHash}${C.reset}`);
|
|
184
|
+
lines.push(` Integrity: ${integrityIcon}`);
|
|
185
|
+
lines.push(` Custody: ${custodyIcon}`);
|
|
186
|
+
const signed = chain.events.filter(e => e.signature).length;
|
|
187
|
+
const sigIcon = signed > 0 ? `${C.green}${signed} signed${C.reset}` : `${C.dim}unsigned${C.reset}`;
|
|
188
|
+
lines.push(` Signatures: ${sigIcon} / ${chain.totalEvents} events`);
|
|
189
|
+
lines.push(` Actors: ${C.blue}${chain.humanEvents} human${C.reset} ${C.magenta}${chain.aiEvents} AI${C.reset} ${C.cyan}${chain.automatedEvents} automated${C.reset}`);
|
|
190
|
+
lines.push("");
|
|
191
|
+
// Chain visualization
|
|
192
|
+
lines.push(` ${C.dim}── AI Code Supply Chain ──${C.reset}`);
|
|
193
|
+
lines.push("");
|
|
194
|
+
for (let i = 0; i < chain.events.length; i++) {
|
|
195
|
+
const e = chain.events[i];
|
|
196
|
+
const icon = actorTypeIcon(e.actorType);
|
|
197
|
+
const actorColor = e.actorType === "human" || e.actorType === "reviewer" ? C.blue
|
|
198
|
+
: e.actorType === "llm" ? C.magenta : C.cyan;
|
|
199
|
+
lines.push(` ${String(i).padStart(2, "0")} ${icon} ${actorColor}${e.actorLabel.padEnd(38).slice(0, 38)}${C.reset} ${resultIcon(e.result)} ${e.action.slice(0, 30)}`);
|
|
200
|
+
lines.push(` ${C.dim}hash: ${e.hash} ← ${e.prevHash ? e.prevHash.slice(0, 14) : "genesis"}${C.reset}`);
|
|
201
|
+
// Connector between events
|
|
202
|
+
if (i < chain.events.length - 1) {
|
|
203
|
+
const nextType = chain.events[i + 1].actorType;
|
|
204
|
+
const connector = e.actorType !== nextType
|
|
205
|
+
? `${C.yellow} │ responsibility handoff${C.reset}`
|
|
206
|
+
: `${C.dim} │${C.reset}`;
|
|
207
|
+
lines.push(connector);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
lines.push("");
|
|
211
|
+
// Custody gap warning
|
|
212
|
+
if (chain.custodyGap) {
|
|
213
|
+
lines.push(` ${C.yellow}⚠️ Custody gaps detected — some actors could not be verified.${C.reset}`);
|
|
214
|
+
lines.push(` ${C.dim}→ Use --author, --reviewer, --approver flags to identify human actors.${C.reset}`);
|
|
215
|
+
lines.push("");
|
|
216
|
+
}
|
|
217
|
+
// Root hash
|
|
218
|
+
lines.push(` ${C.dim}Root: ${chain.chainHash}${C.reset}`);
|
|
219
|
+
lines.push(` ${C.dim}${chain.totalEvents} events · ${chain.humanEvents} human · ${chain.aiEvents} AI · ${chain.automatedEvents} automated${C.reset}`);
|
|
220
|
+
lines.push("");
|
|
221
|
+
return lines.join("\n");
|
|
222
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase 9-10: Ledger Module
|
|
4
|
+
*
|
|
5
|
+
* Public API for provenance tracking and accountability.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.verifyAccountabilityChain = exports.buildAccountabilityChain = exports.buildProvenanceChain = void 0;
|
|
9
|
+
var chain_builder_1 = require("./chain-builder");
|
|
10
|
+
Object.defineProperty(exports, "buildProvenanceChain", { enumerable: true, get: function () { return chain_builder_1.buildProvenanceChain; } });
|
|
11
|
+
var accountability_1 = require("./accountability");
|
|
12
|
+
Object.defineProperty(exports, "buildAccountabilityChain", { enumerable: true, get: function () { return accountability_1.buildAccountabilityChain; } });
|
|
13
|
+
Object.defineProperty(exports, "verifyAccountabilityChain", { enumerable: true, get: function () { return accountability_1.verifyAccountabilityChain; } });
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase 12: Ed25519 Signatures for Accountability Events
|
|
4
|
+
*
|
|
5
|
+
* Cryptographic proof that a specific actor performed a specific action.
|
|
6
|
+
* Uses Node.js built-in crypto (Ed25519 since Node 12+).
|
|
7
|
+
*
|
|
8
|
+
* Each actor has a key pair. Events are signed by the actor's private key.
|
|
9
|
+
* Verification proves: "actor X signed event Y at time Z".
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
+
}) : function(o, v) {
|
|
25
|
+
o["default"] = v;
|
|
26
|
+
});
|
|
27
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
28
|
+
var ownKeys = function(o) {
|
|
29
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
30
|
+
var ar = [];
|
|
31
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
32
|
+
return ar;
|
|
33
|
+
};
|
|
34
|
+
return ownKeys(o);
|
|
35
|
+
};
|
|
36
|
+
return function (mod) {
|
|
37
|
+
if (mod && mod.__esModule) return mod;
|
|
38
|
+
var result = {};
|
|
39
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
40
|
+
__setModuleDefault(result, mod);
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
})();
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.generateKeyPair = generateKeyPair;
|
|
46
|
+
exports.loadPublicKey = loadPublicKey;
|
|
47
|
+
exports.hasKey = hasKey;
|
|
48
|
+
exports.ensureKey = ensureKey;
|
|
49
|
+
exports.signEvent = signEvent;
|
|
50
|
+
exports.verifySignature = verifySignature;
|
|
51
|
+
exports.buildSignPayload = buildSignPayload;
|
|
52
|
+
exports.trySign = trySign;
|
|
53
|
+
const crypto = __importStar(require("crypto"));
|
|
54
|
+
const fs = __importStar(require("fs"));
|
|
55
|
+
const path = __importStar(require("path"));
|
|
56
|
+
// ═══════════════════════════════════════════════════════════════
|
|
57
|
+
// Key Management
|
|
58
|
+
// ═══════════════════════════════════════════════════════════════
|
|
59
|
+
const KEYS_DIR = ".progmune_keys";
|
|
60
|
+
function keysDir() {
|
|
61
|
+
const projectDir = process.env.PROGMUNE_PROJECT_DIR || process.cwd();
|
|
62
|
+
return path.resolve(projectDir, KEYS_DIR);
|
|
63
|
+
}
|
|
64
|
+
function keyPath(actorId) {
|
|
65
|
+
return path.join(keysDir(), `${sanitizeFilename(actorId)}.json`);
|
|
66
|
+
}
|
|
67
|
+
function sanitizeFilename(id) {
|
|
68
|
+
return id.replace(/[^a-zA-Z0-9_@.-]/g, "_").slice(0, 64);
|
|
69
|
+
}
|
|
70
|
+
/** Generate a new Ed25519 key pair for an actor */
|
|
71
|
+
function generateKeyPair(actorId, actorType) {
|
|
72
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync("ed25519", {
|
|
73
|
+
publicKeyEncoding: { type: "spki", format: "der" },
|
|
74
|
+
privateKeyEncoding: { type: "pkcs8", format: "der" },
|
|
75
|
+
});
|
|
76
|
+
const kp = {
|
|
77
|
+
publicKey: publicKey.toString("hex"),
|
|
78
|
+
privateKey: privateKey.toString("hex"),
|
|
79
|
+
actorId,
|
|
80
|
+
actorType,
|
|
81
|
+
createdAt: new Date().toISOString(),
|
|
82
|
+
};
|
|
83
|
+
// Auto-save to .progmune_keys/
|
|
84
|
+
const dir = keysDir();
|
|
85
|
+
if (!fs.existsSync(dir))
|
|
86
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
87
|
+
// Only save public info + type; private key stored separately
|
|
88
|
+
fs.writeFileSync(keyPath(actorId) + ".pub", JSON.stringify({ actorId, actorType, publicKey: kp.publicKey, createdAt: kp.createdAt }, null, 2), "utf-8");
|
|
89
|
+
return kp;
|
|
90
|
+
}
|
|
91
|
+
/** Load public key for an actor */
|
|
92
|
+
function loadPublicKey(actorId) {
|
|
93
|
+
const pubPath = keyPath(actorId) + ".pub";
|
|
94
|
+
try {
|
|
95
|
+
const data = JSON.parse(fs.readFileSync(pubPath, "utf-8"));
|
|
96
|
+
return data.publicKey || null;
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** Check if a key exists for an actor */
|
|
103
|
+
function hasKey(actorId) {
|
|
104
|
+
return loadPublicKey(actorId) !== null;
|
|
105
|
+
}
|
|
106
|
+
/** Load or generate a key for an actor */
|
|
107
|
+
function ensureKey(actorId, actorType) {
|
|
108
|
+
const existingPub = loadPublicKey(actorId);
|
|
109
|
+
if (existingPub) {
|
|
110
|
+
return {
|
|
111
|
+
publicKey: existingPub,
|
|
112
|
+
privateKey: "", // Private key not stored in .pub file
|
|
113
|
+
actorId,
|
|
114
|
+
actorType,
|
|
115
|
+
createdAt: "",
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return generateKeyPair(actorId, actorType);
|
|
119
|
+
}
|
|
120
|
+
// ═══════════════════════════════════════════════════════════════
|
|
121
|
+
// Signing & Verification
|
|
122
|
+
// ═══════════════════════════════════════════════════════════════
|
|
123
|
+
/**
|
|
124
|
+
* Sign a payload with a private key.
|
|
125
|
+
* Returns the hex-encoded Ed25519 signature + public key for verification.
|
|
126
|
+
*/
|
|
127
|
+
function signEvent(payload, privateKey) {
|
|
128
|
+
const privKeyObj = crypto.createPrivateKey({
|
|
129
|
+
key: Buffer.from(privateKey, "hex"),
|
|
130
|
+
format: "der",
|
|
131
|
+
type: "pkcs8",
|
|
132
|
+
});
|
|
133
|
+
const pubKeyObj = crypto.createPublicKey(privKeyObj);
|
|
134
|
+
const pubKeyDer = pubKeyObj.export({ type: "spki", format: "der" });
|
|
135
|
+
const signature = crypto.sign(null, Buffer.from(payload, "utf-8"), privKeyObj);
|
|
136
|
+
return {
|
|
137
|
+
signature: signature.toString("hex"),
|
|
138
|
+
publicKey: pubKeyDer.toString("hex"),
|
|
139
|
+
actorId: "",
|
|
140
|
+
algorithm: "ed25519",
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Verify an Ed25519 signature against a payload and public key.
|
|
145
|
+
*/
|
|
146
|
+
function verifySignature(payload, signature, publicKey) {
|
|
147
|
+
try {
|
|
148
|
+
const pubKeyObj = crypto.createPublicKey({
|
|
149
|
+
key: Buffer.from(publicKey, "hex"),
|
|
150
|
+
format: "der",
|
|
151
|
+
type: "spki",
|
|
152
|
+
});
|
|
153
|
+
const sigBuffer = Buffer.from(signature, "hex");
|
|
154
|
+
const valid = crypto.verify(null, Buffer.from(payload, "utf-8"), pubKeyObj, sigBuffer);
|
|
155
|
+
return {
|
|
156
|
+
valid,
|
|
157
|
+
actorId: "",
|
|
158
|
+
publicKey,
|
|
159
|
+
detail: valid ? undefined : "Signature verification failed — data may have been tampered.",
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
return {
|
|
164
|
+
valid: false,
|
|
165
|
+
actorId: "",
|
|
166
|
+
publicKey,
|
|
167
|
+
detail: `Verification error: ${e.message}`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Build the payload string that gets signed for an accountability event.
|
|
173
|
+
* Deterministic: reconstructable from the event data alone.
|
|
174
|
+
*/
|
|
175
|
+
function buildSignPayload(index, actorId, step, artifact, timestamp, result, prevHash) {
|
|
176
|
+
return `${index}|${actorId}|${step}|${artifact}|${timestamp}|${result}|${prevHash}`;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Sign an event payload using a stored key.
|
|
180
|
+
* Returns the signature string, or undefined if no key available.
|
|
181
|
+
*/
|
|
182
|
+
function trySign(actorId, payload) {
|
|
183
|
+
// In CI, keys are injected via environment variable
|
|
184
|
+
const envKey = process.env[`PROGMUNE_KEY_${sanitizeFilename(actorId).toUpperCase()}`];
|
|
185
|
+
if (envKey) {
|
|
186
|
+
const result = signEvent(payload, envKey);
|
|
187
|
+
result.actorId = actorId;
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
// In local dev, try loading from .progmune_keys/
|
|
191
|
+
// (private keys are not stored by default — user provides them)
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase 9: Ledger Provenance Types
|
|
4
|
+
* Phase 10: Accountability Ledger Types
|
|
5
|
+
*
|
|
6
|
+
* End-to-end provenance + accountability tracking for AI-generated code.
|
|
7
|
+
* Every step identifies WHO acted, not just WHAT happened.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|