progmune-runtime 2.1.5 → 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 +326 -59
- 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,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* P9.2b++: Protocol Security Benchmark — defining a new security category
|
|
4
|
+
*
|
|
5
|
+
* This is NOT just another CVE benchmark. It's the FIRST dataset
|
|
6
|
+
* specifically designed for protocol lifecycle vulnerabilities —
|
|
7
|
+
* missing states, missing edges, and illegal transitions that
|
|
8
|
+
* traditional SAST tools cannot see because they look at code
|
|
9
|
+
* patterns, not state machines.
|
|
10
|
+
*
|
|
11
|
+
* The benchmark measures one thing: can a system detect that a
|
|
12
|
+
* protocol lifecycle has been violated, regardless of how the
|
|
13
|
+
* code is written?
|
|
14
|
+
*
|
|
15
|
+
* Categories:
|
|
16
|
+
* RESOURCE_LEAK: Acquire→Use...no Release
|
|
17
|
+
* AUTH_BYPASS: Action without prior Authentication
|
|
18
|
+
* TRANSACTION_VIOLATION: Begin→...no Commit/Rollback
|
|
19
|
+
* USE_AFTER_FREE: Free→Use (illegal edge)
|
|
20
|
+
* SESSION_VIOLATION: Logout→Access (illegal edge)
|
|
21
|
+
* DOUBLE_FREE: Free→Free (illegal self-loop)
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.buildProtocolSecurityBenchmark = buildProtocolSecurityBenchmark;
|
|
25
|
+
exports.runProtocolSecurityBenchmark = runProtocolSecurityBenchmark;
|
|
26
|
+
exports.printProtocolSecurityReport = printProtocolSecurityReport;
|
|
27
|
+
const gold_cve_1 = require("./gold-cve");
|
|
28
|
+
// ═══════════════════════════════════════════════════════════════
|
|
29
|
+
// Build the benchmark from all available verified cases
|
|
30
|
+
// ═══════════════════════════════════════════════════════════════
|
|
31
|
+
function buildProtocolSecurityBenchmark() {
|
|
32
|
+
const cases = [];
|
|
33
|
+
// Source 1: Curated 20 cases (manually verified against real CVE patterns)
|
|
34
|
+
const curated = (0, gold_cve_1.loadGoldDataset)().cases;
|
|
35
|
+
for (const c of curated) {
|
|
36
|
+
cases.push({
|
|
37
|
+
id: c.id,
|
|
38
|
+
category: c.category,
|
|
39
|
+
severity: c.severity,
|
|
40
|
+
broken: c.broken,
|
|
41
|
+
expected: c.expected,
|
|
42
|
+
source: "curated",
|
|
43
|
+
verified: true,
|
|
44
|
+
notes: c.notes,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
// Source 2: Diff-based gold cases (from real git diffs)
|
|
48
|
+
try {
|
|
49
|
+
const fs = require("fs");
|
|
50
|
+
const path = require("path");
|
|
51
|
+
const seedPath = path.resolve(__dirname, "..", "benchmarks", "gold-seed.json");
|
|
52
|
+
if (fs.existsSync(seedPath)) {
|
|
53
|
+
const seed = JSON.parse(fs.readFileSync(seedPath, "utf-8"));
|
|
54
|
+
for (const c of seed) {
|
|
55
|
+
cases.push({
|
|
56
|
+
id: `GOLD-${c.cve}`,
|
|
57
|
+
category: c.category,
|
|
58
|
+
severity: c.severity || "high",
|
|
59
|
+
broken: c.before,
|
|
60
|
+
expected: c.after,
|
|
61
|
+
source: "git_diff",
|
|
62
|
+
verified: true,
|
|
63
|
+
notes: c.notes,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch { }
|
|
69
|
+
// Source 3: Synthetic cases from topology factory (for stress testing)
|
|
70
|
+
// These are NOT verified — marked accordingly
|
|
71
|
+
const generateSyntheticCases = () => {
|
|
72
|
+
const { createProtocolForTopology, ALL_TOPOLOGIES } = require("./topology-factory");
|
|
73
|
+
const synthetic = [];
|
|
74
|
+
let id = 200;
|
|
75
|
+
for (const topo of ALL_TOPOLOGIES) {
|
|
76
|
+
const rules = createProtocolForTopology(topo);
|
|
77
|
+
if (rules.size < 2)
|
|
78
|
+
continue;
|
|
79
|
+
const entries = [...rules.entries()];
|
|
80
|
+
for (let v = 0; v < 3 && synthetic.length < 30; v++) {
|
|
81
|
+
const path = [];
|
|
82
|
+
const ss = new Set(["INIT", "IDLE"]);
|
|
83
|
+
const s = entries[Math.floor(Math.random() * entries.length)];
|
|
84
|
+
path.push(s[0]);
|
|
85
|
+
const r = s[1];
|
|
86
|
+
if (r.invalidate)
|
|
87
|
+
r.invalidate.forEach((x) => ss.delete(x));
|
|
88
|
+
for (const x of r.post_states)
|
|
89
|
+
ss.add(x);
|
|
90
|
+
for (let t = 0; t < 4; t++) {
|
|
91
|
+
const cands = entries.filter(([, rr]) => rr.pre_states.every((x) => ss.has(x)));
|
|
92
|
+
if (!cands.length)
|
|
93
|
+
break;
|
|
94
|
+
const [fn, nr] = cands[Math.floor(Math.random() * cands.length)];
|
|
95
|
+
path.push(fn);
|
|
96
|
+
if (nr.invalidate)
|
|
97
|
+
nr.invalidate.forEach((x) => ss.delete(x));
|
|
98
|
+
for (const x of nr.post_states)
|
|
99
|
+
ss.add(x);
|
|
100
|
+
}
|
|
101
|
+
if (path.length < 3)
|
|
102
|
+
continue;
|
|
103
|
+
synthetic.push({
|
|
104
|
+
id: `SYN-${id++}`,
|
|
105
|
+
category: "resource_leak",
|
|
106
|
+
severity: "medium",
|
|
107
|
+
broken: path.slice(0, -1),
|
|
108
|
+
expected: path,
|
|
109
|
+
source: "synthetic",
|
|
110
|
+
verified: false,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return synthetic;
|
|
115
|
+
};
|
|
116
|
+
try {
|
|
117
|
+
cases.push(...generateSyntheticCases());
|
|
118
|
+
}
|
|
119
|
+
catch { }
|
|
120
|
+
// Build metadata
|
|
121
|
+
const byCategory = {};
|
|
122
|
+
const bySource = {};
|
|
123
|
+
let verified = 0;
|
|
124
|
+
for (const c of cases) {
|
|
125
|
+
byCategory[c.category] = (byCategory[c.category] || 0) + 1;
|
|
126
|
+
bySource[c.source] = (bySource[c.source] || 0) + 1;
|
|
127
|
+
if (c.verified)
|
|
128
|
+
verified++;
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
name: "Protocol Lifecycle Security Benchmark",
|
|
132
|
+
version: "1.0.0",
|
|
133
|
+
cases,
|
|
134
|
+
metadata: { total: cases.length, verified, byCategory, bySource },
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function runProtocolSecurityBenchmark() {
|
|
138
|
+
const bench = buildProtocolSecurityBenchmark();
|
|
139
|
+
const { inferStateMachine } = require("./experimental/state-inference");
|
|
140
|
+
const { detectStructuralViolations } = require("./protocol-invariants");
|
|
141
|
+
const CWE_TO_VIOLATION = {
|
|
142
|
+
resource_leak: "missing_release",
|
|
143
|
+
auth_bypass: "missing_prerequisite",
|
|
144
|
+
data_corruption: "missing_commit",
|
|
145
|
+
use_after_free: "illegal_transition",
|
|
146
|
+
race_condition: "missing_prerequisite",
|
|
147
|
+
};
|
|
148
|
+
const byCat = {};
|
|
149
|
+
let totalDetected = 0, totalMatched = 0;
|
|
150
|
+
let verifiedDetected = 0, verifiedTotal = 0;
|
|
151
|
+
for (const c of bench.cases) {
|
|
152
|
+
if (!byCat[c.category])
|
|
153
|
+
byCat[c.category] = { total: 0, verified: 0, detected: 0, matched: 0 };
|
|
154
|
+
byCat[c.category].total++;
|
|
155
|
+
if (c.verified) {
|
|
156
|
+
byCat[c.category].verified++;
|
|
157
|
+
verifiedTotal++;
|
|
158
|
+
}
|
|
159
|
+
const templateSM = inferStateMachine([c.expected]);
|
|
160
|
+
const brokenSM = inferStateMachine([c.broken]);
|
|
161
|
+
const violations = detectStructuralViolations(brokenSM, templateSM);
|
|
162
|
+
const violationTypes = violations.map((v) => v.violationSubtype);
|
|
163
|
+
const detected = violations.length > 0;
|
|
164
|
+
const expectedV = CWE_TO_VIOLATION[c.category] || "";
|
|
165
|
+
const matched = expectedV ? violationTypes.includes(expectedV) : false;
|
|
166
|
+
if (detected) {
|
|
167
|
+
totalDetected++;
|
|
168
|
+
byCat[c.category].detected++;
|
|
169
|
+
if (c.verified)
|
|
170
|
+
verifiedDetected++;
|
|
171
|
+
}
|
|
172
|
+
if (matched) {
|
|
173
|
+
totalMatched++;
|
|
174
|
+
byCat[c.category].matched++;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const total = bench.cases.length;
|
|
178
|
+
const overallRecall = total > 0 ? totalDetected / total : 0;
|
|
179
|
+
const overallPrecision = totalDetected > 0 ? totalMatched / totalDetected : 0;
|
|
180
|
+
const verifiedRecall = verifiedTotal > 0 ? verifiedDetected / verifiedTotal : 0;
|
|
181
|
+
const verifiedPrecision = verifiedTotal > 0 ? totalMatched / Math.max(1, totalDetected) : 0;
|
|
182
|
+
const parserGap = verifiedRecall - overallRecall;
|
|
183
|
+
const categoryBreakdown = {};
|
|
184
|
+
for (const [cat, s] of Object.entries(byCat)) {
|
|
185
|
+
categoryBreakdown[cat] = {
|
|
186
|
+
total: s.total, verified: s.verified,
|
|
187
|
+
detected: s.detected, matched: s.matched,
|
|
188
|
+
recall: s.total > 0 ? s.detected / s.total : 0,
|
|
189
|
+
precision: s.detected > 0 ? s.matched / s.detected : 0,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
benchmark: bench.name,
|
|
194
|
+
totalCases: total,
|
|
195
|
+
verifiedCases: verifiedTotal,
|
|
196
|
+
overallRecall, overallPrecision,
|
|
197
|
+
byCategory: categoryBreakdown,
|
|
198
|
+
verifiedOnly: { total: verifiedTotal, detected: verifiedDetected, recall: verifiedRecall, precision: verifiedPrecision },
|
|
199
|
+
parserNoiseGap: parserGap,
|
|
200
|
+
verdict: verifiedRecall > 0.85
|
|
201
|
+
? "✅ PROTOCOL LIFECYCLE SECURITY — verified performance exceeds 85%"
|
|
202
|
+
: verifiedRecall > 0.7
|
|
203
|
+
? "⚠️ PROMISING — verified recall >70%, needs more cases"
|
|
204
|
+
: "❌ INSUFFICIENT — core detector performance below threshold",
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function printProtocolSecurityReport(report) {
|
|
208
|
+
console.log(`\n╔════════════════════════════════════════════════════╗`);
|
|
209
|
+
console.log(`║ ${report.benchmark}`);
|
|
210
|
+
console.log(`║ ${report.totalCases} cases (${report.verifiedCases} manually verified)`);
|
|
211
|
+
console.log(`╚════════════════════════════════════════════════════╝\n`);
|
|
212
|
+
console.log(` Overall: recall ${(report.overallRecall * 100).toFixed(0)}% precision ${(report.overallPrecision * 100).toFixed(0)}%`);
|
|
213
|
+
console.log(` Verified: recall ${(report.verifiedOnly.recall * 100).toFixed(0)}% precision ${(report.verifiedOnly.precision * 100).toFixed(0)}%`);
|
|
214
|
+
console.log(` Parser gap: ${(report.parserNoiseGap * 100).toFixed(0)}% (noise in CVE→sequence conversion)`);
|
|
215
|
+
console.log();
|
|
216
|
+
console.log(` ── Per Category ──`);
|
|
217
|
+
for (const [cat, s] of Object.entries(report.byCategory)) {
|
|
218
|
+
const vMark = s.verified > 0 ? ` (${s.verified} verified)` : "";
|
|
219
|
+
console.log(` ${cat.padEnd(22)} ${String(s.total).padStart(3)} cases${vMark.padEnd(14)} recall ${(s.recall * 100).toFixed(0).padStart(3)}% precision ${(s.precision * 100).toFixed(0)}%`);
|
|
220
|
+
}
|
|
221
|
+
console.log(`\n Verdict: ${report.verdict}\n`);
|
|
222
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* P9.0: Protocol Structure → Vulnerability Prediction
|
|
4
|
+
*
|
|
5
|
+
* THE decisive question: does protocol TOPOLOGY carry enough information
|
|
6
|
+
* to predict defects WITHOUT seeing function names, code, or comments?
|
|
7
|
+
*
|
|
8
|
+
* If yes: protocol structure contains security information.
|
|
9
|
+
* If no: structure is real but semantically empty.
|
|
10
|
+
*
|
|
11
|
+
* Experiment design:
|
|
12
|
+
* 1. For each of 10 topologies, generate CLEAN (complete) and BROKEN
|
|
13
|
+
* (missing-step, wrong-order) sequences
|
|
14
|
+
* 2. Extract WL fingerprints from both
|
|
15
|
+
* 3. Train a simple nearest-centroid classifier on 7 topologies
|
|
16
|
+
* 4. Test zero-shot on 3 held-out topologies
|
|
17
|
+
* 5. Measure: precision, recall, F1 on held-out set
|
|
18
|
+
*
|
|
19
|
+
* Baseline: random guess = 50% (binary classification: clean/broken)
|
|
20
|
+
* Target: >70% F1 on held-out topologies
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.buildWLDefectDataset = buildWLDefectDataset;
|
|
24
|
+
exports.runZeroShotDefectPrediction = runZeroShotDefectPrediction;
|
|
25
|
+
exports.printDefectReport = printDefectReport;
|
|
26
|
+
const topology_factory_1 = require("./topology-factory");
|
|
27
|
+
const state_inference_1 = require("./experimental/state-inference");
|
|
28
|
+
const wl_fingerprint_1 = require("./wl-fingerprint");
|
|
29
|
+
/**
|
|
30
|
+
* Generate clean sequences (valid random walks through the state machine).
|
|
31
|
+
*/
|
|
32
|
+
function generateCleanSequences(rules, count) {
|
|
33
|
+
const entries = [...rules.entries()];
|
|
34
|
+
const sequences = [];
|
|
35
|
+
for (let i = 0; i < count; i++) {
|
|
36
|
+
const targetLen = 2 + Math.floor(Math.random() * 4); // 2-5 steps
|
|
37
|
+
const path = [];
|
|
38
|
+
const visited = new Set();
|
|
39
|
+
// Start from any rule
|
|
40
|
+
const startIdx = Math.floor(Math.random() * entries.length);
|
|
41
|
+
path.push(entries[startIdx][0]);
|
|
42
|
+
const stateSet = new Set(["INIT", "IDLE"]);
|
|
43
|
+
const rule = entries[startIdx][1];
|
|
44
|
+
if (rule.invalidate)
|
|
45
|
+
rule.invalidate.forEach((s) => stateSet.delete(s));
|
|
46
|
+
for (const s of rule.post_states)
|
|
47
|
+
stateSet.add(s);
|
|
48
|
+
let currentFn = path[0];
|
|
49
|
+
while (path.length < targetLen) {
|
|
50
|
+
const candidates = entries.filter(([fn, r]) => !visited.has(fn) && r.pre_states.every((s) => stateSet.has(s)));
|
|
51
|
+
if (candidates.length === 0)
|
|
52
|
+
break;
|
|
53
|
+
const [nextFn, nextRule] = candidates[Math.floor(Math.random() * candidates.length)];
|
|
54
|
+
path.push(nextFn);
|
|
55
|
+
visited.add(nextFn);
|
|
56
|
+
if (nextRule.invalidate)
|
|
57
|
+
nextRule.invalidate.forEach((s) => stateSet.delete(s));
|
|
58
|
+
for (const s of nextRule.post_states)
|
|
59
|
+
stateSet.add(s);
|
|
60
|
+
currentFn = nextFn;
|
|
61
|
+
}
|
|
62
|
+
if (path.length >= 2)
|
|
63
|
+
sequences.push(path);
|
|
64
|
+
}
|
|
65
|
+
return sequences;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Generate broken sequences by removing a step or inserting a wrong step.
|
|
69
|
+
*
|
|
70
|
+
* Broken variants:
|
|
71
|
+
* 1. REMOVE: drop the last step (incomplete lifecycle)
|
|
72
|
+
* 2. SKIP: skip a middle step (jump over a state)
|
|
73
|
+
*/
|
|
74
|
+
function generateBrokenSequences(rules, count) {
|
|
75
|
+
const clean = generateCleanSequences(rules, Math.ceil(count * 1.5));
|
|
76
|
+
const broken = [];
|
|
77
|
+
for (const seq of clean) {
|
|
78
|
+
if (broken.length >= count)
|
|
79
|
+
break;
|
|
80
|
+
// REMOVE last step (resource leak / missing close / missing commit)
|
|
81
|
+
if (seq.length >= 3) {
|
|
82
|
+
broken.push(seq.slice(0, -1));
|
|
83
|
+
}
|
|
84
|
+
// SKIP: remove a middle step if long enough
|
|
85
|
+
if (seq.length >= 4 && broken.length < count) {
|
|
86
|
+
const mid = 1 + Math.floor(Math.random() * (seq.length - 2));
|
|
87
|
+
broken.push([...seq.slice(0, mid), ...seq.slice(mid + 1)]);
|
|
88
|
+
}
|
|
89
|
+
// WRONG ORDER: swap two adjacent steps
|
|
90
|
+
if (seq.length >= 3 && broken.length < count) {
|
|
91
|
+
const swapIdx = Math.floor(Math.random() * (seq.length - 1));
|
|
92
|
+
const swapped = [...seq];
|
|
93
|
+
[swapped[swapIdx], swapped[swapIdx + 1]] = [swapped[swapIdx + 1], swapped[swapIdx]];
|
|
94
|
+
broken.push(swapped);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return broken.slice(0, count);
|
|
98
|
+
}
|
|
99
|
+
// ═══════════════════════════════════════════════════════════════
|
|
100
|
+
// Dataset construction
|
|
101
|
+
// ═══════════════════════════════════════════════════════════════
|
|
102
|
+
/**
|
|
103
|
+
* Build a labeled dataset of WL fingerprints from protocol topologies.
|
|
104
|
+
*
|
|
105
|
+
* @param topologies Which topologies to include
|
|
106
|
+
* @param perClass Samples per class per topology
|
|
107
|
+
*/
|
|
108
|
+
function buildWLDefectDataset(topologies, perClass = 10) {
|
|
109
|
+
const samples = [];
|
|
110
|
+
for (const topo of topologies) {
|
|
111
|
+
const rules = (0, topology_factory_1.createProtocolForTopology)(topo);
|
|
112
|
+
if (rules.size === 0)
|
|
113
|
+
continue;
|
|
114
|
+
const cleanSeqs = generateCleanSequences(rules, perClass);
|
|
115
|
+
const brokenSeqs = generateBrokenSequences(rules, perClass);
|
|
116
|
+
for (const seq of cleanSeqs) {
|
|
117
|
+
const sm = (0, state_inference_1.inferStateMachine)(seq.map(fn => [fn]));
|
|
118
|
+
const wl = (0, wl_fingerprint_1.extractWLFingerprint)(sm, 3);
|
|
119
|
+
samples.push({ topology: topo, label: "clean", wl });
|
|
120
|
+
}
|
|
121
|
+
for (const seq of brokenSeqs) {
|
|
122
|
+
const sm = (0, state_inference_1.inferStateMachine)(seq.map(fn => [fn]));
|
|
123
|
+
const wl = (0, wl_fingerprint_1.extractWLFingerprint)(sm, 3);
|
|
124
|
+
samples.push({ topology: topo, label: "broken", wl });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return samples;
|
|
128
|
+
}
|
|
129
|
+
// ═══════════════════════════════════════════════════════════════
|
|
130
|
+
// Nearest-centroid classifier (simplest possible, no overfitting risk)
|
|
131
|
+
// ═══════════════════════════════════════════════════════════════
|
|
132
|
+
function meanVector(vectors) {
|
|
133
|
+
const dims = vectors[0].length;
|
|
134
|
+
const mean = new Array(dims).fill(0);
|
|
135
|
+
for (const v of vectors) {
|
|
136
|
+
for (let i = 0; i < dims; i++)
|
|
137
|
+
mean[i] += v[i];
|
|
138
|
+
}
|
|
139
|
+
for (let i = 0; i < dims; i++)
|
|
140
|
+
mean[i] /= vectors.length;
|
|
141
|
+
return mean;
|
|
142
|
+
}
|
|
143
|
+
function cosineSim(a, b) {
|
|
144
|
+
let dot = 0, normA = 0, normB = 0;
|
|
145
|
+
for (let i = 0; i < a.length; i++) {
|
|
146
|
+
dot += a[i] * b[i];
|
|
147
|
+
normA += a[i] * a[i];
|
|
148
|
+
normB += b[i] * b[i];
|
|
149
|
+
}
|
|
150
|
+
if (normA === 0 && normB === 0)
|
|
151
|
+
return 1;
|
|
152
|
+
if (normA === 0 || normB === 0)
|
|
153
|
+
return 0;
|
|
154
|
+
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Train on some topologies, test zero-shot on held-out ones.
|
|
158
|
+
*
|
|
159
|
+
* Uses nearest-centroid: compute the mean WL vector for "clean" and
|
|
160
|
+
* "broken" classes from training topologies, then classify test
|
|
161
|
+
* samples by which centroid is closer.
|
|
162
|
+
*/
|
|
163
|
+
function runZeroShotDefectPrediction(trainTopos, testTopos, samplesPerClass = 10) {
|
|
164
|
+
// Build training set
|
|
165
|
+
const trainSamples = buildWLDefectDataset(trainTopos, samplesPerClass);
|
|
166
|
+
const cleanVectors = trainSamples.filter(s => s.label === "clean").map(s => s.wl.vector);
|
|
167
|
+
const brokenVectors = trainSamples.filter(s => s.label === "broken").map(s => s.wl.vector);
|
|
168
|
+
if (cleanVectors.length === 0 || brokenVectors.length === 0) {
|
|
169
|
+
return {
|
|
170
|
+
trainTopos, testTopos, samples: samplesPerClass,
|
|
171
|
+
accuracy: 0, precision: 0, recall: 0, f1: 0,
|
|
172
|
+
perTopology: {}, confusion: { tp: 0, fp: 0, tn: 0, fn: 0 },
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
// Compute centroids
|
|
176
|
+
const cleanCentroid = meanVector(cleanVectors);
|
|
177
|
+
const brokenCentroid = meanVector(brokenVectors);
|
|
178
|
+
// Test on held-out topologies
|
|
179
|
+
const testSamples = buildWLDefectDataset(testTopos, samplesPerClass);
|
|
180
|
+
let tp = 0, fp = 0, tn = 0, fn = 0;
|
|
181
|
+
const perTopology = {};
|
|
182
|
+
for (const sample of testSamples) {
|
|
183
|
+
const distClean = 1 - cosineSim(sample.wl.vector, cleanCentroid);
|
|
184
|
+
const distBroken = 1 - cosineSim(sample.wl.vector, brokenCentroid);
|
|
185
|
+
const predicted = distClean < distBroken ? "clean" : "broken";
|
|
186
|
+
if (!perTopology[sample.topology]) {
|
|
187
|
+
perTopology[sample.topology] = { correct: 0, total: 0, tp: 0, fp: 0, tn: 0, fn: 0 };
|
|
188
|
+
}
|
|
189
|
+
perTopology[sample.topology].total++;
|
|
190
|
+
if (predicted === sample.label)
|
|
191
|
+
perTopology[sample.topology].correct++;
|
|
192
|
+
if (sample.label === "broken" && predicted === "broken") {
|
|
193
|
+
tp++;
|
|
194
|
+
perTopology[sample.topology].tp++;
|
|
195
|
+
}
|
|
196
|
+
else if (sample.label === "clean" && predicted === "broken") {
|
|
197
|
+
fp++;
|
|
198
|
+
perTopology[sample.topology].fp++;
|
|
199
|
+
}
|
|
200
|
+
else if (sample.label === "clean" && predicted === "clean") {
|
|
201
|
+
tn++;
|
|
202
|
+
perTopology[sample.topology].tn++;
|
|
203
|
+
}
|
|
204
|
+
else if (sample.label === "broken" && predicted === "clean") {
|
|
205
|
+
fn++;
|
|
206
|
+
perTopology[sample.topology].fn++;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
const total = tp + fp + tn + fn;
|
|
210
|
+
const accuracy = total > 0 ? (tp + tn) / total : 0;
|
|
211
|
+
const precision = (tp + fp) > 0 ? tp / (tp + fp) : 0;
|
|
212
|
+
const recall = (tp + fn) > 0 ? tp / (tp + fn) : 0;
|
|
213
|
+
const f1 = (precision + recall) > 0 ? 2 * precision * recall / (precision + recall) : 0;
|
|
214
|
+
return {
|
|
215
|
+
trainTopos, testTopos, samples: samplesPerClass,
|
|
216
|
+
accuracy, precision, recall, f1,
|
|
217
|
+
perTopology: Object.fromEntries(Object.entries(perTopology).map(([k, v]) => [
|
|
218
|
+
k,
|
|
219
|
+
{
|
|
220
|
+
accuracy: v.total > 0 ? v.correct / v.total : 0,
|
|
221
|
+
f1: (v.tp + v.fp + v.fn) > 0
|
|
222
|
+
? 2 * (v.tp / Math.max(1, v.tp + v.fp)) * (v.tp / Math.max(1, v.tp + v.fn))
|
|
223
|
+
/ ((v.tp / Math.max(1, v.tp + v.fp)) + (v.tp / Math.max(1, v.tp + v.fn)))
|
|
224
|
+
: 0,
|
|
225
|
+
},
|
|
226
|
+
])),
|
|
227
|
+
confusion: { tp, fp, tn, fn },
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function printDefectReport(report) {
|
|
231
|
+
console.log("\n╔════════════════════════════════════════════════════╗");
|
|
232
|
+
console.log("║ P9.0 Protocol → Defect Prediction (Zero-Shot) ║");
|
|
233
|
+
console.log("╚════════════════════════════════════════════════════╝\n");
|
|
234
|
+
console.log(` Train: ${report.trainTopos.join(", ")}`);
|
|
235
|
+
console.log(` Test: ${report.testTopos.join(", ")}`);
|
|
236
|
+
console.log(` Samples per topology: ${report.samples}`);
|
|
237
|
+
console.log();
|
|
238
|
+
console.log(` Accuracy: ${(report.accuracy * 100).toFixed(0)}%`);
|
|
239
|
+
console.log(` Precision: ${(report.precision * 100).toFixed(0)}% (broken class)`);
|
|
240
|
+
console.log(` Recall: ${(report.recall * 100).toFixed(0)}% (broken class)`);
|
|
241
|
+
console.log(` F1: ${(report.f1 * 100).toFixed(0)}%`);
|
|
242
|
+
console.log();
|
|
243
|
+
console.log(` Confusion: TP=${report.confusion.tp} FP=${report.confusion.fp} TN=${report.confusion.tn} FN=${report.confusion.fn}`);
|
|
244
|
+
console.log();
|
|
245
|
+
console.log(` Per-topology:`);
|
|
246
|
+
for (const [topo, stats] of Object.entries(report.perTopology)) {
|
|
247
|
+
console.log(` ${topo.padEnd(18)} acc=${(stats.accuracy * 100).toFixed(0)}% f1=${(stats.f1 * 100).toFixed(0)}%`);
|
|
248
|
+
}
|
|
249
|
+
const baseline = 0.5; // random chance
|
|
250
|
+
const improvement = report.f1 - baseline;
|
|
251
|
+
const verdict = report.f1 > 0.7 ? "✅ PROTOCOL STRUCTURE PREDICTS DEFECTS"
|
|
252
|
+
: report.f1 > baseline + 0.1 ? "⚠️ WEAK SIGNAL — above random, below useful"
|
|
253
|
+
: "❌ No predictive power — structure alone insufficient";
|
|
254
|
+
console.log(`\n Baseline (random): 50%`);
|
|
255
|
+
console.log(` Improvement: ${improvement > 0 ? '+' : ''}${(improvement * 100).toFixed(0)}%`);
|
|
256
|
+
console.log(` Verdict: ${verdict}\n`);
|
|
257
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* P9.0: Protocol Structure → Defect Prediction Test
|
|
5
|
+
*
|
|
6
|
+
* THE decisive question: can WL fingerprints of protocol state machines
|
|
7
|
+
* predict whether a sequence has a defect (missing step, wrong order)
|
|
8
|
+
* WITHOUT seeing function names, code, or comments?
|
|
9
|
+
*/
|
|
10
|
+
const vitest_1 = require("vitest");
|
|
11
|
+
const protocol_vulnerability_1 = require("./protocol-vulnerability");
|
|
12
|
+
const topology_factory_1 = require("./topology-factory");
|
|
13
|
+
(0, vitest_1.describe)("P9.0 Protocol → Vulnerability Prediction", () => {
|
|
14
|
+
(0, vitest_1.it)("builds WL defect dataset from protocol topologies", () => {
|
|
15
|
+
const samples = (0, protocol_vulnerability_1.buildWLDefectDataset)(["linear", "star", "loop"], 5);
|
|
16
|
+
(0, vitest_1.expect)(samples.length).toBeGreaterThanOrEqual(20);
|
|
17
|
+
const clean = samples.filter(s => s.label === "clean").length;
|
|
18
|
+
const broken = samples.filter(s => s.label === "broken").length;
|
|
19
|
+
(0, vitest_1.expect)(clean).toBeGreaterThan(0);
|
|
20
|
+
(0, vitest_1.expect)(broken).toBeGreaterThan(0);
|
|
21
|
+
// All samples should have valid WL fingerprints
|
|
22
|
+
for (const s of samples) {
|
|
23
|
+
(0, vitest_1.expect)(s.wl.vector.length).toBe(256);
|
|
24
|
+
(0, vitest_1.expect)(s.wl.uniqueLabels).toBeGreaterThan(0);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
(0, vitest_1.it)("ZERO-SHOT: train on 7 topologies, test on 3 held-out", () => {
|
|
28
|
+
// Leave out 3 topologies for zero-shot testing
|
|
29
|
+
const trainTopos = topology_factory_1.ALL_TOPOLOGIES.slice(0, 7);
|
|
30
|
+
const testTopos = topology_factory_1.ALL_TOPOLOGIES.slice(7);
|
|
31
|
+
const report = (0, protocol_vulnerability_1.runZeroShotDefectPrediction)(trainTopos, testTopos, 10);
|
|
32
|
+
(0, protocol_vulnerability_1.printDefectReport)(report);
|
|
33
|
+
// Must be better than random (50%)
|
|
34
|
+
(0, vitest_1.expect)(report.accuracy).toBeGreaterThan(0.5);
|
|
35
|
+
});
|
|
36
|
+
(0, vitest_1.it)("FULL CROSS-VALIDATION: average over 3 random splits", () => {
|
|
37
|
+
const shuffled = [...topology_factory_1.ALL_TOPOLOGIES].sort(() => Math.random() - 0.5);
|
|
38
|
+
const splits = [
|
|
39
|
+
{ train: shuffled.slice(0, 7), test: shuffled.slice(7) },
|
|
40
|
+
{ train: shuffled.slice(3), test: shuffled.slice(0, 3) },
|
|
41
|
+
{ train: [...shuffled.slice(0, 4), ...shuffled.slice(7)], test: shuffled.slice(4, 7) },
|
|
42
|
+
];
|
|
43
|
+
let totalF1 = 0;
|
|
44
|
+
const results = [];
|
|
45
|
+
for (const { train, test } of splits) {
|
|
46
|
+
const report = (0, protocol_vulnerability_1.runZeroShotDefectPrediction)(train, test, 8);
|
|
47
|
+
totalF1 += report.f1;
|
|
48
|
+
results.push({ testTopos: test, accuracy: report.accuracy, f1: report.f1 });
|
|
49
|
+
}
|
|
50
|
+
const avgF1 = totalF1 / splits.length;
|
|
51
|
+
console.log(`\n ═══ 3-FOLD CROSS-VALIDATION ═══`);
|
|
52
|
+
for (const r of results) {
|
|
53
|
+
console.log(` Test: ${r.testTopos.join(",").padEnd(35)} acc=${(r.accuracy * 100).toFixed(0)}% f1=${(r.f1 * 100).toFixed(0)}%`);
|
|
54
|
+
}
|
|
55
|
+
console.log(` Average F1: ${(avgF1 * 100).toFixed(0)}%`);
|
|
56
|
+
console.log(` Baseline (random): 50%`);
|
|
57
|
+
// Average F1 should exceed random baseline
|
|
58
|
+
(0, vitest_1.expect)(avgF1).toBeGreaterThan(0.5);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase 2: Python Detection Benchmark Runner
|
|
4
|
+
*
|
|
5
|
+
* Runs protocol detection + safeguard detection on Python projects,
|
|
6
|
+
* compares against labeled data, reports Precision/Recall/F1.
|
|
7
|
+
*
|
|
8
|
+
* Usage: npx ts-node src/python-benchmark.ts [projectPath]
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.runPythonBenchmark = runPythonBenchmark;
|
|
45
|
+
exports.loadLabels = loadLabels;
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const sequence_extractor_1 = require("./sequence-extractor");
|
|
49
|
+
const protocol_detector_1 = require("./protocol-detector");
|
|
50
|
+
const protocol_detector_2 = require("./protocol-detector");
|
|
51
|
+
const resource_detector_1 = require("./resource-detector");
|
|
52
|
+
function loadLabels(labelsPath) {
|
|
53
|
+
if (!fs.existsSync(labelsPath))
|
|
54
|
+
return [];
|
|
55
|
+
return JSON.parse(fs.readFileSync(labelsPath, "utf-8"));
|
|
56
|
+
}
|
|
57
|
+
function runPythonBenchmark(projectPath, labelsPath) {
|
|
58
|
+
const sequences = (0, sequence_extractor_1.extractSequences)(projectPath, { maxBodyLines: 200 });
|
|
59
|
+
const labels = loadLabels(labelsPath);
|
|
60
|
+
// Build label lookup
|
|
61
|
+
const labelMap = new Map();
|
|
62
|
+
for (const l of labels) {
|
|
63
|
+
labelMap.set(`${l.filePath}:${l.functionName}`, l);
|
|
64
|
+
}
|
|
65
|
+
let tp = 0, fp = 0, fn = 0, tn = 0;
|
|
66
|
+
for (const seq of sequences) {
|
|
67
|
+
const key = `${seq.filePath}:${seq.functionName}`;
|
|
68
|
+
const label = labelMap.get(key);
|
|
69
|
+
const hasLabelViolation = label?.hasViolation ?? false;
|
|
70
|
+
// Run detection
|
|
71
|
+
const protoViolations = (0, protocol_detector_1.detectProtocolViolations)(seq.calls);
|
|
72
|
+
const safeViolations = (0, protocol_detector_2.detectSafeguardViolations)(seq.calls, seq.functionName, "python");
|
|
73
|
+
const resResult = (0, resource_detector_1.validateResourceLifecycle)(seq.calls);
|
|
74
|
+
const resViolations = resResult.violations || [];
|
|
75
|
+
const totalViolations = protoViolations.length + safeViolations.length + resViolations.length;
|
|
76
|
+
const detected = totalViolations > 0;
|
|
77
|
+
if (detected && hasLabelViolation)
|
|
78
|
+
tp++;
|
|
79
|
+
else if (detected && !hasLabelViolation)
|
|
80
|
+
fp++;
|
|
81
|
+
else if (!detected && hasLabelViolation)
|
|
82
|
+
fn++;
|
|
83
|
+
else
|
|
84
|
+
tn++;
|
|
85
|
+
}
|
|
86
|
+
const precision = tp + fp > 0 ? tp / (tp + fp) : 0;
|
|
87
|
+
const recall = tp + fn > 0 ? tp / (tp + fn) : 0;
|
|
88
|
+
const f1 = precision + recall > 0 ? 2 * (precision * recall) / (precision + recall) : 0;
|
|
89
|
+
// Check for unlabeled functions → treat as true negatives
|
|
90
|
+
const unlabeledCount = sequences.length - labels.length;
|
|
91
|
+
return {
|
|
92
|
+
precision: Math.round(precision * 1000) / 10,
|
|
93
|
+
recall: Math.round(recall * 1000) / 10,
|
|
94
|
+
f1: Math.round(f1 * 1000) / 10,
|
|
95
|
+
tp, fp, fn,
|
|
96
|
+
totalFunctions: sequences.length,
|
|
97
|
+
totalViolations: tp + fp,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
// ── Main ──
|
|
101
|
+
if (require.main === module) {
|
|
102
|
+
const projectPath = process.argv[2] || path.join(__dirname, "..", "test-python-protocol");
|
|
103
|
+
const labelsPath = process.argv[3] || path.join(__dirname, "..", "benchmarks", "python-labels.json");
|
|
104
|
+
console.log(`Python Benchmark Runner`);
|
|
105
|
+
console.log(`Project: ${projectPath}`);
|
|
106
|
+
console.log(`Labels: ${labelsPath}`);
|
|
107
|
+
console.log("");
|
|
108
|
+
if (!fs.existsSync(projectPath)) {
|
|
109
|
+
console.error(`Project path not found: ${projectPath}`);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
const result = runPythonBenchmark(projectPath, labelsPath);
|
|
113
|
+
console.log(`Functions: ${result.totalFunctions}`);
|
|
114
|
+
console.log(`Detected: ${result.totalViolations}`);
|
|
115
|
+
console.log(`TP: ${result.tp} FP: ${result.fp} FN: ${result.fn}`);
|
|
116
|
+
console.log(`Precision: ${result.precision}%`);
|
|
117
|
+
console.log(`Recall: ${result.recall}%`);
|
|
118
|
+
console.log(`F1: ${result.f1}%`);
|
|
119
|
+
process.exit(0);
|
|
120
|
+
}
|