actshield 0.9.0__py3-none-any.whl

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 (366) hide show
  1. actshield/__init__.py +439 -0
  2. actshield/__main__.py +46 -0
  3. actshield/agents/__init__.py +12 -0
  4. actshield/agents/agent.py +200 -0
  5. actshield/agents/identity.py +114 -0
  6. actshield/api/__init__.py +34 -0
  7. actshield/api/models.py +198 -0
  8. actshield/api/server.py +669 -0
  9. actshield/api/service.py +599 -0
  10. actshield/approval/__init__.py +15 -0
  11. actshield/approval/approval.py +164 -0
  12. actshield/cli/__init__.py +8 -0
  13. actshield/cli/graph.py +49 -0
  14. actshield/cli/main.py +802 -0
  15. actshield/cli/shell.py +406 -0
  16. actshield/cli/theme.py +110 -0
  17. actshield/client.py +757 -0
  18. actshield/config.py +88 -0
  19. actshield/context/__init__.py +14 -0
  20. actshield/context/context.py +161 -0
  21. actshield/context/provenance.py +108 -0
  22. actshield/context/taint.py +48 -0
  23. actshield/decisions/decision.py +74 -0
  24. actshield/delegation/__init__.py +11 -0
  25. actshield/delegation/authority.py +63 -0
  26. actshield/delegation/delegation.py +180 -0
  27. actshield/demo.py +139 -0
  28. actshield/doctor.py +94 -0
  29. actshield/drift/__init__.py +27 -0
  30. actshield/drift/drift_engine.py +149 -0
  31. actshield/drift/drift_models.py +63 -0
  32. actshield/evaluation/__init__.py +1 -0
  33. actshield/evaluation/cases/__init__.py +1 -0
  34. actshield/evaluation/eval_suite.py +254 -0
  35. actshield/forensics/__init__.py +53 -0
  36. actshield/forensics/access_graph.py +216 -0
  37. actshield/forensics/authority_graph.py +186 -0
  38. actshield/forensics/delegation_graph.py +119 -0
  39. actshield/forensics/explanation.py +254 -0
  40. actshield/forensics/models.py +488 -0
  41. actshield/forensics/queries.py +367 -0
  42. actshield/forensics/serializers.py +68 -0
  43. actshield/forensics/service.py +310 -0
  44. actshield/forensics/snapshots.py +174 -0
  45. actshield/gates/__init__.py +13 -0
  46. actshield/gates/gate_models.py +46 -0
  47. actshield/gates/security_gate.py +191 -0
  48. actshield/gateway/__init__.py +13 -0
  49. actshield/gateway/http.py +191 -0
  50. actshield/gateway/mcp.py +292 -0
  51. actshield/incidents/__init__.py +25 -0
  52. actshield/incidents/incident.py +94 -0
  53. actshield/incidents/incident_engine.py +163 -0
  54. actshield/incidents/incident_rules.py +116 -0
  55. actshield/incidents/incident_state.py +58 -0
  56. actshield/integrations/__init__.py +24 -0
  57. actshield/integrations/ai_secura.py +169 -0
  58. actshield/integrations/ai_secura_analysis.py +236 -0
  59. actshield/integrations/apiris.py +122 -0
  60. actshield/integrations/few_shot.py +104 -0
  61. actshield/integrations/ollama_adapter.py +538 -0
  62. actshield/integrations/prompts/__init__.py +1 -0
  63. actshield/integrations/prompts/examples/__init__.py +1 -0
  64. actshield/integrations/security_packet.py +82 -0
  65. actshield/llm_config.py +89 -0
  66. actshield/offensive/__init__.py +95 -0
  67. actshield/offensive/adaptive/__init__.py +22 -0
  68. actshield/offensive/adaptive/adaptive_engine.py +165 -0
  69. actshield/offensive/adaptive/attack_selector.py +51 -0
  70. actshield/offensive/adaptive/boundary_search.py +99 -0
  71. actshield/offensive/adaptive/campaign_memory.py +123 -0
  72. actshield/offensive/adaptive/feedback.py +84 -0
  73. actshield/offensive/adaptive/mutation_planner.py +57 -0
  74. actshield/offensive/attack.py +78 -0
  75. actshield/offensive/campaign.py +219 -0
  76. actshield/offensive/corpus.py +155 -0
  77. actshield/offensive/engine.py +466 -0
  78. actshield/offensive/evaluator.py +116 -0
  79. actshield/offensive/evidence.py +63 -0
  80. actshield/offensive/generator.py +128 -0
  81. actshield/offensive/mutation.py +101 -0
  82. actshield/offensive/results.py +77 -0
  83. actshield/offensive/safety.py +80 -0
  84. actshield/offensive/strategies/__init__.py +22 -0
  85. actshield/offensive/strategies/authority_escalation.py +100 -0
  86. actshield/offensive/strategies/base.py +34 -0
  87. actshield/offensive/strategies/context_manipulation.py +100 -0
  88. actshield/offensive/strategies/data_exfiltration.py +100 -0
  89. actshield/offensive/strategies/delegation_attacks.py +100 -0
  90. actshield/offensive/strategies/mcp_attacks.py +100 -0
  91. actshield/offensive/strategies/prompt_injection.py +100 -0
  92. actshield/offensive/strategies/tool_poisoning.py +100 -0
  93. actshield/offensive/target.py +113 -0
  94. actshield/offensive/vulnerable_target.py +121 -0
  95. actshield/persistence/__init__.py +18 -0
  96. actshield/persistence/siem.py +102 -0
  97. actshield/persistence/storage.py +240 -0
  98. actshield/policy/__init__.py +12 -0
  99. actshield/policy/evaluator.py +294 -0
  100. actshield/policy/intent.py +113 -0
  101. actshield/policy/policy.py +48 -0
  102. actshield/posture/__init__.py +26 -0
  103. actshield/posture/posture_engine.py +186 -0
  104. actshield/posture/posture_models.py +152 -0
  105. actshield/posture/posture_rules.py +137 -0
  106. actshield/providers/__init__.py +32 -0
  107. actshield/providers/anthropic_provider.py +146 -0
  108. actshield/providers/base.py +160 -0
  109. actshield/providers/gemini_provider.py +133 -0
  110. actshield/providers/null_provider.py +40 -0
  111. actshield/providers/ollama_provider.py +135 -0
  112. actshield/providers/openai_provider.py +142 -0
  113. actshield/providers/registry.py +244 -0
  114. actshield/py.typed +0 -0
  115. actshield/response/__init__.py +14 -0
  116. actshield/response/response_actions.py +39 -0
  117. actshield/response/response_audit.py +32 -0
  118. actshield/response/response_engine.py +139 -0
  119. actshield/risk/models.py +104 -0
  120. actshield/serve.py +117 -0
  121. actshield/static/404.html +1 -0
  122. actshield/static/__next.__PAGE__.txt +24 -0
  123. actshield/static/__next._full.txt +20 -0
  124. actshield/static/__next._tree.txt +4 -0
  125. actshield/static/_next/static/Yp_swxN-C9UoCRNOwkYnY/_buildManifest.js +11 -0
  126. actshield/static/_next/static/Yp_swxN-C9UoCRNOwkYnY/_clientMiddlewareManifest.js +1 -0
  127. actshield/static/_next/static/Yp_swxN-C9UoCRNOwkYnY/_ssgManifest.js +1 -0
  128. actshield/static/_next/static/chunks/09kny2eqjc2or.js +1 -0
  129. actshield/static/_next/static/chunks/0c1zba1u9whdp.js +1 -0
  130. actshield/static/_next/static/chunks/0cz1d0mv5g_q7.js +1 -0
  131. actshield/static/_next/static/chunks/0dbjjeg01x25o.js +1 -0
  132. actshield/static/_next/static/chunks/0duobs55ne238.js +1 -0
  133. actshield/static/_next/static/chunks/0iaz41l6068e4.js +1 -0
  134. actshield/static/_next/static/chunks/0mjhyv72x2idp.js +1 -0
  135. actshield/static/_next/static/chunks/0nelpqfu_ciq6.js +1 -0
  136. actshield/static/_next/static/chunks/0p1bci9ch797v.js +1 -0
  137. actshield/static/_next/static/chunks/0tld_ygho5tgm.js +1 -0
  138. actshield/static/_next/static/chunks/0w1-y7oni66j9.js +1 -0
  139. actshield/static/_next/static/chunks/10537zyl427zj.js +1 -0
  140. actshield/static/_next/static/chunks/11pc_jkl3aggn.js +1 -0
  141. actshield/static/_next/static/chunks/16k7nw0b3t8ys.js +1 -0
  142. actshield/static/_next/static/chunks/19mx3mg6lkumu.js +1 -0
  143. actshield/static/_next/static/chunks/1_8p47b-kxg2a.js +1 -0
  144. actshield/static/_next/static/chunks/1dszjozwfqegx.js +1 -0
  145. actshield/static/_next/static/chunks/1h43jcb90-m2r.js +22 -0
  146. actshield/static/_next/static/chunks/1ly04cvt_wh_j.js +1 -0
  147. actshield/static/_next/static/chunks/1odxrypuwuwp_.js +1 -0
  148. actshield/static/_next/static/chunks/1oes4c35qz5ku.js +1 -0
  149. actshield/static/_next/static/chunks/1ow883jl4ln-r.js +16 -0
  150. actshield/static/_next/static/chunks/1po7bna1as8tc.js +1 -0
  151. actshield/static/_next/static/chunks/1rsh0og8ifkzx.js +1 -0
  152. actshield/static/_next/static/chunks/1v0lwzv-859z_.js +1 -0
  153. actshield/static/_next/static/chunks/25iat2epwx25a.js +1 -0
  154. actshield/static/_next/static/chunks/25uvt4s2f39a4.js +1 -0
  155. actshield/static/_next/static/chunks/27t_qfc-3_lzs.js +1 -0
  156. actshield/static/_next/static/chunks/28bkmy8mez7gm.js +1 -0
  157. actshield/static/_next/static/chunks/2b6brmw_drw1p.js +1 -0
  158. actshield/static/_next/static/chunks/2fnhtxi4j6vge.js +1 -0
  159. actshield/static/_next/static/chunks/2p087eftxemg4.js +6 -0
  160. actshield/static/_next/static/chunks/2s8pao_z8pgtq.js +1 -0
  161. actshield/static/_next/static/chunks/2yj7ooc2c-zpg.js +1 -0
  162. actshield/static/_next/static/chunks/3-mrrr8udt5tk.js +1 -0
  163. actshield/static/_next/static/chunks/310vm2bl3xxpt.js +31 -0
  164. actshield/static/_next/static/chunks/35mvsv251jx1r.css +3 -0
  165. actshield/static/_next/static/chunks/370vf0oetlsx9.js +1 -0
  166. actshield/static/_next/static/chunks/3e-2m72tyo556.js +1 -0
  167. actshield/static/_next/static/chunks/3fntmmi971322.js +1 -0
  168. actshield/static/_next/static/chunks/3fzw-g0hycl2c.js +1 -0
  169. actshield/static/_next/static/chunks/3lopq3lhmcjxg.js +129 -0
  170. actshield/static/_next/static/chunks/3mpe2jejel0v2.css +1 -0
  171. actshield/static/_next/static/chunks/3t8o4f2lzr2sf.js +1 -0
  172. actshield/static/_next/static/chunks/3y-v1neyllne5.js +1 -0
  173. actshield/static/_next/static/chunks/43oiwy8mx6cs1.js +1 -0
  174. actshield/static/_next/static/chunks/turbopack-23wzuebcy_lxm.js +1 -0
  175. actshield/static/_next/static/media/1bffadaabf893a1e-s.3-6t-g6q0vh0a.woff2 +0 -0
  176. actshield/static/_next/static/media/2bbe8d2671613f1f-s.0k62hbripvv8p.woff2 +0 -0
  177. actshield/static/_next/static/media/2c55a0e60120577a-s.0-dom-5bn10r2.woff2 +0 -0
  178. actshield/static/_next/static/media/5476f68d60460930-s.2uwcyprjm3xu3.woff2 +0 -0
  179. actshield/static/_next/static/media/83afe278b6a6bb3c-s.p.2bn3s6zvc0dyp.woff2 +0 -0
  180. actshield/static/_next/static/media/9c72aa0f40e4eef8-s.1y4-pdgsjb-pw.woff2 +0 -0
  181. actshield/static/_next/static/media/ad66f9afd8947f86-s.3lvt2whj97whp.woff2 +0 -0
  182. actshield/static/_next/static/media/favicon.2vob68tjqpejf.ico +0 -0
  183. actshield/static/_not-found/__next._full.txt +17 -0
  184. actshield/static/_not-found/__next._not-found/__PAGE__.txt +23 -0
  185. actshield/static/_not-found/__next._tree.txt +3 -0
  186. actshield/static/_not-found.html +1 -0
  187. actshield/static/_not-found.txt +17 -0
  188. actshield/static/access/matrix/__next._full.txt +24 -0
  189. actshield/static/access/matrix/__next._tree.txt +4 -0
  190. actshield/static/access/matrix/__next.access/matrix/__PAGE__.txt +30 -0
  191. actshield/static/access/matrix.html +1 -0
  192. actshield/static/access/matrix.txt +24 -0
  193. actshield/static/activity/__next._full.txt +22 -0
  194. actshield/static/activity/__next._tree.txt +4 -0
  195. actshield/static/activity/__next.activity/__PAGE__.txt +27 -0
  196. actshield/static/activity.html +1 -0
  197. actshield/static/activity.txt +22 -0
  198. actshield/static/agents/__next._full.txt +22 -0
  199. actshield/static/agents/__next._tree.txt +4 -0
  200. actshield/static/agents/__next.agents/__PAGE__.txt +27 -0
  201. actshield/static/agents.html +1 -0
  202. actshield/static/agents.txt +22 -0
  203. actshield/static/ai-secura/__next._full.txt +22 -0
  204. actshield/static/ai-secura/__next._tree.txt +4 -0
  205. actshield/static/ai-secura/__next.ai-secura/__PAGE__.txt +27 -0
  206. actshield/static/ai-secura.html +1 -0
  207. actshield/static/ai-secura.txt +22 -0
  208. actshield/static/api/__next._full.txt +22 -0
  209. actshield/static/api/__next._tree.txt +4 -0
  210. actshield/static/api/__next.api/__PAGE__.txt +27 -0
  211. actshield/static/api.html +15 -0
  212. actshield/static/api.txt +22 -0
  213. actshield/static/apiris/__next._full.txt +22 -0
  214. actshield/static/apiris/__next._tree.txt +4 -0
  215. actshield/static/apiris/__next.apiris/__PAGE__.txt +27 -0
  216. actshield/static/apiris.html +1 -0
  217. actshield/static/apiris.txt +22 -0
  218. actshield/static/attack-graph/__next._full.txt +23 -0
  219. actshield/static/attack-graph/__next._tree.txt +5 -0
  220. actshield/static/attack-graph/__next.attack-graph/__PAGE__.txt +28 -0
  221. actshield/static/attack-graph.html +2 -0
  222. actshield/static/attack-graph.txt +23 -0
  223. actshield/static/campaigns/__next._full.txt +22 -0
  224. actshield/static/campaigns/__next._tree.txt +4 -0
  225. actshield/static/campaigns/__next.campaigns/__PAGE__.txt +27 -0
  226. actshield/static/campaigns.html +1 -0
  227. actshield/static/campaigns.txt +22 -0
  228. actshield/static/context/__next._full.txt +22 -0
  229. actshield/static/context/__next._tree.txt +4 -0
  230. actshield/static/context/__next.context/__PAGE__.txt +27 -0
  231. actshield/static/context.html +1 -0
  232. actshield/static/context.txt +22 -0
  233. actshield/static/dashboard/__next._full.txt +22 -0
  234. actshield/static/dashboard/__next._tree.txt +4 -0
  235. actshield/static/dashboard/__next.dashboard/__PAGE__.txt +27 -0
  236. actshield/static/dashboard.html +1 -0
  237. actshield/static/dashboard.txt +22 -0
  238. actshield/static/delegations/__next._full.txt +22 -0
  239. actshield/static/delegations/__next._tree.txt +4 -0
  240. actshield/static/delegations/__next.delegations/__PAGE__.txt +27 -0
  241. actshield/static/delegations.html +1 -0
  242. actshield/static/delegations.txt +22 -0
  243. actshield/static/demo/__next._full.txt +22 -0
  244. actshield/static/demo/__next._tree.txt +4 -0
  245. actshield/static/demo/__next.demo/__PAGE__.txt +27 -0
  246. actshield/static/demo.html +1 -0
  247. actshield/static/demo.txt +22 -0
  248. actshield/static/drift/__next._full.txt +22 -0
  249. actshield/static/drift/__next._tree.txt +4 -0
  250. actshield/static/drift/__next.drift/__PAGE__.txt +27 -0
  251. actshield/static/drift.html +1 -0
  252. actshield/static/drift.txt +22 -0
  253. actshield/static/favicon.ico +0 -0
  254. actshield/static/file.svg +1 -0
  255. actshield/static/forensics/__next._full.txt +22 -0
  256. actshield/static/forensics/__next._tree.txt +4 -0
  257. actshield/static/forensics/__next.forensics/__PAGE__.txt +27 -0
  258. actshield/static/forensics.html +1 -0
  259. actshield/static/forensics.txt +22 -0
  260. actshield/static/globe.svg +1 -0
  261. actshield/static/incidents/__next._full.txt +22 -0
  262. actshield/static/incidents/__next._tree.txt +4 -0
  263. actshield/static/incidents/__next.incidents/__PAGE__.txt +27 -0
  264. actshield/static/incidents.html +1 -0
  265. actshield/static/incidents.txt +22 -0
  266. actshield/static/index.html +3 -0
  267. actshield/static/index.txt +20 -0
  268. actshield/static/logo.png +0 -0
  269. actshield/static/metrics/__next._full.txt +22 -0
  270. actshield/static/metrics/__next._tree.txt +4 -0
  271. actshield/static/metrics/__next.metrics/__PAGE__.txt +27 -0
  272. actshield/static/metrics.html +1 -0
  273. actshield/static/metrics.txt +22 -0
  274. actshield/static/next.svg +1 -0
  275. actshield/static/offensive/__next._full.txt +22 -0
  276. actshield/static/offensive/__next._tree.txt +4 -0
  277. actshield/static/offensive/__next.offensive/__PAGE__.txt +27 -0
  278. actshield/static/offensive.html +1 -0
  279. actshield/static/offensive.txt +22 -0
  280. actshield/static/policies/__next._full.txt +22 -0
  281. actshield/static/policies/__next._tree.txt +4 -0
  282. actshield/static/policies/__next.policies/__PAGE__.txt +27 -0
  283. actshield/static/policies.html +1 -0
  284. actshield/static/policies.txt +22 -0
  285. actshield/static/posture/__next._full.txt +22 -0
  286. actshield/static/posture/__next._tree.txt +4 -0
  287. actshield/static/posture/__next.posture/__PAGE__.txt +27 -0
  288. actshield/static/posture.html +1 -0
  289. actshield/static/posture.txt +22 -0
  290. actshield/static/regressions/__next._full.txt +22 -0
  291. actshield/static/regressions/__next._tree.txt +4 -0
  292. actshield/static/regressions/__next.regressions/__PAGE__.txt +27 -0
  293. actshield/static/regressions.html +1 -0
  294. actshield/static/regressions.txt +22 -0
  295. actshield/static/reports/__next._full.txt +22 -0
  296. actshield/static/reports/__next._tree.txt +4 -0
  297. actshield/static/reports/__next.reports/__PAGE__.txt +27 -0
  298. actshield/static/reports.html +1 -0
  299. actshield/static/reports.txt +22 -0
  300. actshield/static/resources/__next._full.txt +22 -0
  301. actshield/static/resources/__next._tree.txt +4 -0
  302. actshield/static/resources/__next.resources/__PAGE__.txt +27 -0
  303. actshield/static/resources.html +1 -0
  304. actshield/static/resources.txt +22 -0
  305. actshield/static/security-gates/__next._full.txt +22 -0
  306. actshield/static/security-gates/__next._tree.txt +4 -0
  307. actshield/static/security-gates/__next.security-gates/__PAGE__.txt +27 -0
  308. actshield/static/security-gates.html +1 -0
  309. actshield/static/security-gates.txt +22 -0
  310. actshield/static/settings/__next._full.txt +22 -0
  311. actshield/static/settings/__next._tree.txt +4 -0
  312. actshield/static/settings/__next.settings/__PAGE__.txt +27 -0
  313. actshield/static/settings.html +1 -0
  314. actshield/static/settings.txt +22 -0
  315. actshield/static/tasks/__next._full.txt +22 -0
  316. actshield/static/tasks/__next._tree.txt +4 -0
  317. actshield/static/tasks/__next.tasks/__PAGE__.txt +27 -0
  318. actshield/static/tasks.html +1 -0
  319. actshield/static/tasks.txt +22 -0
  320. actshield/static/threats/__next._full.txt +22 -0
  321. actshield/static/threats/__next._tree.txt +4 -0
  322. actshield/static/threats/__next.threats/__PAGE__.txt +27 -0
  323. actshield/static/threats.html +1 -0
  324. actshield/static/threats.txt +22 -0
  325. actshield/static/tools/__next._full.txt +22 -0
  326. actshield/static/tools/__next._tree.txt +4 -0
  327. actshield/static/tools/__next.tools/__PAGE__.txt +27 -0
  328. actshield/static/tools.html +1 -0
  329. actshield/static/tools.txt +22 -0
  330. actshield/static/traces/__next._full.txt +22 -0
  331. actshield/static/traces/__next._tree.txt +4 -0
  332. actshield/static/traces/__next.traces/__PAGE__.txt +27 -0
  333. actshield/static/traces.html +1 -0
  334. actshield/static/traces.txt +22 -0
  335. actshield/static/vercel.svg +1 -0
  336. actshield/static/window.svg +1 -0
  337. actshield/tasks/__init__.py +6 -0
  338. actshield/tasks/task.py +143 -0
  339. actshield/threatmodel/__init__.py +70 -0
  340. actshield/threatmodel/actors.py +210 -0
  341. actshield/threatmodel/analyzer.py +131 -0
  342. actshield/threatmodel/assets.py +167 -0
  343. actshield/threatmodel/boundaries.py +165 -0
  344. actshield/threatmodel/exporters.py +49 -0
  345. actshield/threatmodel/mitigations.py +209 -0
  346. actshield/threatmodel/models.py +80 -0
  347. actshield/threatmodel/report.py +341 -0
  348. actshield/threatmodel/scenarios.py +212 -0
  349. actshield/threatmodel/scoring.py +66 -0
  350. actshield/threatmodel/threats.py +387 -0
  351. actshield/tools/__init__.py +20 -0
  352. actshield/tools/interceptor.py +256 -0
  353. actshield/tools/tool.py +71 -0
  354. actshield/tracing/__init__.py +38 -0
  355. actshield/tracing/correlation.py +173 -0
  356. actshield/tracing/events.py +75 -0
  357. actshield/tracing/tracer.py +305 -0
  358. actshield/watch.py +129 -0
  359. actshield-0.9.0.dist-info/METADATA +57 -0
  360. actshield-0.9.0.dist-info/RECORD +366 -0
  361. actshield-0.9.0.dist-info/WHEEL +5 -0
  362. actshield-0.9.0.dist-info/entry_points.txt +4 -0
  363. actshield-0.9.0.dist-info/top_level.txt +2 -0
  364. agentguard/__init__.py +39 -0
  365. agentguard/__main__.py +8 -0
  366. agentguard/py.typed +1 -0
