@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,42 @@
1
+ """Project-local MCP configuration generator (Section 64)."""
2
+
3
+ import json
4
+ import sys
5
+ from pathlib import Path
6
+ from typing import Optional
7
+
8
+
9
+ def generate_mcp_json(project_dir: Path, trace_cmd_path: Optional[str] = None) -> Path:
10
+ """Generate .mcp.json in the repository directory."""
11
+ project_dir = project_dir.resolve()
12
+ mcp_file = project_dir / ".mcp.json"
13
+
14
+ import shutil
15
+
16
+ candidate_cmd = (Path(__file__).parent.parent.parent.parent / "trace.cmd").resolve()
17
+ if trace_cmd_path:
18
+ cmd = trace_cmd_path
19
+ args = ["mcp"]
20
+ elif sys.platform == "win32" and candidate_cmd.exists():
21
+ cmd = str(candidate_cmd)
22
+ args = ["mcp"]
23
+ elif shutil.which("trace"):
24
+ cmd = "trace"
25
+ args = ["mcp"]
26
+ else:
27
+ cmd = sys.executable
28
+ args = ["-m", "trace_engine.cli", "mcp"]
29
+
30
+ config_data = {
31
+ "mcpServers": {
32
+ "trace": {
33
+ "command": cmd,
34
+ "args": args,
35
+ }
36
+ }
37
+ }
38
+
39
+ with open(mcp_file, "w", encoding="utf-8") as f:
40
+ json.dump(config_data, f, indent=2)
41
+
42
+ return mcp_file
@@ -0,0 +1,398 @@
1
+ """TRACE Model Context Protocol (MCP) stdio server implementation."""
2
+
3
+ import sys
4
+ import json
5
+ import logging
6
+ from pathlib import Path
7
+ from typing import Dict, Any, Optional, List
8
+
9
+ from trace_engine.findings.store import FindingStore
10
+ from trace_engine.verify import VerificationEngine
11
+ from trace_engine.ingest.repository import RepositoryScanner
12
+ from trace_engine.parsing.parser import CodeParser
13
+ from trace_engine.framework import get_adapters
14
+ from trace_engine.apm.builder import APMBuilder
15
+ from trace_engine.apm.model import AttackPathModel
16
+ from trace_engine.security.hypotheses import HypothesisEngine
17
+ from trace_engine.policy.scope import ScopeGuard
18
+ from trace_engine.runtime.client import ScopedHttpClient
19
+ from trace_engine.testpacks.registry import default_registry
20
+ from trace_engine.testpacks.base import TestContext
21
+ from trace_engine.findings.correlate import EvidenceCorrelator
22
+ from trace_engine.config.loader import load_config, get_trace_dir
23
+
24
+ logger = logging.getLogger("trace_mcp")
25
+
26
+ # MCP Specification Tool Definitions
27
+ TRACE_TOOLS = [
28
+ {
29
+ "name": "trace_scan",
30
+ "description": "Run complete TRACE static + runtime security audit on repository.",
31
+ "inputSchema": {
32
+ "type": "object",
33
+ "properties": {
34
+ "repository": {"type": "string", "default": ".", "description": "Path to target repository"},
35
+ "target": {"type": "string", "default": "http://127.0.0.1:18080", "description": "Target HTTP runtime URL"},
36
+ "profile": {"type": "string", "default": "standard", "enum": ["quick", "standard", "deep"]},
37
+ },
38
+ "required": ["repository"],
39
+ },
40
+ },
41
+ {
42
+ "name": "trace_status",
43
+ "description": "Get current status and statistics of TRACE engine in repository.",
44
+ "inputSchema": {
45
+ "type": "object",
46
+ "properties": {
47
+ "repository": {"type": "string", "default": "."},
48
+ },
49
+ },
50
+ },
51
+ {
52
+ "name": "trace_findings",
53
+ "description": "Retrieve all correlated vulnerability findings for repository.",
54
+ "inputSchema": {
55
+ "type": "object",
56
+ "properties": {
57
+ "repository": {"type": "string", "default": "."},
58
+ "severity": {"type": "string", "description": "Filter by minimum severity"},
59
+ },
60
+ },
61
+ },
62
+ {
63
+ "name": "trace_explain",
64
+ "description": "Retrieve root cause explanation, attack path, and evidence for a finding.",
65
+ "inputSchema": {
66
+ "type": "object",
67
+ "properties": {
68
+ "finding_id": {"type": "string", "description": "Finding identifier (e.g. TR-BOLA-001)"},
69
+ "repository": {"type": "string", "default": "."},
70
+ },
71
+ "required": ["finding_id"],
72
+ },
73
+ },
74
+ {
75
+ "name": "trace_attack_path",
76
+ "description": "Inspect Attack-Path Model hops connecting an endpoint to dangerous sinks.",
77
+ "inputSchema": {
78
+ "type": "object",
79
+ "properties": {
80
+ "endpoint": {"type": "string", "description": "Endpoint path (e.g. /api/orders/{id})"},
81
+ "repository": {"type": "string", "default": "."},
82
+ },
83
+ "required": ["endpoint"],
84
+ },
85
+ },
86
+ {
87
+ "name": "trace_verify",
88
+ "description": "Verify whether a code modification by a coding agent resolved a finding.",
89
+ "inputSchema": {
90
+ "type": "object",
91
+ "properties": {
92
+ "finding_id": {"type": "string", "description": "Finding identifier to verify"},
93
+ "repository": {"type": "string", "default": "."},
94
+ "target": {"type": "string", "default": "http://127.0.0.1:18080"},
95
+ },
96
+ "required": ["finding_id"],
97
+ },
98
+ },
99
+ {
100
+ "name": "trace_harness_task",
101
+ "description": "Retrieve benchmark task specification (SWE-bench format) for a security finding to guide an autonomous agent harness.",
102
+ "inputSchema": {
103
+ "type": "object",
104
+ "properties": {
105
+ "finding_id": {"type": "string", "description": "Finding identifier (e.g. TR-BOLA-001)"},
106
+ "repository": {"type": "string", "default": "."},
107
+ },
108
+ "required": ["finding_id"],
109
+ },
110
+ },
111
+ {
112
+ "name": "trace_eval_patch",
113
+ "description": "Evaluate an agent's proposed patch or diff against the TRACE verification oracle and exploit tests.",
114
+ "inputSchema": {
115
+ "type": "object",
116
+ "properties": {
117
+ "finding_id": {"type": "string", "description": "Finding identifier"},
118
+ "patch_content": {"type": "string", "description": "Full new content for the target file"},
119
+ "target_file": {"type": "string", "description": "Relative path to target file in repository"},
120
+ "repository": {"type": "string", "default": "."},
121
+ "target": {"type": "string", "default": "http://127.0.0.1:18080"},
122
+ "rollback_after": {"type": "boolean", "default": False, "description": "Whether to rollback the patch after evaluation"},
123
+ },
124
+ "required": ["finding_id"],
125
+ },
126
+ },
127
+ ]
128
+
129
+
130
+ class TraceMCPServer:
131
+ """Stdio JSON-RPC 2.0 MCP server for coding agent handoff."""
132
+
133
+ def __init__(self):
134
+ self.running = True
135
+
136
+ def handle_request(self, request: Dict[str, Any]) -> Optional[Dict[str, Any]]:
137
+ method = request.get("method")
138
+ msg_id = request.get("id")
139
+ params = request.get("params", {})
140
+
141
+ if method == "initialize":
142
+ return {
143
+ "jsonrpc": "2.0",
144
+ "id": msg_id,
145
+ "result": {
146
+ "protocolVersion": "2024-11-05",
147
+ "serverInfo": {
148
+ "name": "trace-security-mcp",
149
+ "version": "2.0.0",
150
+ },
151
+ "capabilities": {"tools": {}},
152
+ },
153
+ }
154
+
155
+ elif method == "notifications/initialized":
156
+ return None
157
+
158
+ elif method == "tools/list":
159
+ return {
160
+ "jsonrpc": "2.0",
161
+ "id": msg_id,
162
+ "result": {"tools": TRACE_TOOLS},
163
+ }
164
+
165
+ elif method == "tools/call":
166
+ tool_name = params.get("name")
167
+ args = params.get("arguments", {})
168
+ try:
169
+ res_content = self.execute_tool(tool_name, args)
170
+ return {
171
+ "jsonrpc": "2.0",
172
+ "id": msg_id,
173
+ "result": {
174
+ "content": [
175
+ {"type": "text", "text": json.dumps(res_content, indent=2)}
176
+ ]
177
+ },
178
+ }
179
+ except Exception as e:
180
+ return {
181
+ "jsonrpc": "2.0",
182
+ "id": msg_id,
183
+ "error": {"code": -32000, "message": str(e)},
184
+ }
185
+
186
+ elif method == "ping":
187
+ return {"jsonrpc": "2.0", "id": msg_id, "result": {}}
188
+
189
+ return {
190
+ "jsonrpc": "2.0",
191
+ "id": msg_id,
192
+ "error": {"code": -32601, "message": f"Method {method} not found"},
193
+ }
194
+
195
+ def execute_tool(self, name: str, args: Dict[str, Any]) -> Any:
196
+ repo_path = Path(args.get("repository", ".")).resolve()
197
+ target_url = args.get("target", "http://127.0.0.1:18080")
198
+
199
+ if name == "trace_status":
200
+ trace_dir = repo_path / ".trace"
201
+ store = FindingStore(trace_dir)
202
+ findings = store.load_findings()
203
+ return {
204
+ "repository": str(repo_path),
205
+ "initialized": trace_dir.exists(),
206
+ "total_findings": len(findings),
207
+ "confirmed": sum(1 for f in findings if f.confidence.value == "CONFIRMED"),
208
+ }
209
+
210
+ elif name == "trace_findings":
211
+ store = FindingStore(repo_path / ".trace")
212
+ findings = store.load_findings()
213
+ return [
214
+ {
215
+ "id": f.id,
216
+ "title": f.title,
217
+ "category": f.category,
218
+ "severity": f.severity.value,
219
+ "confidence": f.confidence.value,
220
+ "endpoint": f.endpoint,
221
+ "remediation": f.remediation,
222
+ "source": str(f.source_location) if f.source_location else None,
223
+ }
224
+ for f in findings
225
+ ]
226
+
227
+ elif name == "trace_explain":
228
+ finding_id = args.get("finding_id", "")
229
+ store = FindingStore(repo_path / ".trace")
230
+ finding = store.get_finding_by_id(finding_id)
231
+ if not finding:
232
+ return {"error": f"Finding {finding_id} not found."}
233
+ return {
234
+ "id": finding.id,
235
+ "title": finding.title,
236
+ "category": finding.category,
237
+ "severity": finding.severity.value,
238
+ "confidence": finding.confidence.value,
239
+ "endpoint": finding.endpoint,
240
+ "source": str(finding.source_location),
241
+ "attack_path": finding.attack_path,
242
+ "static_evidence": finding.static_evidence,
243
+ "runtime_evidence": finding.runtime_evidence,
244
+ "correlation_notes": finding.correlation_notes,
245
+ "reproduction_steps": finding.reproduction_steps,
246
+ "remediation": finding.remediation,
247
+ }
248
+
249
+ elif name == "trace_verify":
250
+ finding_id = args.get("finding_id", "")
251
+ engine = VerificationEngine(repo_path=repo_path, target_url=target_url)
252
+ res = engine.verify(finding_id)
253
+ return res.model_dump()
254
+
255
+ elif name == "trace_scan":
256
+ # Execute scan programmatic flow
257
+ scanner = RepositoryScanner(repo_path)
258
+ source_files = scanner.scan()
259
+ parser = CodeParser()
260
+ adapters = get_adapters()
261
+
262
+ parsed_files = []
263
+ discovered_endpoints = []
264
+ for sf in source_files:
265
+ content = Path(sf.absolute_path).read_text(encoding="utf-8", errors="replace")
266
+ pf = parser.parse(sf.path, content, sf.language, absolute_path=sf.absolute_path)
267
+ parsed_files.append(pf)
268
+ for adapter in adapters:
269
+ if adapter.can_handle(pf):
270
+ discovered_endpoints.extend(adapter.extract_endpoints(pf, content))
271
+
272
+ builder = APMBuilder(project_name=repo_path.name)
273
+ apm = builder.build(repo_path, source_files, parsed_files, discovered_endpoints)
274
+
275
+ engine = HypothesisEngine()
276
+ hypotheses = engine.derive_hypotheses(apm, discovered_endpoints)
277
+
278
+ scope_guard = ScopeGuard()
279
+ scope_guard.allow_target(target_url)
280
+ client = ScopedHttpClient(scope_guard=scope_guard)
281
+ context = TestContext(
282
+ target_base_url=target_url,
283
+ active_tokens={"user-a": "user-a", "user-b": "user-b", "admin": "admin"},
284
+ )
285
+
286
+ correlator = EvidenceCorrelator()
287
+ findings = []
288
+ for hyp in hypotheses:
289
+ pack = default_registry.get(hyp.recommended_test_pack)
290
+ test_res = None
291
+ if pack:
292
+ try:
293
+ test_res = pack.execute(hyp, client, context)
294
+ except Exception:
295
+ test_res = None
296
+ f = correlator.correlate(hyp, test_res, apm)
297
+ if f:
298
+ findings.append(f)
299
+
300
+ store = FindingStore(repo_path / ".trace")
301
+ store.save_findings(findings)
302
+
303
+ return {
304
+ "status": "completed",
305
+ "total_findings": len(findings),
306
+ "confirmed": sum(1 for f in findings if f.confidence.value == "CONFIRMED"),
307
+ "endpoints_audited": len(discovered_endpoints),
308
+ }
309
+
310
+ elif name == "trace_attack_path":
311
+ endpoint_str = args.get("endpoint", "")
312
+ store = FindingStore(repo_path / ".trace")
313
+ for f in store.load_findings():
314
+ if endpoint_str.lower() in f.endpoint.lower():
315
+ return {"endpoint": f.endpoint, "attack_path": f.attack_path}
316
+ return {"endpoint": endpoint_str, "attack_path": []}
317
+
318
+ elif name == "trace_harness_task":
319
+ finding_id = args.get("finding_id", "")
320
+ from trace_engine.plugin import TraceHarnessPlugin
321
+ plugin = TraceHarnessPlugin(repo_path=repo_path, target_url=target_url)
322
+ task = plugin.get_task(finding_id)
323
+ if not task:
324
+ return {"error": f"Harness task for finding '{finding_id}' not found."}
325
+ return task.model_dump()
326
+
327
+ elif name == "trace_eval_patch":
328
+ finding_id = args.get("finding_id", "")
329
+ patch_content = args.get("patch_content")
330
+ target_file = args.get("target_file")
331
+ rollback = args.get("rollback_after", False)
332
+ from trace_engine.plugin import TraceHarnessPlugin
333
+ plugin = TraceHarnessPlugin(repo_path=repo_path, target_url=target_url)
334
+ eval_res = plugin.evaluate_patch(
335
+ finding_id=finding_id,
336
+ patch_content=patch_content,
337
+ target_file=target_file,
338
+ rollback_after=rollback,
339
+ )
340
+ return eval_res.model_dump()
341
+
342
+ return {"error": f"Unknown tool: {name}"}
343
+
344
+ def run_stdio(self):
345
+ """Run the stdio JSON-RPC loop supporting both line-delimited JSON and Content-Length headers."""
346
+ while self.running:
347
+ line = sys.stdin.readline()
348
+ if not line:
349
+ break
350
+ line_str = line.strip()
351
+ if not line_str:
352
+ continue
353
+
354
+ # Support Content-Length framing if sent by client
355
+ if line_str.lower().startswith("content-length:"):
356
+ try:
357
+ content_length = int(line_str.split(":", 1)[1].strip())
358
+ while True:
359
+ hdr = sys.stdin.readline()
360
+ if not hdr or hdr.strip() == "":
361
+ break
362
+ body = sys.stdin.read(content_length)
363
+ req = json.loads(body)
364
+ except Exception as e:
365
+ err_resp = {
366
+ "jsonrpc": "2.0",
367
+ "id": None,
368
+ "error": {"code": -32700, "message": f"Parse error: {e}"},
369
+ }
370
+ sys.stdout.write(json.dumps(err_resp) + "\n")
371
+ sys.stdout.flush()
372
+ continue
373
+ else:
374
+ try:
375
+ req = json.loads(line_str)
376
+ except Exception as e:
377
+ err_resp = {
378
+ "jsonrpc": "2.0",
379
+ "id": None,
380
+ "error": {"code": -32700, "message": f"Parse error: {e}"},
381
+ }
382
+ sys.stdout.write(json.dumps(err_resp) + "\n")
383
+ sys.stdout.flush()
384
+ continue
385
+
386
+ try:
387
+ resp = self.handle_request(req)
388
+ if resp is not None:
389
+ sys.stdout.write(json.dumps(resp) + "\n")
390
+ sys.stdout.flush()
391
+ except Exception as e:
392
+ err_resp = {
393
+ "jsonrpc": "2.0",
394
+ "id": req.get("id") if isinstance(req, dict) else None,
395
+ "error": {"code": -32603, "message": f"Internal error: {e}"},
396
+ }
397
+ sys.stdout.write(json.dumps(err_resp) + "\n")
398
+ sys.stdout.flush()
@@ -0,0 +1,28 @@
1
+ """Output and rendering module."""
2
+
3
+ from trace_engine.output.terminal import (
4
+ print_banner,
5
+ print_security_notes,
6
+ print_endpoints_table,
7
+ print_hypotheses_table,
8
+ print_findings_table,
9
+ print_finding_detail,
10
+ print_doctor_report,
11
+ )
12
+ from trace_engine.output.markdown import generate_markdown_report
13
+ from trace_engine.output.html import generate_html_report
14
+ from trace_engine.output.sarif import generate_sarif_report, export_sarif_json
15
+
16
+ __all__ = [
17
+ "print_banner",
18
+ "print_security_notes",
19
+ "print_endpoints_table",
20
+ "print_hypotheses_table",
21
+ "print_findings_table",
22
+ "print_finding_detail",
23
+ "print_doctor_report",
24
+ "generate_markdown_report",
25
+ "generate_html_report",
26
+ "generate_sarif_report",
27
+ "export_sarif_json",
28
+ ]
@@ -0,0 +1,142 @@
1
+ """Standalone dark-themed HTML report generator with green accents."""
2
+
3
+ import html
4
+ from typing import List
5
+ from trace_engine.findings.model import Finding
6
+
7
+
8
+ def generate_html_report(findings: List[Finding], project_name: str = "Application") -> str:
9
+ cards = []
10
+ for f in findings:
11
+ sev_color = {
12
+ "CRITICAL": "#ff4d4d",
13
+ "HIGH": "#ff7733",
14
+ "MEDIUM": "#ffcc00",
15
+ "LOW": "#33ccff",
16
+ }.get(f.severity.value, "#888888")
17
+
18
+ cards.append(f"""
19
+ <div class="card">
20
+ <div class="card-header">
21
+ <span class="finding-id">{html.escape(f.id)}</span>
22
+ <span class="badge" style="background: {sev_color}; color: #000;">{f.severity.value}</span>
23
+ <span class="badge badge-conf">{f.confidence.value}</span>
24
+ <span class="category">{html.escape(f.category)}</span>
25
+ </div>
26
+ <h3 class="card-title">{html.escape(f.title)}</h3>
27
+ <p class="endpoint"><code>{html.escape(f.endpoint)}</code></p>
28
+ <div class="section-title">Static Code Evidence</div>
29
+ <ul>{"".join(f"<li>{html.escape(e)}</li>" for e in f.static_evidence)}</ul>
30
+ <div class="section-title">Runtime Behavioral Evidence</div>
31
+ <ul>{"".join(f"<li>{html.escape(e)}</li>" for e in f.runtime_evidence)}</ul>
32
+ <div class="section-title">Remediation</div>
33
+ <p class="remediation">{html.escape(f.remediation)}</p>
34
+ </div>
35
+ """)
36
+
37
+ return f"""<!DOCTYPE html>
38
+ <html lang="en">
39
+ <head>
40
+ <meta charset="UTF-8">
41
+ <title>TRACE Report — {html.escape(project_name)}</title>
42
+ <style>
43
+ body {{
44
+ background-color: #0c0d0e;
45
+ color: #e6edf3;
46
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace;
47
+ margin: 0;
48
+ padding: 30px;
49
+ }}
50
+ .header {{
51
+ border-bottom: 1px solid #21262d;
52
+ padding-bottom: 20px;
53
+ margin-bottom: 30px;
54
+ }}
55
+ h1 {{
56
+ color: #00FF66;
57
+ margin: 0 0 8px 0;
58
+ font-size: 28px;
59
+ letter-spacing: -0.5px;
60
+ }}
61
+ .subtitle {{
62
+ color: #8b949e;
63
+ font-size: 14px;
64
+ }}
65
+ .card {{
66
+ background: #161b22;
67
+ border: 1px solid #30363d;
68
+ border-radius: 8px;
69
+ padding: 20px;
70
+ margin-bottom: 20px;
71
+ }}
72
+ .card-header {{
73
+ display: flex;
74
+ align-items: center;
75
+ gap: 12px;
76
+ margin-bottom: 12px;
77
+ }}
78
+ .finding-id {{
79
+ font-family: monospace;
80
+ font-weight: bold;
81
+ color: #00FF66;
82
+ }}
83
+ .badge {{
84
+ font-size: 11px;
85
+ font-weight: bold;
86
+ padding: 2px 8px;
87
+ border-radius: 4px;
88
+ text-transform: uppercase;
89
+ }}
90
+ .badge-conf {{
91
+ background: #00FF66;
92
+ color: #000;
93
+ }}
94
+ .category {{
95
+ color: #8b949e;
96
+ font-size: 12px;
97
+ }}
98
+ .card-title {{
99
+ margin: 0 0 10px 0;
100
+ font-size: 18px;
101
+ }}
102
+ code {{
103
+ background: #0d1117;
104
+ padding: 4px 8px;
105
+ border-radius: 4px;
106
+ color: #00FF66;
107
+ }}
108
+ .section-title {{
109
+ font-size: 12px;
110
+ font-weight: bold;
111
+ color: #8b949e;
112
+ text-transform: uppercase;
113
+ margin-top: 15px;
114
+ margin-bottom: 5px;
115
+ }}
116
+ ul {{
117
+ margin: 0 0 10px 0;
118
+ padding-left: 20px;
119
+ color: #c9d1d9;
120
+ font-size: 14px;
121
+ }}
122
+ .remediation {{
123
+ background: #0d1117;
124
+ border-left: 3px solid #00FF66;
125
+ padding: 10px 14px;
126
+ font-size: 13px;
127
+ color: #8b949e;
128
+ margin: 5px 0 0 0;
129
+ }}
130
+ </style>
131
+ </head>
132
+ <body>
133
+ <div class="header">
134
+ <h1>TRACE Security Assessment</h1>
135
+ <div class="subtitle">Threat Reconnaissance & Attack-path Correlation Engine • {html.escape(project_name)}</div>
136
+ </div>
137
+ <div class="findings-container">
138
+ {"".join(cards) if cards else "<p>No correlated vulnerabilities detected.</p>"}
139
+ </div>
140
+ </body>
141
+ </html>
142
+ """