@vk.amogh/trace 2.1.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.
Files changed (249) hide show
  1. package/README.md +208 -0
  2. package/bin/trace.js +112 -0
  3. package/package.json +46 -0
  4. package/pyproject.toml +39 -0
  5. package/src/trace_engine/__init__.py +8 -0
  6. package/src/trace_engine/__pycache__/__init__.cpython-311.pyc +0 -0
  7. package/src/trace_engine/__pycache__/cli.cpython-311.pyc +0 -0
  8. package/src/trace_engine/__pycache__/doctor.cpython-311.pyc +0 -0
  9. package/src/trace_engine/__pycache__/interactive.cpython-311.pyc +0 -0
  10. package/src/trace_engine/__pycache__/verify.cpython-311.pyc +0 -0
  11. package/src/trace_engine/ai/__init__.py +7 -0
  12. package/src/trace_engine/ai/__pycache__/__init__.cpython-311.pyc +0 -0
  13. package/src/trace_engine/ai/__pycache__/base.cpython-311.pyc +0 -0
  14. package/src/trace_engine/ai/__pycache__/ollama.cpython-311.pyc +0 -0
  15. package/src/trace_engine/ai/__pycache__/planner.cpython-311.pyc +0 -0
  16. package/src/trace_engine/ai/base.py +23 -0
  17. package/src/trace_engine/ai/ollama.py +50 -0
  18. package/src/trace_engine/ai/planner.py +40 -0
  19. package/src/trace_engine/apm/__init__.py +18 -0
  20. package/src/trace_engine/apm/__pycache__/__init__.cpython-311.pyc +0 -0
  21. package/src/trace_engine/apm/__pycache__/builder.cpython-311.pyc +0 -0
  22. package/src/trace_engine/apm/__pycache__/edges.cpython-311.pyc +0 -0
  23. package/src/trace_engine/apm/__pycache__/model.cpython-311.pyc +0 -0
  24. package/src/trace_engine/apm/__pycache__/nodes.cpython-311.pyc +0 -0
  25. package/src/trace_engine/apm/__pycache__/serialization.cpython-311.pyc +0 -0
  26. package/src/trace_engine/apm/builder.py +208 -0
  27. package/src/trace_engine/apm/edges.py +25 -0
  28. package/src/trace_engine/apm/model.py +107 -0
  29. package/src/trace_engine/apm/nodes.py +27 -0
  30. package/src/trace_engine/apm/serialization.py +105 -0
  31. package/src/trace_engine/benchmark/__init__.py +5 -0
  32. package/src/trace_engine/benchmark/__pycache__/__init__.cpython-311.pyc +0 -0
  33. package/src/trace_engine/benchmark/__pycache__/owasp.cpython-311.pyc +0 -0
  34. package/src/trace_engine/benchmark/owasp.py +183 -0
  35. package/src/trace_engine/cli.py +1184 -0
  36. package/src/trace_engine/config/__init__.py +35 -0
  37. package/src/trace_engine/config/__pycache__/__init__.cpython-311.pyc +0 -0
  38. package/src/trace_engine/config/__pycache__/defaults.cpython-311.pyc +0 -0
  39. package/src/trace_engine/config/__pycache__/loader.cpython-311.pyc +0 -0
  40. package/src/trace_engine/config/__pycache__/settings.cpython-311.pyc +0 -0
  41. package/src/trace_engine/config/defaults.py +48 -0
  42. package/src/trace_engine/config/loader.py +64 -0
  43. package/src/trace_engine/config/settings.py +72 -0
  44. package/src/trace_engine/doctor.py +250 -0
  45. package/src/trace_engine/findings/__init__.py +15 -0
  46. package/src/trace_engine/findings/__pycache__/__init__.cpython-311.pyc +0 -0
  47. package/src/trace_engine/findings/__pycache__/correlate.cpython-311.pyc +0 -0
  48. package/src/trace_engine/findings/__pycache__/model.cpython-311.pyc +0 -0
  49. package/src/trace_engine/findings/__pycache__/recommendations.cpython-311.pyc +0 -0
  50. package/src/trace_engine/findings/__pycache__/store.cpython-311.pyc +0 -0
  51. package/src/trace_engine/findings/correlate.py +103 -0
  52. package/src/trace_engine/findings/model.py +40 -0
  53. package/src/trace_engine/findings/recommendations.py +35 -0
  54. package/src/trace_engine/findings/store.py +39 -0
  55. package/src/trace_engine/framework/__init__.py +58 -0
  56. package/src/trace_engine/framework/__pycache__/__init__.cpython-311.pyc +0 -0
  57. package/src/trace_engine/framework/__pycache__/base.cpython-311.pyc +0 -0
  58. package/src/trace_engine/framework/__pycache__/csharp.cpython-311.pyc +0 -0
  59. package/src/trace_engine/framework/__pycache__/dart.cpython-311.pyc +0 -0
  60. package/src/trace_engine/framework/__pycache__/django.cpython-311.pyc +0 -0
  61. package/src/trace_engine/framework/__pycache__/express.cpython-311.pyc +0 -0
  62. package/src/trace_engine/framework/__pycache__/fastapi.cpython-311.pyc +0 -0
  63. package/src/trace_engine/framework/__pycache__/flask.cpython-311.pyc +0 -0
  64. package/src/trace_engine/framework/__pycache__/go.cpython-311.pyc +0 -0
  65. package/src/trace_engine/framework/__pycache__/nextjs.cpython-311.pyc +0 -0
  66. package/src/trace_engine/framework/__pycache__/php.cpython-311.pyc +0 -0
  67. package/src/trace_engine/framework/__pycache__/react_router.cpython-311.pyc +0 -0
  68. package/src/trace_engine/framework/__pycache__/ruby.cpython-311.pyc +0 -0
  69. package/src/trace_engine/framework/__pycache__/rust.cpython-311.pyc +0 -0
  70. package/src/trace_engine/framework/__pycache__/springboot.cpython-311.pyc +0 -0
  71. package/src/trace_engine/framework/base.py +49 -0
  72. package/src/trace_engine/framework/csharp.py +111 -0
  73. package/src/trace_engine/framework/dart.py +152 -0
  74. package/src/trace_engine/framework/django.py +188 -0
  75. package/src/trace_engine/framework/express.py +82 -0
  76. package/src/trace_engine/framework/fastapi.py +135 -0
  77. package/src/trace_engine/framework/flask.py +108 -0
  78. package/src/trace_engine/framework/go.py +94 -0
  79. package/src/trace_engine/framework/nextjs.py +200 -0
  80. package/src/trace_engine/framework/php.py +98 -0
  81. package/src/trace_engine/framework/react_router.py +331 -0
  82. package/src/trace_engine/framework/ruby.py +69 -0
  83. package/src/trace_engine/framework/rust.py +101 -0
  84. package/src/trace_engine/framework/springboot.py +145 -0
  85. package/src/trace_engine/harness/__init__.py +19 -0
  86. package/src/trace_engine/harness/__pycache__/__init__.cpython-311.pyc +0 -0
  87. package/src/trace_engine/harness/__pycache__/benchmark.cpython-311.pyc +0 -0
  88. package/src/trace_engine/harness/__pycache__/context.cpython-311.pyc +0 -0
  89. package/src/trace_engine/harness/__pycache__/engine.cpython-311.pyc +0 -0
  90. package/src/trace_engine/harness/__pycache__/patcher.cpython-311.pyc +0 -0
  91. package/src/trace_engine/harness/__pycache__/remediators.cpython-311.pyc +0 -0
  92. package/src/trace_engine/harness/benchmark.py +55 -0
  93. package/src/trace_engine/harness/context.py +49 -0
  94. package/src/trace_engine/harness/engine.py +187 -0
  95. package/src/trace_engine/harness/patcher.py +143 -0
  96. package/src/trace_engine/harness/remediators.py +307 -0
  97. package/src/trace_engine/ingest/__init__.py +15 -0
  98. package/src/trace_engine/ingest/__pycache__/__init__.cpython-311.pyc +0 -0
  99. package/src/trace_engine/ingest/__pycache__/files.cpython-311.pyc +0 -0
  100. package/src/trace_engine/ingest/__pycache__/hashing.cpython-311.pyc +0 -0
  101. package/src/trace_engine/ingest/__pycache__/ignore.cpython-311.pyc +0 -0
  102. package/src/trace_engine/ingest/__pycache__/repository.cpython-311.pyc +0 -0
  103. package/src/trace_engine/ingest/files.py +60 -0
  104. package/src/trace_engine/ingest/hashing.py +21 -0
  105. package/src/trace_engine/ingest/ignore.py +108 -0
  106. package/src/trace_engine/ingest/repository.py +50 -0
  107. package/src/trace_engine/intelligence/__init__.py +15 -0
  108. package/src/trace_engine/intelligence/__pycache__/__init__.cpython-311.pyc +0 -0
  109. package/src/trace_engine/intelligence/__pycache__/evaluation.cpython-311.pyc +0 -0
  110. package/src/trace_engine/intelligence/__pycache__/orchestrator.cpython-311.pyc +0 -0
  111. package/src/trace_engine/intelligence/__pycache__/tracebench.cpython-311.pyc +0 -0
  112. package/src/trace_engine/intelligence/evaluation.py +828 -0
  113. package/src/trace_engine/intelligence/laya/__init__.py +19 -0
  114. package/src/trace_engine/intelligence/laya/__pycache__/__init__.cpython-311.pyc +0 -0
  115. package/src/trace_engine/intelligence/laya/__pycache__/prompts.cpython-311.pyc +0 -0
  116. package/src/trace_engine/intelligence/laya/__pycache__/router.cpython-311.pyc +0 -0
  117. package/src/trace_engine/intelligence/laya/__pycache__/schemas.cpython-311.pyc +0 -0
  118. package/src/trace_engine/intelligence/laya/__pycache__/telemetry.cpython-311.pyc +0 -0
  119. package/src/trace_engine/intelligence/laya/__pycache__/thresholds.cpython-311.pyc +0 -0
  120. package/src/trace_engine/intelligence/laya/prompts.py +67 -0
  121. package/src/trace_engine/intelligence/laya/router.py +352 -0
  122. package/src/trace_engine/intelligence/laya/schemas.py +56 -0
  123. package/src/trace_engine/intelligence/laya/telemetry.py +48 -0
  124. package/src/trace_engine/intelligence/laya/thresholds.py +12 -0
  125. package/src/trace_engine/intelligence/orchestrator.py +130 -0
  126. package/src/trace_engine/intelligence/securebert/__init__.py +6 -0
  127. package/src/trace_engine/intelligence/securebert/__pycache__/__init__.cpython-311.pyc +0 -0
  128. package/src/trace_engine/intelligence/securebert/__pycache__/cache.cpython-311.pyc +0 -0
  129. package/src/trace_engine/intelligence/securebert/__pycache__/classifier.cpython-311.pyc +0 -0
  130. package/src/trace_engine/intelligence/securebert/cache.py +37 -0
  131. package/src/trace_engine/intelligence/securebert/classifier.py +240 -0
  132. package/src/trace_engine/intelligence/tracebench.py +61 -0
  133. package/src/trace_engine/intelligence/training/__init__.py +21 -0
  134. package/src/trace_engine/intelligence/training/__pycache__/__init__.cpython-311.pyc +0 -0
  135. package/src/trace_engine/intelligence/training/__pycache__/dataset.cpython-311.pyc +0 -0
  136. package/src/trace_engine/intelligence/training/__pycache__/dataset_importers.cpython-311.pyc +0 -0
  137. package/src/trace_engine/intelligence/training/__pycache__/laya_trainer.cpython-311.pyc +0 -0
  138. package/src/trace_engine/intelligence/training/__pycache__/lora_system2.cpython-311.pyc +0 -0
  139. package/src/trace_engine/intelligence/training/__pycache__/morefixes_pipeline.cpython-311.pyc +0 -0
  140. package/src/trace_engine/intelligence/training/__pycache__/slicer.cpython-311.pyc +0 -0
  141. package/src/trace_engine/intelligence/training/__pycache__/train_all.cpython-311.pyc +0 -0
  142. package/src/trace_engine/intelligence/training/__pycache__/trainer.cpython-311.pyc +0 -0
  143. package/src/trace_engine/intelligence/training/dataset.py +320 -0
  144. package/src/trace_engine/intelligence/training/dataset_importers.py +349 -0
  145. package/src/trace_engine/intelligence/training/laya_trainer.py +678 -0
  146. package/src/trace_engine/intelligence/training/lora_system2.py +162 -0
  147. package/src/trace_engine/intelligence/training/morefixes_pipeline.py +463 -0
  148. package/src/trace_engine/intelligence/training/slicer.py +129 -0
  149. package/src/trace_engine/intelligence/training/train_all.py +1009 -0
  150. package/src/trace_engine/intelligence/training/trainer.py +321 -0
  151. package/src/trace_engine/interactive.py +623 -0
  152. package/src/trace_engine/mcp/__init__.py +6 -0
  153. package/src/trace_engine/mcp/__pycache__/__init__.cpython-311.pyc +0 -0
  154. package/src/trace_engine/mcp/__pycache__/config.cpython-311.pyc +0 -0
  155. package/src/trace_engine/mcp/__pycache__/server.cpython-311.pyc +0 -0
  156. package/src/trace_engine/mcp/config.py +42 -0
  157. package/src/trace_engine/mcp/server.py +398 -0
  158. package/src/trace_engine/output/__init__.py +28 -0
  159. package/src/trace_engine/output/__pycache__/__init__.cpython-311.pyc +0 -0
  160. package/src/trace_engine/output/__pycache__/html.cpython-311.pyc +0 -0
  161. package/src/trace_engine/output/__pycache__/markdown.cpython-311.pyc +0 -0
  162. package/src/trace_engine/output/__pycache__/sarif.cpython-311.pyc +0 -0
  163. package/src/trace_engine/output/__pycache__/terminal.cpython-311.pyc +0 -0
  164. package/src/trace_engine/output/html.py +142 -0
  165. package/src/trace_engine/output/markdown.py +65 -0
  166. package/src/trace_engine/output/sarif.py +180 -0
  167. package/src/trace_engine/output/terminal.py +537 -0
  168. package/src/trace_engine/parsing/__init__.py +26 -0
  169. package/src/trace_engine/parsing/__pycache__/__init__.cpython-311.pyc +0 -0
  170. package/src/trace_engine/parsing/__pycache__/calls.cpython-311.pyc +0 -0
  171. package/src/trace_engine/parsing/__pycache__/language.cpython-311.pyc +0 -0
  172. package/src/trace_engine/parsing/__pycache__/locations.cpython-311.pyc +0 -0
  173. package/src/trace_engine/parsing/__pycache__/parser.cpython-311.pyc +0 -0
  174. package/src/trace_engine/parsing/__pycache__/symbols.cpython-311.pyc +0 -0
  175. package/src/trace_engine/parsing/calls.py +14 -0
  176. package/src/trace_engine/parsing/language.py +24 -0
  177. package/src/trace_engine/parsing/locations.py +17 -0
  178. package/src/trace_engine/parsing/parser.py +465 -0
  179. package/src/trace_engine/parsing/symbols.py +45 -0
  180. package/src/trace_engine/plugin/__init__.py +157 -0
  181. package/src/trace_engine/plugin/__pycache__/__init__.cpython-311.pyc +0 -0
  182. package/src/trace_engine/plugin/__pycache__/evaluator.cpython-311.pyc +0 -0
  183. package/src/trace_engine/plugin/__pycache__/swebench_adapter.cpython-311.pyc +0 -0
  184. package/src/trace_engine/plugin/__pycache__/task.cpython-311.pyc +0 -0
  185. package/src/trace_engine/plugin/bundle/hooks.json +24 -0
  186. package/src/trace_engine/plugin/bundle/mcp_config.json +11 -0
  187. package/src/trace_engine/plugin/bundle/plugin.json +20 -0
  188. package/src/trace_engine/plugin/bundle/rules/security_remediation.md +40 -0
  189. package/src/trace_engine/plugin/bundle/skills/trace-security-harness/SKILL.md +118 -0
  190. package/src/trace_engine/plugin/evaluator.py +105 -0
  191. package/src/trace_engine/plugin/swebench_adapter.py +96 -0
  192. package/src/trace_engine/plugin/task.py +48 -0
  193. package/src/trace_engine/policy/__init__.py +5 -0
  194. package/src/trace_engine/policy/__pycache__/__init__.cpython-311.pyc +0 -0
  195. package/src/trace_engine/policy/__pycache__/scope.cpython-311.pyc +0 -0
  196. package/src/trace_engine/policy/scope.py +80 -0
  197. package/src/trace_engine/runtime/__init__.py +7 -0
  198. package/src/trace_engine/runtime/__pycache__/__init__.cpython-311.pyc +0 -0
  199. package/src/trace_engine/runtime/__pycache__/client.cpython-311.pyc +0 -0
  200. package/src/trace_engine/runtime/__pycache__/observations.cpython-311.pyc +0 -0
  201. package/src/trace_engine/runtime/__pycache__/target.cpython-311.pyc +0 -0
  202. package/src/trace_engine/runtime/client.py +81 -0
  203. package/src/trace_engine/runtime/observations.py +18 -0
  204. package/src/trace_engine/runtime/target.py +23 -0
  205. package/src/trace_engine/security/__init__.py +16 -0
  206. package/src/trace_engine/security/__pycache__/__init__.cpython-311.pyc +0 -0
  207. package/src/trace_engine/security/__pycache__/fusion.cpython-311.pyc +0 -0
  208. package/src/trace_engine/security/__pycache__/hypotheses.cpython-311.pyc +0 -0
  209. package/src/trace_engine/security/__pycache__/signals.cpython-311.pyc +0 -0
  210. package/src/trace_engine/security/__pycache__/timing.cpython-311.pyc +0 -0
  211. package/src/trace_engine/security/fusion.py +126 -0
  212. package/src/trace_engine/security/hypotheses.py +251 -0
  213. package/src/trace_engine/security/signals.py +28 -0
  214. package/src/trace_engine/security/timing.py +132 -0
  215. package/src/trace_engine/testpacks/__init__.py +18 -0
  216. package/src/trace_engine/testpacks/__pycache__/__init__.cpython-311.pyc +0 -0
  217. package/src/trace_engine/testpacks/__pycache__/authentication.cpython-311.pyc +0 -0
  218. package/src/trace_engine/testpacks/__pycache__/base.cpython-311.pyc +0 -0
  219. package/src/trace_engine/testpacks/__pycache__/bfla.cpython-311.pyc +0 -0
  220. package/src/trace_engine/testpacks/__pycache__/bola.cpython-311.pyc +0 -0
  221. package/src/trace_engine/testpacks/__pycache__/cors.cpython-311.pyc +0 -0
  222. package/src/trace_engine/testpacks/__pycache__/deserialization.cpython-311.pyc +0 -0
  223. package/src/trace_engine/testpacks/__pycache__/injection.cpython-311.pyc +0 -0
  224. package/src/trace_engine/testpacks/__pycache__/mass_assignment.cpython-311.pyc +0 -0
  225. package/src/trace_engine/testpacks/__pycache__/path_traversal.cpython-311.pyc +0 -0
  226. package/src/trace_engine/testpacks/__pycache__/registry.cpython-311.pyc +0 -0
  227. package/src/trace_engine/testpacks/__pycache__/ssrf.cpython-311.pyc +0 -0
  228. package/src/trace_engine/testpacks/__pycache__/ssti.cpython-311.pyc +0 -0
  229. package/src/trace_engine/testpacks/authentication.py +60 -0
  230. package/src/trace_engine/testpacks/base.py +63 -0
  231. package/src/trace_engine/testpacks/bfla.py +70 -0
  232. package/src/trace_engine/testpacks/bola.py +94 -0
  233. package/src/trace_engine/testpacks/cors.py +85 -0
  234. package/src/trace_engine/testpacks/deserialization.py +86 -0
  235. package/src/trace_engine/testpacks/injection.py +179 -0
  236. package/src/trace_engine/testpacks/mass_assignment.py +70 -0
  237. package/src/trace_engine/testpacks/path_traversal.py +117 -0
  238. package/src/trace_engine/testpacks/registry.py +44 -0
  239. package/src/trace_engine/testpacks/ssrf.py +85 -0
  240. package/src/trace_engine/testpacks/ssti.py +96 -0
  241. package/src/trace_engine/tools/__init__.py +6 -0
  242. package/src/trace_engine/tools/__pycache__/__init__.cpython-311.pyc +0 -0
  243. package/src/trace_engine/tools/__pycache__/adapters.cpython-311.pyc +0 -0
  244. package/src/trace_engine/tools/__pycache__/base.cpython-311.pyc +0 -0
  245. package/src/trace_engine/tools/__pycache__/registry.cpython-311.pyc +0 -0
  246. package/src/trace_engine/tools/adapters.py +111 -0
  247. package/src/trace_engine/tools/base.py +68 -0
  248. package/src/trace_engine/tools/registry.py +36 -0
  249. package/src/trace_engine/verify.py +156 -0