@@ -0,0 +1,488 @@
1
+ """Forensic data models — Clean structured representations of security state.
2
+
3
+ These models are NEW. They do NOT duplicate existing security models.
4
+ They reference existing models by ID and add forensic-specific views.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from datetime import datetime, timezone
10
+ from enum import Enum
11
+ from typing import Any, Dict, List, Optional
12
+ from pydantic import BaseModel, Field
13
+
14
+ from actshield.tracing.correlation import generate_id
15
+
16
+
17
+ # ---------------------------------------------------------------------------
18
+ # Enumerations
19
+ # ---------------------------------------------------------------------------
20
+
21
+ class AccessDecision(str, Enum):
22
+ """Forensic access decision classification."""
23
+ ALLOW = "ALLOW"
24
+ BLOCK = "BLOCK"
25
+ HITL = "HITL"
26
+ MONITOR = "MONITOR"
27
+ UNKNOWN = "UNKNOWN"
28
+
29
+
30
+ class IncidentType(str, Enum):
31
+ """Classification of security incident types."""
32
+ INDIRECT_PROMPT_INJECTION = "INDIRECT_PROMPT_INJECTION"
33
+ AUTHORITY_ESCALATION = "AUTHORITY_ESCALATION"
34
+ TAINT_PROPAGATION = "TAINT_PROPAGATION"
35
+ CAPABILITY_VIOLATION = "CAPABILITY_VIOLATION"
36
+ INTENT_VIOLATION = "INTENT_VIOLATION"
37
+ BYPASS_DETECTED = "BYPASS_DETECTED"
38
+ UNTRUSTED_SENSITIVE_ACCESS = "UNTRUSTED_SENSITIVE_ACCESS"
39
+ DELEGATION_VIOLATION = "DELEGATION_VIOLATION"
40
+ GENERIC = "GENERIC"
41
+
42
+
43
+ class IncidentSeverity(str, Enum):
44
+ """Incident severity tiers."""
45
+ CRITICAL = "CRITICAL"
46
+ HIGH = "HIGH"
47
+ MEDIUM = "MEDIUM"
48
+ LOW = "LOW"
49
+ INFO = "INFO"
50
+
51
+
52
+ class IncidentStatus(str, Enum):
53
+ """Incident containment status."""
54
+ CONTAINED = "CONTAINED"
55
+ ACTIVE = "ACTIVE"
56
+ INVESTIGATING = "INVESTIGATING"
57
+ RESOLVED = "RESOLVED"
58
+
59
+
60
+ # ---------------------------------------------------------------------------
61
+ # Graph Relationship Models
62
+ # ---------------------------------------------------------------------------
63
+
64
+ class AuthorityRelationship(BaseModel):
65
+ """A single authority edge: who delegated what to whom."""
66
+ relationship_id: str = Field(default_factory=lambda: generate_id("arl"))
67
+ source_agent_id: str
68
+ target_agent_id: str
69
+ relationship_type: str = "delegates"
70
+ capabilities: List[str] = Field(default_factory=list)
71
+ delegation_id: Optional[str] = None
72
+ task_id: Optional[str] = None
73
+ trace_id: Optional[str] = None
74
+ depth: int = 0
75
+ timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
76
+ status: str = "active"
77
+
78
+
79
+ class AccessRelationship(BaseModel):
80
+ """A single access edge: agent↔tool↔resource."""
81
+ relationship_id: str = Field(default_factory=lambda: generate_id("acc"))
82
+ agent_id: str
83
+ tool_name: str
84
+ resource_id: Optional[str] = None
85
+ resource_name: Optional[str] = None
86
+ decision: AccessDecision = AccessDecision.UNKNOWN
87
+ executed: bool = False
88
+ capability_required: Optional[str] = None
89
+ sensitivity: str = "UNKNOWN"
90
+ timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
91
+ trace_id: Optional[str] = None
92
+ task_id: Optional[str] = None
93
+ taint_state: str = "CLEAN"
94
+ reason_code: str = ""
95
+
96
+
97
+ class DelegationRelationship(BaseModel):
98
+ """Delegation chain edge — forensic representation of a Delegation record."""
99
+ delegation_id: str
100
+ delegator_agent_id: str
101
+ delegate_agent_id: str
102
+ granted_capabilities: List[str] = Field(default_factory=list)
103
+ depth: int = 0
104
+ parent_delegation_id: Optional[str] = None
105
+ task_id: Optional[str] = None
106
+ trace_id: Optional[str] = None
107
+ status: str = "active"
108
+ timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
109
+
110
+
111
+ # ---------------------------------------------------------------------------
112
+ # Access Attempt / Actual Access
113
+ # ---------------------------------------------------------------------------
114
+
115
+ class AccessAttempt(BaseModel):
116
+ """Records that an agent attempted to access a tool/resource."""
117
+ attempt_id: str = Field(default_factory=lambda: generate_id("att"))
118
+ agent_id: str
119
+ task_id: Optional[str] = None
120
+ trace_id: Optional[str] = None
121
+ tool_name: str
122
+ capability_requested: Optional[str] = None
123
+ required_capability: Optional[str] = None
124
+ resource_name: Optional[str] = None
125
+ resource_sensitivity: str = "UNKNOWN"
126
+ decision: AccessDecision = AccessDecision.UNKNOWN
127
+ policy_reason: str = ""
128
+ context_ids: List[str] = Field(default_factory=list)
129
+ taint_state: str = "CLEAN"
130
+ authority_contained: bool = True
131
+ executed: bool = False
132
+ execution_count: int = 0
133
+ timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
134
+
135
+ @property
136
+ def was_blocked(self) -> bool:
137
+ return self.decision == AccessDecision.BLOCK
138
+
139
+ @property
140
+ def was_allowed(self) -> bool:
141
+ return self.decision in (AccessDecision.ALLOW, AccessDecision.MONITOR)
142
+
143
+
144
+ class ActualAccess(BaseModel):
145
+ """Records confirmed execution — tool ran, resource was accessed."""
146
+ access_id: str = Field(default_factory=lambda: generate_id("axs"))
147
+ agent_id: str
148
+ tool_name: str
149
+ resource_name: Optional[str] = None
150
+ resource_sensitivity: str = "UNKNOWN"
151
+ execution_count: int = 1
152
+ sensitive_db_calls: int = 0
153
+ trace_id: Optional[str] = None
154
+ task_id: Optional[str] = None
155
+ timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
156
+
157
+
158
+ # ---------------------------------------------------------------------------
159
+ # Agent & Resource Access Profiles
160
+ # ---------------------------------------------------------------------------
161
+
162
+ class AgentAccessProfile(BaseModel):
163
+ """Complete forensic access profile for a single agent."""
164
+ agent_id: str
165
+ agent_name: str
166
+ trust_level: str = "medium"
167
+ declared_capabilities: List[str] = Field(default_factory=list)
168
+ delegated_capabilities: List[str] = Field(default_factory=list)
169
+ effective_capabilities: List[str] = Field(default_factory=list)
170
+ restricted_capabilities: List[str] = Field(default_factory=list)
171
+ reachable_tools: List[str] = Field(default_factory=list)
172
+ reachable_resources: List[str] = Field(default_factory=list)
173
+ recent_attempts: List[AccessAttempt] = Field(default_factory=list)
174
+ recent_actual_access: List[ActualAccess] = Field(default_factory=list)
175
+ delegation_chain: List[DelegationRelationship] = Field(default_factory=list)
176
+ total_attempts: int = 0
177
+ total_blocked: int = 0
178
+ total_allowed: int = 0
179
+ total_executions: int = 0
180
+ generated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
181
+
182
+
183
+ class ResourceAccessProfile(BaseModel):
184
+ """Complete forensic access profile for a single resource."""
185
+ resource_id: str
186
+ resource_name: str
187
+ resource_type: str = "api"
188
+ sensitivity: str = "MEDIUM"
189
+ exposing_tools: List[str] = Field(default_factory=list)
190
+ authorized_agents: List[str] = Field(default_factory=list)
191
+ attempted_agents: List[str] = Field(default_factory=list)
192
+ actual_access_agents: List[str] = Field(default_factory=list)
193
+ blocked_agents: List[str] = Field(default_factory=list)
194
+ access_history: List[AccessAttempt] = Field(default_factory=list)
195
+ total_attempts: int = 0
196
+ total_blocked: int = 0
197
+ total_executions: int = 0
198
+ generated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
199
+
200
+
201
+ # ---------------------------------------------------------------------------
202
+ # Access Matrix
203
+ # ---------------------------------------------------------------------------
204
+
205
+ class AccessMatrixEntry(BaseModel):
206
+ """Single cell in the access matrix: agent × resource."""
207
+ agent_id: str
208
+ resource_name: str
209
+ effective_permission: bool = False
210
+ historically_accessed: bool = False
211
+ attempted: bool = False
212
+ blocked: bool = False
213
+
214
+
215
+ class AccessMatrix(BaseModel):
216
+ """Machine-readable access matrix: agents × resources."""
217
+ matrix_id: str = Field(default_factory=lambda: generate_id("mat"))
218
+ agents: List[str] = Field(default_factory=list)
219
+ resources: List[str] = Field(default_factory=list)
220
+ # entries[agent_id][resource_name] = AccessMatrixEntry
221
+ entries: Dict[str, Dict[str, AccessMatrixEntry]] = Field(default_factory=dict)
222
+ generated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
223
+
224
+ def to_table(self) -> Dict[str, Any]:
225
+ """Return table-friendly representation."""
226
+ rows = {}
227
+ for agent in self.agents:
228
+ rows[agent] = {}
229
+ for resource in self.resources:
230
+ entry = self.entries.get(agent, {}).get(resource)
231
+ if entry:
232
+ if entry.effective_permission and entry.historically_accessed:
233
+ rows[agent][resource] = "YES (accessed)"
234
+ elif entry.effective_permission:
235
+ rows[agent][resource] = "YES"
236
+ elif entry.attempted:
237
+ rows[agent][resource] = "ATTEMPTED (blocked)"
238
+ else:
239
+ rows[agent][resource] = "NO"
240
+ else:
241
+ rows[agent][resource] = "NO"
242
+ return rows
243
+
244
+
245
+ # ---------------------------------------------------------------------------
246
+ # Access Snapshot & Diff
247
+ # ---------------------------------------------------------------------------
248
+
249
+ class AgentSnapshot(BaseModel):
250
+ """Point-in-time security state of one agent."""
251
+ agent_id: str
252
+ effective_capabilities: List[str] = Field(default_factory=list)
253
+ reachable_resources: List[str] = Field(default_factory=list)
254
+ active_delegations: List[str] = Field(default_factory=list)
255
+ taint_exposure: bool = False
256
+
257
+
258
+ class AccessSnapshot(BaseModel):
259
+ """Complete security state snapshot at a point in time."""
260
+ snapshot_id: str = Field(default_factory=lambda: generate_id("snp"))
261
+ label: str = "snapshot"
262
+ timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
263
+ agents: Dict[str, AgentSnapshot] = Field(default_factory=dict)
264
+ resources: Dict[str, Dict[str, Any]] = Field(default_factory=dict)
265
+ delegations: Dict[str, Dict[str, Any]] = Field(default_factory=dict)
266
+ context_count: int = 0
267
+ tainted_context_count: int = 0
268
+
269
+ def to_dict(self) -> Dict[str, Any]:
270
+ return self.model_dump(mode="json")
271
+
272
+
273
+ class AccessDiff(BaseModel):
274
+ """Before/after comparison of security state — distinguishes authority change from attack attempt."""
275
+ diff_id: str = Field(default_factory=lambda: generate_id("dif"))
276
+ before_snapshot_id: str
277
+ after_snapshot_id: str
278
+ authority_changed: bool = False
279
+ new_capabilities: List[str] = Field(default_factory=list)
280
+ lost_capabilities: List[str] = Field(default_factory=list)
281
+ new_attempts: List[AccessAttempt] = Field(default_factory=list)
282
+ new_actual_accesses: List[ActualAccess] = Field(default_factory=list)
283
+ taint_changed: bool = False
284
+ context_changed: bool = False
285
+ attack_detected: bool = False
286
+ attack_ids: List[str] = Field(default_factory=list)
287
+ summary: str = ""
288
+ generated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
289
+
290
+
291
+ # ---------------------------------------------------------------------------
292
+ # Forensic Explanation
293
+ # ---------------------------------------------------------------------------
294
+
295
+ class ForensicExplanation(BaseModel):
296
+ """Deterministic, evidence-backed explanation of a security decision.
297
+
298
+ Assembled entirely from existing evidence — no LLM inference.
299
+ """
300
+ explanation_id: str = Field(default_factory=lambda: generate_id("exp"))
301
+ event_id: Optional[str] = None
302
+ trace_id: Optional[str] = None
303
+ agent_id: str
304
+ tool_name: str
305
+ resource_name: Optional[str] = None
306
+ resource_sensitivity: str = "UNKNOWN"
307
+
308
+ # User intent
309
+ original_intent: str = "Unspecified"
310
+
311
+ # Influencing context
312
+ influencing_context_sources: List[str] = Field(default_factory=list)
313
+ influencing_context_ids: List[str] = Field(default_factory=list)
314
+ context_trust: str = "UNKNOWN"
315
+
316
+ # Taint
317
+ taint_state: str = "CLEAN"
318
+
319
+ # Authority chain
320
+ delegated_authority: List[str] = Field(default_factory=list)
321
+ requested_capability: Optional[str] = None
322
+ effective_authority: str = "DENIED" # "GRANTED" or "DENIED"
323
+
324
+ # Policy
325
+ policy_decision: AccessDecision = AccessDecision.UNKNOWN
326
+ policy_reason_code: str = ""
327
+ policy_explanation: str = ""
328
+
329
+ # Intelligence signals (references only)
330
+ ai_secura_summary: Optional[str] = None
331
+ apiris_summary: Optional[str] = None
332
+
333
+ # Hard execution evidence
334
+ tool_executed: bool = False
335
+ execution_count: int = 0
336
+ sensitive_db_calls: int = 0
337
+
338
+ # Bypass forensics (Phase 5 integration)
339
+ bypass_detected: bool = False
340
+ bypass_attack_id: Optional[str] = None
341
+ regression_created: bool = False
342
+
343
+ generated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
344
+
345
+ def to_text(self) -> str:
346
+ """Render human-readable forensic explanation."""
347
+ lines = [
348
+ "=" * 60,
349
+ f"FORENSIC EXPLANATION — {self.tool_name}",
350
+ "=" * 60,
351
+ f"Agent: {self.agent_id}",
352
+ f"Tool: {self.tool_name}",
353
+ f"Resource: {self.resource_name or 'N/A'}",
354
+ f"Sensitivity: {self.resource_sensitivity}",
355
+ "",
356
+ f"Original Intent: {self.original_intent}",
357
+ f"Context Sources: {', '.join(self.influencing_context_sources) or 'none'}",
358
+ f"Context Trust: {self.context_trust}",
359
+ f"Taint State: {self.taint_state}",
360
+ "",
361
+ f"Delegated Authority: {', '.join(self.delegated_authority) or 'none'}",
362
+ f"Requested Cap: {self.requested_capability or 'N/A'}",
363
+ f"Effective Authority: {self.effective_authority}",
364
+ "",
365
+ f"Policy Decision: {self.policy_decision.value}",
366
+ f"Reason Code: {self.policy_reason_code}",
367
+ f"Explanation: {self.policy_explanation}",
368
+ "",
369
+ ]
370
+ if self.ai_secura_summary:
371
+ lines.append(f"AI Secura: {self.ai_secura_summary}")
372
+ if self.apiris_summary:
373
+ lines.append(f"APIRIS: {self.apiris_summary}")
374
+ lines += [
375
+ "",
376
+ f"Tool Executed: {self.tool_executed}",
377
+ f"Execution Count: {self.execution_count}",
378
+ f"Sensitive DB Calls: {self.sensitive_db_calls}",
379
+ ]
380
+ if self.bypass_detected:
381
+ lines += [
382
+ "",
383
+ f"⚠ BYPASS DETECTED — Attack: {self.bypass_attack_id}",
384
+ f" Regression Created: {self.regression_created}",
385
+ ]
386
+ lines.append("=" * 60)
387
+ return "\n".join(lines)
388
+
389
+
390
+ # ---------------------------------------------------------------------------
391
+ # Attack Forensic Report
392
+ # ---------------------------------------------------------------------------
393
+
394
+ class AttackForensicReport(BaseModel):
395
+ """Unified forensic report for a single attack run.
396
+
397
+ Aggregates: attack metadata + mutation lineage + security pipeline
398
+ evidence + access impact + reachable resources + regression status.
399
+ Connects Phase 5 offensive evidence to the forensic layer.
400
+ """
401
+ report_id: str = Field(default_factory=lambda: generate_id("afr"))
402
+ attack_id: str
403
+ campaign_id: Optional[str] = None
404
+ attack_type: str = "UNKNOWN"
405
+ target: str = ""
406
+ entry_point: str = ""
407
+
408
+ # Agent & task context
409
+ agent_id: str = ""
410
+ task_id: Optional[str] = None
411
+ trace_id: Optional[str] = None
412
+ original_intent: str = ""
413
+
414
+ # Mutation lineage (Phase 5)
415
+ mutation_lineage: List[str] = Field(default_factory=list)
416
+ adaptive_iteration: int = 0
417
+ parent_attack_id: Optional[str] = None
418
+
419
+ # Context provenance
420
+ influencing_contexts: List[str] = Field(default_factory=list)
421
+ context_trust: str = "UNKNOWN"
422
+ taint_state: str = "TAINTED"
423
+
424
+ # Authority chain
425
+ delegated_capabilities: List[str] = Field(default_factory=list)
426
+ requested_capability: Optional[str] = None
427
+ effective_capabilities: List[str] = Field(default_factory=list)
428
+ authority_contained: bool = True
429
+
430
+ # Resource target
431
+ resource_name: Optional[str] = None
432
+ resource_sensitivity: str = "UNKNOWN"
433
+
434
+ # Intelligence signals
435
+ apiris_summary: Optional[str] = None
436
+ ai_secura_summary: Optional[str] = None
437
+ risk_score: float = 0.0
438
+
439
+ # Policy decision
440
+ policy_decision: AccessDecision = AccessDecision.UNKNOWN
441
+ policy_reason_code: str = ""
442
+ policy_explanation: str = ""
443
+
444
+ # Hard execution evidence
445
+ tool_executed: bool = False
446
+ execution_count: int = 0
447
+ sensitive_db_calls: int = 0
448
+
449
+ # Access impact
450
+ actual_access: bool = False
451
+ reachable_resources: List[str] = Field(default_factory=list)
452
+
453
+ # Outcome
454
+ bypassed: bool = False
455
+ expected_decision: str = "BLOCK"
456
+ actual_decision: str = "UNKNOWN"
457
+
458
+ # Remediation
459
+ remediation_status: str = "NONE"
460
+ regression_status: str = "NONE"
461
+ regression_fixture_id: Optional[str] = None
462
+
463
+ generated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
464
+
465
+
466
+ # ---------------------------------------------------------------------------
467
+ # Incident
468
+ # ---------------------------------------------------------------------------
469
+
470
+ class ForensicIncident(BaseModel):
471
+ """Unified incident — references (not duplicates) existing evidence."""
472
+ incident_id: str = Field(default_factory=lambda: generate_id("inc"))
473
+ incident_type: IncidentType = IncidentType.GENERIC
474
+ severity: IncidentSeverity = IncidentSeverity.HIGH
475
+ agent_id: Optional[str] = None
476
+ resource_name: Optional[str] = None
477
+ tool_name: Optional[str] = None
478
+ decision: AccessDecision = AccessDecision.UNKNOWN
479
+ executed: bool = False
480
+ # References (IDs only — no duplication)
481
+ trace_id: Optional[str] = None
482
+ attack_id: Optional[str] = None
483
+ decision_id: Optional[str] = None
484
+ campaign_id: Optional[str] = None
485
+ status: IncidentStatus = IncidentStatus.CONTAINED
486
+ description: str = ""
487
+ timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
488
+