@@ -0,0 +1,18 @@
1
+ """Runtime test observations and HTTP exchange records."""
2
+
3
+ from typing import Dict, Any, Optional, List
4
+ from pydantic import BaseModel, Field
5
+
6
+
7
+ class RuntimeObservation(BaseModel):
8
+ """Detailed observation from executing a test request against a target."""
9
+ request_method: str
10
+ request_url: str
11
+ request_headers: Dict[str, str] = Field(default_factory=dict)
12
+ request_body: Optional[str] = None
13
+ response_status: int
14
+ response_headers: Dict[str, str] = Field(default_factory=dict)
15
+ response_body: str = ""
16
+ latency_ms: float = 0.0
17
+ is_anomaly: bool = False
18
+ observation_notes: List[str] = Field(default_factory=list)
@@ -0,0 +1,23 @@
1
+ """Target runtime specification."""
2
+
3
+ from urllib.parse import urlparse
4
+ from pydantic import BaseModel, Field
5
+
6
+
7
+ class Target(BaseModel):
8
+ """Runtime target specification for security validation."""
9
+ url: str
10
+ scheme: str = "http"
11
+ host: str = "127.0.0.1"
12
+ port: int = 8000
13
+ base_path: str = ""
14
+
15
+ @classmethod
16
+ def from_url(cls, url: str) -> "Target":
17
+ parsed = urlparse(url)
18
+ scheme = parsed.scheme or "http"
19
+ host = parsed.hostname or "127.0.0.1"
20
+ port = parsed.port or (443 if scheme == "https" else 80)
21
+ base_path = parsed.path.rstrip("/")
22
+ normalized_url = f"{scheme}://{host}:{port}{base_path}"
23
+ return cls(url=normalized_url, scheme=scheme, host=host, port=port, base_path=base_path)
@@ -0,0 +1,16 @@
1
+ """Security signals and hypotheses module."""
2
+
3
+ from trace_engine.security.signals import SignalType, SecuritySignal
4
+ from trace_engine.security.hypotheses import (
5
+ VulnerabilityCategory,
6
+ SecurityHypothesis,
7
+ HypothesisEngine,
8
+ )
9
+
10
+ __all__ = [
11
+ "SignalType",
12
+ "SecuritySignal",
13
+ "VulnerabilityCategory",
14
+ "SecurityHypothesis",
15
+ "HypothesisEngine",
16
+ ]
@@ -0,0 +1,126 @@
1
+ """Neuro-Symbolic Confidence Fusion Engine combining Neural, AST, and Dynamic Evidence via Bayesian calibration.
2
+
3
+ Implements the 3-Signal Bayesian Evidence Fusion model:
4
+ Confidence = 1 - (1 - P_SecureBERT) * (1 - P_AST_Dataflow) * (1 - P_Dynamic_Oracle)
5
+
6
+ Levels:
7
+ - Level 3 (Triple Match): SecureBERT (0.85) + AST dataflow sink + Dynamic probe error -> Confidence ~99.8% (Critical / Zero-False-Positive Verified).
8
+ - Level 2 (Static + Dynamic Partial): Probe blocked by WAF, but AST source-to-sink dataflow is proven -> Confidence ~82% (High / Code-Audited).
9
+ - Level 1 (Single Signal): Only SecureBERT flags it with no AST sink -> Soft hypothesis for agent exploration.
10
+ """
11
+
12
+ import math
13
+ from typing import Optional, Dict, Any, List
14
+ from pydantic import BaseModel, Field
15
+ from trace_engine.findings.model import FindingConfidence
16
+
17
+
18
+ class ConfidenceEvidence(BaseModel):
19
+ """Signals supplied to the Bayesian Fusion Engine."""
20
+ neural_score: Optional[float] = Field(None, description="SecureBERT 2.0 probability [0.0 - 1.0]")
21
+ symbolic_ast_score: float = Field(0.5, description="AST dataflow & reachability confidence [0.0 - 1.0]")
22
+ dynamic_test_score: Optional[float] = Field(None, description="Active probe verification confidence [0.0 - 1.0]")
23
+ is_dynamically_confirmed: bool = Field(False, description="True if exploit payload was actively verified")
24
+ has_sanitizer: bool = Field(False, description="True if defensive guard/sanitizer was identified in AST")
25
+
26
+
27
+ class FusedConfidenceResult(BaseModel):
28
+ """Calibrated result from Neuro-Symbolic Bayesian evidence fusion."""
29
+ posterior_probability: float = Field(..., description="Calibrated Bayesian posterior [0.0 - 1.0]")
30
+ confidence_level: FindingConfidence = Field(..., description="Discrete confidence category")
31
+ log_odds: float = Field(..., description="Log-odds score")
32
+ fusion_level: str = Field(..., description="Level 1, Level 2, or Level 3")
33
+ evidence_breakdown: Dict[str, float] = Field(default_factory=dict)
34
+ rationale: str = Field(..., description="Explanation of signal weights and fusion outcome")
35
+
36
+
37
+ class NeuroSymbolicConfidenceEngine:
38
+ """Combines Neural (System 1 SecureBERT), Symbolic AST (System 2 Dataflow Sinks),
39
+ and Dynamic Verification signals into mathematically calibrated Bayesian confidence.
40
+ """
41
+
42
+ @classmethod
43
+ def fuse_evidence(cls, evidence: ConfidenceEvidence) -> FusedConfidenceResult:
44
+ """Calculates calibrated posterior probability from multiple independent security signals:
45
+ Confidence = 1 - (1 - P_SecureBERT) * (1 - P_AST_Dataflow) * (1 - P_Dynamic_Oracle)
46
+ """
47
+ # 1. Neural Signal (SecureBERT)
48
+ p_bert = 0.0
49
+ if evidence.neural_score is not None:
50
+ p_bert = max(0.0, min(0.99, evidence.neural_score))
51
+
52
+ # 2. Symbolic AST Signal (Dataflow Sinks & Control Flow)
53
+ p_ast = max(0.0, min(0.99, evidence.symbolic_ast_score))
54
+ if evidence.has_sanitizer:
55
+ p_ast = p_ast * 0.15 # 85% penalty if sanitizer or validator detected in AST
56
+
57
+ # 3. Dynamic Signal (Active Testpack Probes & Timing Oracle)
58
+ p_dyn = 0.0
59
+ if evidence.is_dynamically_confirmed:
60
+ p_dyn = 0.99
61
+ elif evidence.dynamic_test_score is not None:
62
+ p_dyn = max(0.0, min(0.99, evidence.dynamic_test_score))
63
+
64
+ # Bayesian Independence Fusion Formula:
65
+ # Confidence = 1 - (1 - P_SecureBERT) * (1 - P_AST_Dataflow) * (1 - P_Dynamic_Oracle)
66
+ prob_not_vuln = (1.0 - p_bert) * (1.0 - p_ast) * (1.0 - p_dyn)
67
+ raw_confidence = 1.0 - prob_not_vuln
68
+ posterior = round(max(0.01, min(0.999, raw_confidence)), 4)
69
+
70
+ # Log-odds representation:
71
+ p_clamped = max(0.001, min(0.999, posterior))
72
+ log_odds = round(math.log(p_clamped / (1.0 - p_clamped)), 3)
73
+
74
+ # Classify into Levels
75
+ signals_present = sum([
76
+ 1 if p_bert >= 0.4 else 0,
77
+ 1 if p_ast >= 0.4 else 0,
78
+ 1 if p_dyn >= 0.4 else 0,
79
+ ])
80
+
81
+ if evidence.is_dynamically_confirmed or (signals_present >= 3 and posterior >= 0.95):
82
+ fusion_level = "Level 3 (Triple Match: Neural + AST + Dynamic Runtime Confirmation)"
83
+ level = FindingConfidence.CONFIRMED
84
+ elif (signals_present >= 2 and posterior >= 0.75) or posterior >= 0.80:
85
+ fusion_level = "Level 2 (Static + Dynamic Partial: Proven AST Dataflow Sink)"
86
+ level = FindingConfidence.HIGH
87
+ elif posterior >= 0.50:
88
+ fusion_level = "Level 1 (Single Signal: Exploratory Hypothesis)"
89
+ level = FindingConfidence.MEDIUM
90
+ else:
91
+ fusion_level = "Level 1 (Low Confidence / Mitigated Signal)"
92
+ level = FindingConfidence.POTENTIAL
93
+
94
+ breakdown = {
95
+ "p_securebert": round(p_bert, 3),
96
+ "p_ast_dataflow": round(p_ast, 3),
97
+ "p_dynamic_oracle": round(p_dyn, 3),
98
+ "fused_confidence": posterior,
99
+ "has_sanitizer": 1.0 if evidence.has_sanitizer else 0.0,
100
+ }
101
+
102
+ signals = []
103
+ if p_dyn >= 0.90:
104
+ signals.append("empirically verified by dynamic runtime oracle")
105
+ elif p_dyn > 0.3:
106
+ signals.append(f"dynamic response signature ({int(p_dyn*100)}%)")
107
+ if p_bert > 0.4:
108
+ signals.append(f"SecureBERT semantic match ({int(p_bert*100)}%)")
109
+ if p_ast > 0.4:
110
+ signals.append(f"AST unparameterized sink reachability ({int(p_ast*100)}%)")
111
+ if evidence.has_sanitizer:
112
+ signals.append("downweighted: input sanitizer detected in AST")
113
+
114
+ rationale = (
115
+ f"Bayesian Evidence Fusion: {fusion_level} with calibrated confidence {int(posterior*100)}%. "
116
+ f"Signals: {'; '.join(signals) if signals else 'baseline hypothesis'}."
117
+ )
118
+
119
+ return FusedConfidenceResult(
120
+ posterior_probability=posterior,
121
+ confidence_level=level,
122
+ log_odds=log_odds,
123
+ fusion_level=fusion_level,
124
+ evidence_breakdown=breakdown,
125
+ rationale=rationale,
126
+ )
@@ -0,0 +1,251 @@
1
+ """Security hypotheses generation from APM and deterministic signals."""
2
+
3
+ from enum import Enum
4
+ from typing import List, Dict, Any, Optional
5
+ from pydantic import BaseModel, Field
6
+ from trace_engine.apm.model import AttackPathModel
7
+ from trace_engine.framework.base import Endpoint
8
+ from trace_engine.security.signals import SecuritySignal, SignalType
9
+
10
+
11
+ class VulnerabilityCategory(str, Enum):
12
+ BOLA = "BOLA"
13
+ BFLA = "BFLA"
14
+ AUTHENTICATION = "AUTHENTICATION"
15
+ SSRF = "SSRF"
16
+ INJECTION = "INJECTION"
17
+ MASS_ASSIGNMENT = "MASS_ASSIGNMENT"
18
+ PATH_TRAVERSAL = "PATH_TRAVERSAL"
19
+ SSTI = "SSTI"
20
+ CORS = "CORS"
21
+ DESERIALIZATION = "DESERIALIZATION"
22
+
23
+
24
+ class SecurityHypothesis(BaseModel):
25
+ """A testable hypothesis about an attack path in the application."""
26
+ id: str
27
+ category: VulnerabilityCategory
28
+ endpoint_id: str
29
+ endpoint_display: str
30
+ title: str
31
+ description: str
32
+ recommended_test_pack: str
33
+ confidence_prior: float = 0.5 # Prior confidence from static signals alone
34
+ static_evidence: List[str] = Field(default_factory=list)
35
+
36
+
37
+ class HypothesisEngine:
38
+ """Analyzes APM and endpoints to derive actionable security hypotheses."""
39
+
40
+ def derive_hypotheses(
41
+ self, apm: AttackPathModel, endpoints: List[Endpoint]
42
+ ) -> List[SecurityHypothesis]:
43
+ hypotheses: List[SecurityHypothesis] = []
44
+ hypo_idx = 1
45
+
46
+ for ep in endpoints:
47
+ ep_disp = ep.display_name()
48
+
49
+ # 1. BOLA Hypothesis: Endpoint accepts ID parameter, touches DB, but lacks ownership verification
50
+ if ep.object_identifier and ep.database_access:
51
+ hypotheses.append(
52
+ SecurityHypothesis(
53
+ id=f"HYP-BOLA-{hypo_idx:03d}",
54
+ category=VulnerabilityCategory.BOLA,
55
+ endpoint_id=ep.id,
56
+ endpoint_display=ep_disp,
57
+ title=f"Potential BOLA on {ep_disp}",
58
+ description="Endpoint looks up objects by client-supplied ID with potential absence of tenant/user ownership check.",
59
+ recommended_test_pack="bola",
60
+ confidence_prior=0.75,
61
+ static_evidence=[
62
+ f"Path parameter matches object ID pattern: {[p.name for p in ep.parameters if p.location == 'path']}",
63
+ "Database lookup confirmed in handler source",
64
+ f"Declared auth required: {ep.auth_required}",
65
+ ],
66
+ )
67
+ )
68
+ hypo_idx += 1
69
+
70
+ # 2. BFLA Hypothesis: Endpoint has administrative or privileged semantics
71
+ if "admin" in ep.path.lower() or "admin" in [r.lower() for r in ep.roles]:
72
+ hypotheses.append(
73
+ SecurityHypothesis(
74
+ id=f"HYP-BFLA-{hypo_idx:03d}",
75
+ category=VulnerabilityCategory.BFLA,
76
+ endpoint_id=ep.id,
77
+ endpoint_display=ep_disp,
78
+ title=f"Potential BFLA on privileged endpoint {ep_disp}",
79
+ description="Administrative/privileged action may fail to enforce strict RBAC check at runtime.",
80
+ recommended_test_pack="bfla",
81
+ confidence_prior=0.70,
82
+ static_evidence=[
83
+ f"Privileged path/role identifier present: {ep.roles or ['admin path']}",
84
+ f"Source location: {ep.source}",
85
+ ],
86
+ )
87
+ )
88
+ hypo_idx += 1
89
+
90
+ # 3. Authentication Bypass / Missing Auth: State-changing endpoint without auth
91
+ if not ep.auth_required and (ep.state_changing or ep.sensitive_data):
92
+ if not ep.path.endswith("/login") and not ep.path.endswith("/register"):
93
+ hypotheses.append(
94
+ SecurityHypothesis(
95
+ id=f"HYP-AUTH-{hypo_idx:03d}",
96
+ category=VulnerabilityCategory.AUTHENTICATION,
97
+ endpoint_id=ep.id,
98
+ endpoint_display=ep_disp,
99
+ title=f"Unauthenticated sensitive endpoint {ep_disp}",
100
+ description="Sensitive or state-modifying endpoint does not declare authentication requirement.",
101
+ recommended_test_pack="authentication",
102
+ confidence_prior=0.80,
103
+ static_evidence=[
104
+ f"State-changing: {ep.state_changing}",
105
+ f"Sensitive data indicator: {ep.sensitive_data}",
106
+ "No auth middleware or dependency detected",
107
+ ],
108
+ )
109
+ )
110
+ hypo_idx += 1
111
+
112
+ # 4. SSRF Hypothesis: Endpoint takes URL or makes external network calls
113
+ if ep.external_network or any("url" in p.name.lower() for p in ep.parameters):
114
+ hypotheses.append(
115
+ SecurityHypothesis(
116
+ id=f"HYP-SSRF-{hypo_idx:03d}",
117
+ category=VulnerabilityCategory.SSRF,
118
+ endpoint_id=ep.id,
119
+ endpoint_display=ep_disp,
120
+ title=f"Potential SSRF on {ep_disp}",
121
+ description="Endpoint handles URL parameter and communicates with outbound HTTP client.",
122
+ recommended_test_pack="ssrf",
123
+ confidence_prior=0.85,
124
+ static_evidence=[
125
+ "Outbound HTTP client calls detected in handler body",
126
+ f"URL parameter detected: {[p.name for p in ep.parameters if 'url' in p.name.lower()]}",
127
+ ],
128
+ )
129
+ )
130
+ hypo_idx += 1
131
+
132
+ # 5. Mass Assignment Hypothesis: PATCH or PUT or POST on user or profile
133
+ if ep.method in ("PATCH", "PUT", "POST") and any(term in ep.path.lower() for term in ("user", "profile", "account")):
134
+ hypotheses.append(
135
+ SecurityHypothesis(
136
+ id=f"HYP-MASS-{hypo_idx:03d}",
137
+ category=VulnerabilityCategory.MASS_ASSIGNMENT,
138
+ endpoint_id=ep.id,
139
+ endpoint_display=ep_disp,
140
+ title=f"Potential Mass Assignment on {ep_disp}",
141
+ description="Profile update endpoint may bind sensitive attributes (e.g. is_admin, role) directly from payload.",
142
+ recommended_test_pack="mass_assignment",
143
+ confidence_prior=0.65,
144
+ static_evidence=[
145
+ f"State modifying method {ep.method} on profile/user path",
146
+ "Model payload deserialization detected",
147
+ ],
148
+ )
149
+ )
150
+ hypo_idx += 1
151
+
152
+ # 6. Injection Indicator Hypothesis: Search or query with DB access
153
+ if any(term in ep.path.lower() for term in ("search", "filter", "query")) and ep.database_access:
154
+ hypotheses.append(
155
+ SecurityHypothesis(
156
+ id=f"HYP-INJ-{hypo_idx:03d}",
157
+ category=VulnerabilityCategory.INJECTION,
158
+ endpoint_id=ep.id,
159
+ endpoint_display=ep_disp,
160
+ title=f"Potential Injection Indicator on {ep_disp}",
161
+ description="Dynamic search query routed to database layer without verified parameterization.",
162
+ recommended_test_pack="injection",
163
+ confidence_prior=0.60,
164
+ static_evidence=[
165
+ "User query parameter routed to database handler",
166
+ f"Endpoint parameters: {[p.name for p in ep.parameters]}",
167
+ ],
168
+ )
169
+ )
170
+ hypo_idx += 1
171
+
172
+ # 7. Path Traversal Hypothesis: Endpoints accepting file or path parameters
173
+ file_param_names = [p.name for p in ep.parameters if any(term in p.name.lower() for term in ("file", "path", "doc", "dir", "download", "name", "asset", "key"))]
174
+ if file_param_names or any(term in ep.path.lower() for term in ("file", "doc", "download", "asset", "static")):
175
+ hypotheses.append(
176
+ SecurityHypothesis(
177
+ id=f"HYP-TRAV-{hypo_idx:03d}",
178
+ category=VulnerabilityCategory.PATH_TRAVERSAL,
179
+ endpoint_id=ep.id,
180
+ endpoint_display=ep_disp,
181
+ title=f"Potential Path Traversal on {ep_disp}",
182
+ description="Endpoint handles file or path parameters without verified filesystem boundary isolation.",
183
+ recommended_test_pack="path_traversal",
184
+ confidence_prior=0.65,
185
+ static_evidence=[
186
+ f"File/path parameter names detected: {file_param_names or [ep.path]}",
187
+ f"Source location: {ep.source}",
188
+ ],
189
+ )
190
+ )
191
+ hypo_idx += 1
192
+
193
+ # 8. Server-Side Template Injection (SSTI) Hypothesis
194
+ template_param_names = [p.name for p in ep.parameters if any(term in p.name.lower() for term in ("template", "render", "msg", "format", "view", "preview"))]
195
+ if template_param_names or any(term in ep.path.lower() for term in ("template", "render", "preview", "email", "notify")):
196
+ hypotheses.append(
197
+ SecurityHypothesis(
198
+ id=f"HYP-SSTI-{hypo_idx:03d}",
199
+ category=VulnerabilityCategory.SSTI,
200
+ endpoint_id=ep.id,
201
+ endpoint_display=ep_disp,
202
+ title=f"Potential Template Injection on {ep_disp}",
203
+ description="Endpoint processes dynamic template formatting or user-interpolated rendering.",
204
+ recommended_test_pack="ssti",
205
+ confidence_prior=0.60,
206
+ static_evidence=[
207
+ f"Template rendering parameter detected: {template_param_names or [ep.path]}",
208
+ ],
209
+ )
210
+ )
211
+ hypo_idx += 1
212
+
213
+ # 9. CORS Misconfiguration Hypothesis
214
+ if ep.auth_required and ep.sensitive_data:
215
+ hypotheses.append(
216
+ SecurityHypothesis(
217
+ id=f"HYP-CORS-{hypo_idx:03d}",
218
+ category=VulnerabilityCategory.CORS,
219
+ endpoint_id=ep.id,
220
+ endpoint_display=ep_disp,
221
+ title=f"Potential CORS Misconfiguration on {ep_disp}",
222
+ description="Authenticated sensitive endpoint may reflect arbitrary cross-origin request headers with credentials.",
223
+ recommended_test_pack="cors",
224
+ confidence_prior=0.55,
225
+ static_evidence=[
226
+ f"Authenticated: {ep.auth_required}, Sensitive data: {ep.sensitive_data}",
227
+ ],
228
+ )
229
+ )
230
+ hypo_idx += 1
231
+
232
+ # 10. Insecure Deserialization Hypothesis
233
+ if ep.method in ("POST", "PUT", "PATCH") and any(term in ep.path.lower() for term in ("import", "upload", "state", "event", "session", "restore", "sync")):
234
+ hypotheses.append(
235
+ SecurityHypothesis(
236
+ id=f"HYP-DESER-{hypo_idx:03d}",
237
+ category=VulnerabilityCategory.DESERIALIZATION,
238
+ endpoint_id=ep.id,
239
+ endpoint_display=ep_disp,
240
+ title=f"Potential Insecure Deserialization on {ep_disp}",
241
+ description="State or data restoration endpoint accepting structured object representations.",
242
+ recommended_test_pack="deserialization",
243
+ confidence_prior=0.60,
244
+ static_evidence=[
245
+ f"State restoration path pattern in method {ep.method}: {ep.path}",
246
+ ],
247
+ )
248
+ )
249
+ hypo_idx += 1
250
+
251
+ return hypotheses
@@ -0,0 +1,28 @@
1
+ """Deterministic security signal models and static detectors."""
2
+
3
+ from enum import Enum
4
+ from typing import List, Optional, Dict, Any
5
+ from pydantic import BaseModel, Field
6
+ from trace_engine.parsing.locations import SourceLocation
7
+
8
+
9
+ class SignalType(str, Enum):
10
+ MISSING_AUTH = "MISSING_AUTH"
11
+ UNTRUSTED_OBJECT_LOOKUP = "UNTRUSTED_OBJECT_LOOKUP"
12
+ PRIVILEGE_MISMATCH = "PRIVILEGE_MISMATCH"
13
+ USER_URL_OUTBOUND = "USER_URL_OUTBOUND"
14
+ DYNAMIC_QUERY_CONSTRUCTION = "DYNAMIC_QUERY_CONSTRUCTION"
15
+ MASS_ASSIGNMENT_SURFACE = "MASS_ASSIGNMENT_SURFACE"
16
+
17
+
18
+ class SecuritySignal(BaseModel):
19
+ """A deterministic indicator of a potential vulnerability path in source code."""
20
+ id: str
21
+ signal_type: SignalType
22
+ endpoint_id: str
23
+ title: str
24
+ description: str
25
+ severity_potential: str # "CRITICAL", "HIGH", "MEDIUM", "LOW"
26
+ source: SourceLocation
27
+ evidence_snippet: Optional[str] = None
28
+ properties: Dict[str, Any] = Field(default_factory=dict)
@@ -0,0 +1,132 @@
1
+ """Statistical Timing Oracle using Welch's t-test for bulletproof blind injection verification."""
2
+
3
+ import math
4
+ from typing import List, Tuple, Dict, Any, Optional
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class TimingVerificationResult(BaseModel):
9
+ """Result of statistical timing hypothesis verification."""
10
+ is_confirmed: bool = Field(..., description="True if delay is statistically proven beyond network noise")
11
+ t_statistic: float = Field(..., description="Welch's t-statistic")
12
+ p_value: float = Field(..., description="Two-tailed p-value (significance level)")
13
+ degrees_of_freedom: float = Field(..., description="Welch-Satterthwaite degrees of freedom")
14
+ mean_baseline_sec: float = Field(..., description="Mean baseline latency in seconds")
15
+ mean_delay_sec: float = Field(..., description="Mean injected delay latency in seconds")
16
+ observed_shift_sec: float = Field(..., description="Observed latency delta (mean_delay - mean_baseline)")
17
+ confidence: float = Field(..., description="Bayesian probability score [0.0 - 1.0]")
18
+ summary: str = Field(..., description="Detailed statistical rationale")
19
+
20
+
21
+ class StatisticalTimingOracle:
22
+ """Rigorous statistical testing engine for blind SQL, Command, and Code injection verification.
23
+
24
+ Applies Welch's two-sample t-test to eliminate false positives from network latency jitter and CPU throttling.
25
+ """
26
+
27
+ @staticmethod
28
+ def calculate_stats(samples: List[float]) -> Tuple[float, float]:
29
+ """Calculates sample mean and unbiased sample variance."""
30
+ n = len(samples)
31
+ if n < 2:
32
+ return (samples[0] if n == 1 else 0.0, 0.0)
33
+ mean = sum(samples) / n
34
+ variance = sum((x - mean) ** 2 for x in samples) / (n - 1)
35
+ return mean, max(variance, 1e-9)
36
+
37
+ @classmethod
38
+ def evaluate_timing_vulnerability(
39
+ cls,
40
+ baseline_latencies: List[float],
41
+ delay_latencies: List[float],
42
+ expected_delay_sec: float = 1.5,
43
+ alpha_threshold: float = 0.01,
44
+ ) -> TimingVerificationResult:
45
+ """Evaluates whether delay latencies represent a statistically significant vulnerability reaction.
46
+
47
+ Args:
48
+ baseline_latencies: List of latency measurements (seconds) for non-delay probes.
49
+ delay_latencies: List of latency measurements (seconds) for delay-injected probes.
50
+ expected_delay_sec: Nominal delay programmed into probe payload (e.g. 1.5s).
51
+ alpha_threshold: Significance level threshold (default 0.01 for 99% confidence).
52
+ """
53
+ n1 = len(baseline_latencies)
54
+ n2 = len(delay_latencies)
55
+
56
+ if n1 < 2 or n2 < 2:
57
+ return TimingVerificationResult(
58
+ is_confirmed=False,
59
+ t_statistic=0.0,
60
+ p_value=1.0,
61
+ degrees_of_freedom=0.0,
62
+ mean_baseline_sec=sum(baseline_latencies) / max(1, n1),
63
+ mean_delay_sec=sum(delay_latencies) / max(1, n2),
64
+ observed_shift_sec=0.0,
65
+ confidence=0.1,
66
+ summary="Insufficient sample size for statistical verification (minimum 2 samples required per group).",
67
+ )
68
+
69
+ mean1, var1 = cls.calculate_stats(baseline_latencies)
70
+ mean2, var2 = cls.calculate_stats(delay_latencies)
71
+
72
+ delta = mean2 - mean1
73
+ se = math.sqrt((var1 / n1) + (var2 / n2))
74
+
75
+ # Welch-Satterthwaite degrees of freedom
76
+ numerator = ((var1 / n1) + (var2 / n2)) ** 2
77
+ denominator = (((var1 / n1) ** 2) / (n1 - 1)) + (((var2 / n2) ** 2) / (n2 - 1))
78
+ df = max(1.0, numerator / max(denominator, 1e-9))
79
+
80
+ t_stat = delta / max(se, 1e-9)
81
+
82
+ # Approximate p-value using standard normal / t-distribution tail
83
+ # For large df, t approximates normal. For small df, Cornish-Fisher / Student approximation
84
+ p_val = cls._approximate_p_value(t_stat, df)
85
+
86
+ # Requirements for confirmation:
87
+ # 1. Statistically significant difference (p < alpha_threshold, default 0.01)
88
+ # 2. Positive direction (t > 2.5)
89
+ # 3. Magnitude matches at least 85% of nominal programmed sleep time (Delta t >= 0.85 * delay)
90
+ shift_ratio = delta / max(expected_delay_sec, 0.1)
91
+ confirmed = (t_stat > 2.5) and (p_val < alpha_threshold) and (shift_ratio >= 0.85)
92
+
93
+ confidence = 0.99 if confirmed else (0.40 if t_stat > 2.0 and delta > 0 else 0.10)
94
+
95
+ if confirmed:
96
+ summary = (
97
+ f"Statistical Timing Oracle CONFIRMED blind injection: Mean latency shifted by +{delta:.2f}s "
98
+ f"(nominal {expected_delay_sec:.1f}s, ratio={shift_ratio:.1%}) with Welch's t={t_stat:.2f} (df={df:.1f}, p={p_val:.2e} < {alpha_threshold}). "
99
+ f"Null hypothesis (network jitter) rejected with >99% confidence."
100
+ )
101
+ else:
102
+ summary = (
103
+ f"Statistical Timing Oracle INCONCLUSIVE: Observed latency shift +{delta:.2f}s "
104
+ f"(t={t_stat:.2f}, p={p_val:.4f}). Did not satisfy 85% expected delay shift ({expected_delay_sec:.1f}s) "
105
+ f"or significance threshold ({alpha_threshold})."
106
+ )
107
+
108
+ return TimingVerificationResult(
109
+ is_confirmed=confirmed,
110
+ t_statistic=round(t_stat, 3),
111
+ p_value=round(p_val, 6),
112
+ degrees_of_freedom=round(df, 1),
113
+ mean_baseline_sec=round(mean1, 3),
114
+ mean_delay_sec=round(mean2, 3),
115
+ observed_shift_sec=round(delta, 3),
116
+ confidence=confidence,
117
+ summary=summary,
118
+ )
119
+
120
+ @staticmethod
121
+ def _approximate_p_value(t: float, df: float) -> float:
122
+ """Approximates two-tailed p-value for Student's / Welch's t-distribution."""
123
+ if t <= 0:
124
+ return 1.0
125
+
126
+ # Normal approximation with tail correction for degrees of freedom
127
+ # Z = t * (1 - 1/(4*df))
128
+ z = t * (1.0 - (1.0 / (4.0 * max(df, 1.0))))
129
+ # Error function complementary approximation
130
+ erf_arg = z / math.sqrt(2.0)
131
+ p = math.erfc(erf_arg)
132
+ return max(1e-12, min(1.0, p))
@@ -0,0 +1,18 @@
1
+ """Security test pack system."""
2
+
3
+ from trace_engine.testpacks.base import (
4
+ TestPack,
5
+ TestContext,
6
+ TestExecutionResult,
7
+ UserIdentity,
8
+ )
9
+ from trace_engine.testpacks.registry import TestPackRegistry, default_registry
10
+
11
+ __all__ = [
12
+ "TestPack",
13
+ "TestContext",
14
+ "TestExecutionResult",
15
+ "UserIdentity",
16
+ "TestPackRegistry",
17
+ "default_registry",
18
+ ]