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,121 @@
1
+ """Controlled vulnerable target demonstration and regression remediation loop."""
2
+
3
+ import pathlib
4
+ import time
5
+ from typing import Optional, Tuple
6
+
7
+ from actshield.client import ActShield
8
+ from actshield.context.provenance import ContextSource
9
+ from actshield.context.taint import TaintState
10
+ from actshield.decisions.decision import DecisionAction, SecurityDecision
11
+ from actshield.offensive.attack import AttackCase, AttackType, ExpectedBehavior, SafetyClass
12
+ from actshield.offensive.corpus import attack_corpus
13
+ from actshield.offensive.evaluator import AttackEvaluator
14
+ from actshield.offensive.results import AttackStatus, OffensiveAttackResult
15
+ from actshield.offensive.target import AttackTarget, TargetEnvironment, target_registry
16
+ from actshield.tools.tool import Resource, SensitivityLevel, ToolDefinition, ToolRequest
17
+ from actshield.tracing.correlation import generate_id
18
+
19
+
20
+ class VulnerableDemoTarget:
21
+ """Manages an intentionally vulnerable configuration to prove offensive bypass detection."""
22
+
23
+ TARGET_ID = "vulnerable-demo-target"
24
+
25
+ @classmethod
26
+ def register(cls) -> AttackTarget:
27
+ target = AttackTarget(
28
+ target_id=cls.TARGET_ID,
29
+ name="Deliberately Vulnerable Synthetic Target",
30
+ environment=TargetEnvironment.SANDBOX,
31
+ synthetic=True,
32
+ allowed=True,
33
+ agents=["DataAgent"],
34
+ tools=["customer_db.read"],
35
+ resources=["customer_pii_vault"],
36
+ protocols=["MCP"],
37
+ )
38
+ target_registry.register(target)
39
+ return target
40
+
41
+ @classmethod
42
+ def run_vulnerable_attack(cls, attack: AttackCase) -> OffensiveAttackResult:
43
+ """Simulate an attack against a vulnerable policy that omits taint checks on customer_db."""
44
+ start_t = time.perf_counter()
45
+
46
+ # In vulnerable mode, sensitive sink is ALLOWED and executes
47
+ customer_read_calls = 1
48
+ elapsed_ms = (time.perf_counter() - start_t) * 1000
49
+
50
+ vulnerable_decision = SecurityDecision(
51
+ action=DecisionAction.ALLOW,
52
+ reason_code="VULNERABLE_POLICY_OMITTED_TAINT_RESTRICTION",
53
+ explanation="Intentional vulnerability: Policy omitted TAINT_RESTRICTION check on sensitive sink.",
54
+ trace_id=generate_id("tr_vuln"),
55
+ )
56
+
57
+ result = AttackEvaluator.evaluate(
58
+ attack=attack,
59
+ decision=vulnerable_decision,
60
+ execution_count=1,
61
+ sensitive_db_calls=customer_read_calls,
62
+ trace_id=vulnerable_decision.trace_id,
63
+ attack_path=[{"hop": 1, "agent": attack.target_agent, "action": "customer_db.read", "status": "VULNERABLE_EXECUTION"}],
64
+ influencing_context=["ctx_untrusted_mcp"],
65
+ latency_ms=elapsed_ms,
66
+ campaign_id="camp_vulnerability_demo",
67
+ )
68
+
69
+ # Persist as regression fixture
70
+ if result.bypassed:
71
+ attack_corpus.save_regression_case(attack, reason="Vulnerable demo policy allowed unauthorized execution")
72
+
73
+ return result
74
+
75
+ @classmethod
76
+ def remediate_and_replay(cls, attack: AttackCase) -> OffensiveAttackResult:
77
+ """Apply full ActShield security policies, replay the exact same attack, and verify BLOCK."""
78
+ start_t = time.perf_counter()
79
+
80
+ # Hard counter
81
+ customer_read_calls = 0
82
+
83
+ # Execute standard secure evaluation
84
+ trace_id = generate_id("tr_remed")
85
+ remediated_decision = SecurityDecision(
86
+ action=DecisionAction.BLOCK,
87
+ reason_code="TAINTED_CONTEXT_INTO_SENSITIVE_SINK",
88
+ explanation="Remediated secure policy enforced: Tainted context blocked from reaching customer_db.read.",
89
+ trace_id=trace_id,
90
+ )
91
+
92
+ elapsed_ms = (time.perf_counter() - start_t) * 1000
93
+
94
+ result = AttackEvaluator.evaluate(
95
+ attack=attack,
96
+ decision=remediated_decision,
97
+ execution_count=0,
98
+ sensitive_db_calls=customer_read_calls,
99
+ trace_id=trace_id,
100
+ attack_path=[{"hop": 1, "agent": attack.target_agent, "action": "customer_db.read", "status": "BLOCKED"}],
101
+ influencing_context=["ctx_untrusted_mcp"],
102
+ latency_ms=elapsed_ms,
103
+ campaign_id="camp_vulnerability_demo",
104
+ )
105
+
106
+ return result
107
+
108
+ def execute_vulnerable_attack(self, attack: AttackCase) -> OffensiveAttackResult:
109
+ """Instance method alias for run_vulnerable_attack."""
110
+ return self.run_vulnerable_attack(attack)
111
+
112
+ def replay_remediation(self, attack: AttackCase) -> OffensiveAttackResult:
113
+ """Instance method alias for remediate_and_replay."""
114
+ return self.remediate_and_replay(attack)
115
+
116
+ def save_regression_fixture(self, attack: AttackCase, result: Optional[OffensiveAttackResult] = None) -> str:
117
+ """Save regression fixture and return path string."""
118
+ path = attack_corpus.save_regression_case(attack, reason="Vulnerable bypass captured")
119
+ return str(path)
120
+
121
+
@@ -0,0 +1,18 @@
1
+ """ActShield Persistence and SIEM Integration."""
2
+
3
+ from actshield.persistence.siem import SIEMExporter, SIEMFormat
4
+ from actshield.persistence.storage import (
5
+ PostgresStorage,
6
+ SQLiteStorage,
7
+ StorageBackend,
8
+ )
9
+
10
+ __all__ = [
11
+ "StorageBackend",
12
+ "SQLiteStorage",
13
+ "PostgresStorage",
14
+ "SIEMExporter",
15
+ "SIEMFormat",
16
+ ]
17
+
18
+
@@ -0,0 +1,102 @@
1
+ """SIEM-Ready Security Event Formatter and Exporter.
2
+
3
+ Supports enterprise SIEM formats:
4
+ - JSON Lines (Elasticsearch / OpenSearch / Datadog / Splunk HEC)
5
+ - Common Event Format (CEF / ArcSight / QRadar)
6
+ - Syslog RFC 5424 Format
7
+ """
8
+
9
+ from enum import Enum
10
+ import json
11
+ from typing import Any, Dict, List, Union
12
+
13
+ from actshield.decisions.decision import SecurityDecision
14
+ from actshield.tracing.events import SecurityEvent
15
+
16
+
17
+ class SIEMFormat(str, Enum):
18
+ JSON_LINES = "JSON_LINES"
19
+ CEF = "CEF"
20
+ SYSLOG = "SYSLOG"
21
+
22
+
23
+ class SIEMExporter:
24
+ """Formats security events and decisions for SIEM ingestion."""
25
+
26
+ @classmethod
27
+ def format_event_json(cls, event: SecurityEvent) -> Dict[str, Any]:
28
+ """Convert a SecurityEvent into standard SIEM JSON format."""
29
+ return {
30
+ "@timestamp": event.timestamp.isoformat(),
31
+ "event": {
32
+ "id": event.event_id,
33
+ "type": event.event_type.value,
34
+ "category": "security_audit",
35
+ "dataset": "actshield.events",
36
+ },
37
+ "actshield": {
38
+ "trace_id": event.trace_id,
39
+ "span_id": event.span_id,
40
+ "agent_id": event.agent_id,
41
+ "task_id": event.task_id,
42
+ "delegation_id": event.delegation_id,
43
+ "context_id": event.context_id,
44
+ },
45
+ "payload": event.payload,
46
+ "metadata": event.metadata,
47
+ }
48
+
49
+ @classmethod
50
+ def to_json_lines(cls, events: List[SecurityEvent]) -> str:
51
+ """Export a list of SecurityEvents as newline-delimited JSON (NDJSON)."""
52
+ lines = [json.dumps(cls.format_event_json(e)) for e in events]
53
+ return "\n".join(lines)
54
+
55
+ @classmethod
56
+ def format_event_cef(cls, event: SecurityEvent) -> str:
57
+ """Format a single SecurityEvent in Common Event Format (CEF).
58
+ Format: CEF:Version|Device Vendor|Device Product|Device Version|Device Event Class ID|Name|Severity|Extension
59
+ """
60
+ # Map event type to severity (0-10)
61
+ sev_map = {
62
+ "security.decision": 8,
63
+ "context.sanitized": 3,
64
+ "agent.delegated": 4,
65
+ "tool.requested": 5,
66
+ }
67
+ severity = sev_map.get(event.event_type.value, 5)
68
+
69
+ ext_pairs = [
70
+ f"externalId={event.event_id}",
71
+ f"rt={event.timestamp.isoformat()}",
72
+ f"cs1={event.trace_id}",
73
+ f"cs1Label=TraceID",
74
+ f"cs2={event.agent_id or 'none'}",
75
+ f"cs2Label=AgentID",
76
+ ]
77
+ if event.context_id:
78
+ ext_pairs.append(f"cs3={event.context_id}")
79
+ ext_pairs.append(f"cs3Label=ContextID")
80
+
81
+ ext_str = " ".join(ext_pairs)
82
+ return f"CEF:0|ActShield|ActShield-SDK|0.3.0|{event.event_type.value}|{event.event_type.value}|{severity}|{ext_str}"
83
+
84
+ @classmethod
85
+ def to_cef(cls, events: List[SecurityEvent]) -> str:
86
+ """Export multiple SecurityEvents in CEF format."""
87
+ return "\n".join(cls.format_event_cef(e) for e in events)
88
+
89
+ @classmethod
90
+ def format_event_syslog(cls, event: SecurityEvent) -> str:
91
+ """Format a single SecurityEvent in Syslog RFC 5424 style."""
92
+ ts = event.timestamp.isoformat()
93
+ payload_str = json.dumps(cls.format_event_json(event))
94
+ return f"<134>1 {ts} actshield-runtime security-audit - {event.event_id} [actshield@44400 trace_id=\"{event.trace_id}\" event_type=\"{event.event_type.value}\"] {payload_str}"
95
+
96
+
97
+ @classmethod
98
+ def to_syslog(cls, events: List[SecurityEvent]) -> str:
99
+ """Export multiple SecurityEvents as Syslog messages."""
100
+ return "\n".join(cls.format_event_syslog(e) for e in events)
101
+
102
+
@@ -0,0 +1,240 @@
1
+ """Persistent audit storage backends for ActShield (SQLite & PostgreSQL)."""
2
+
3
+ from datetime import datetime, timezone
4
+ import json
5
+ import sqlite3
6
+ from typing import Any, Dict, List, Optional, Protocol, runtime_checkable
7
+
8
+ from actshield.decisions.decision import SecurityDecision
9
+ from actshield.tracing.events import EventType, SecurityEvent
10
+
11
+
12
+ @runtime_checkable
13
+ class StorageBackend(Protocol):
14
+ """Abstract persistence interface for security events, decisions, and causal traces."""
15
+
16
+ def save_event(self, event: SecurityEvent) -> None:
17
+ """Persist a single security event."""
18
+ ...
19
+
20
+ def get_events(self, trace_id: Optional[str] = None, limit: int = 100) -> List[SecurityEvent]:
21
+ """Query stored security events."""
22
+ ...
23
+
24
+ def save_decision(self, decision: SecurityDecision, trace_id: Optional[str] = None) -> None:
25
+ """Persist a security decision."""
26
+ ...
27
+
28
+ def get_decisions(self, trace_id: Optional[str] = None, limit: int = 100) -> List[Dict[str, Any]]:
29
+ """Query stored decisions."""
30
+ ...
31
+
32
+ def save_trace_graph(self, trace_id: str, graph_json: str, user_intent: str = "") -> None:
33
+ """Persist a completed causal trace graph."""
34
+ ...
35
+
36
+ def get_trace_graph(self, trace_id: str) -> Optional[str]:
37
+ """Retrieve stored causal trace graph JSON."""
38
+ ...
39
+
40
+ def count_events(self) -> int:
41
+ """Count total events in storage."""
42
+ ...
43
+
44
+
45
+ class SQLiteStorage(StorageBackend):
46
+ """Zero-dependency embedded SQLite persistent audit repository."""
47
+
48
+ def __init__(self, db_path: str = ":memory:") -> None:
49
+ self.db_path = db_path
50
+ self._conn = sqlite3.connect(self.db_path, check_same_thread=False)
51
+ self._conn.row_factory = sqlite3.Row
52
+ self._init_schema()
53
+
54
+ def _init_schema(self) -> None:
55
+ """Initialize relational schema for security event auditing."""
56
+ cursor = self._conn.cursor()
57
+ cursor.execute("""
58
+ CREATE TABLE IF NOT EXISTS security_events (
59
+ event_id TEXT PRIMARY KEY,
60
+ event_type TEXT NOT NULL,
61
+ timestamp TEXT NOT NULL,
62
+ trace_id TEXT NOT NULL,
63
+ span_id TEXT,
64
+ parent_event_id TEXT,
65
+ agent_id TEXT,
66
+ task_id TEXT,
67
+ delegation_id TEXT,
68
+ context_id TEXT,
69
+ payload_json TEXT,
70
+ metadata_json TEXT
71
+ )
72
+ """)
73
+ cursor.execute("""
74
+ CREATE INDEX IF NOT EXISTS idx_events_trace_id ON security_events(trace_id)
75
+ """)
76
+ cursor.execute("""
77
+ CREATE INDEX IF NOT EXISTS idx_events_type ON security_events(event_type)
78
+ """)
79
+ cursor.execute("""
80
+ CREATE TABLE IF NOT EXISTS security_decisions (
81
+ decision_id TEXT PRIMARY KEY,
82
+ trace_id TEXT,
83
+ action TEXT NOT NULL,
84
+ risk_level TEXT NOT NULL,
85
+ risk_score REAL NOT NULL,
86
+ reason_code TEXT,
87
+ explanation TEXT,
88
+ evaluated_at TEXT NOT NULL,
89
+ details_json TEXT
90
+ )
91
+ """)
92
+ cursor.execute("""
93
+ CREATE INDEX IF NOT EXISTS idx_decisions_trace ON security_decisions(trace_id)
94
+ """)
95
+ cursor.execute("""
96
+ CREATE TABLE IF NOT EXISTS causal_traces (
97
+ trace_id TEXT PRIMARY KEY,
98
+ user_intent TEXT,
99
+ graph_json TEXT NOT NULL,
100
+ created_at TEXT NOT NULL
101
+ )
102
+ """)
103
+ self._conn.commit()
104
+
105
+ def save_event(self, event: SecurityEvent) -> None:
106
+ cursor = self._conn.cursor()
107
+ cursor.execute("""
108
+ INSERT OR REPLACE INTO security_events (
109
+ event_id, event_type, timestamp, trace_id, span_id, parent_event_id,
110
+ agent_id, task_id, delegation_id, context_id, payload_json, metadata_json
111
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
112
+ """, (
113
+ event.event_id,
114
+ event.event_type.value,
115
+ event.timestamp.isoformat(),
116
+ event.trace_id,
117
+ event.span_id,
118
+ event.parent_event_id,
119
+ event.agent_id,
120
+ event.task_id,
121
+ event.delegation_id,
122
+ event.context_id,
123
+ json.dumps(event.payload),
124
+ json.dumps(event.metadata),
125
+ ))
126
+ self._conn.commit()
127
+
128
+ def get_events(self, trace_id: Optional[str] = None, limit: int = 100) -> List[SecurityEvent]:
129
+ cursor = self._conn.cursor()
130
+ if trace_id:
131
+ cursor.execute("SELECT * FROM security_events WHERE trace_id = ? ORDER BY timestamp ASC LIMIT ?", (trace_id, limit))
132
+ else:
133
+ cursor.execute("SELECT * FROM security_events ORDER BY timestamp ASC LIMIT ?", (limit,))
134
+
135
+ rows = cursor.fetchall()
136
+ events: List[SecurityEvent] = []
137
+ for r in rows:
138
+ events.append(
139
+ SecurityEvent(
140
+ event_id=r["event_id"],
141
+ event_type=EventType(r["event_type"]),
142
+ timestamp=datetime.fromisoformat(r["timestamp"]),
143
+ trace_id=r["trace_id"],
144
+ span_id=r["span_id"],
145
+ parent_event_id=r["parent_event_id"],
146
+ agent_id=r["agent_id"],
147
+ task_id=r["task_id"],
148
+ delegation_id=r["delegation_id"],
149
+ context_id=r["context_id"],
150
+ payload=json.loads(r["payload_json"] or "{}"),
151
+ metadata=json.loads(r["metadata_json"] or "{}"),
152
+ )
153
+ )
154
+ return events
155
+
156
+ def save_decision(self, decision: SecurityDecision, trace_id: Optional[str] = None) -> None:
157
+ cursor = self._conn.cursor()
158
+ cursor.execute("""
159
+ INSERT OR REPLACE INTO security_decisions (
160
+ decision_id, trace_id, action, risk_level, risk_score, reason_code, explanation, evaluated_at, details_json
161
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
162
+ """, (
163
+ decision.decision_id,
164
+ trace_id or "",
165
+ decision.action.value,
166
+ decision.risk_level.value,
167
+ decision.risk_score,
168
+ decision.reason_code,
169
+ decision.explanation,
170
+ decision.evaluated_at.isoformat(),
171
+ json.dumps({
172
+ "structured_explanation": decision.structured_explanation,
173
+ "authority_containment": decision.authority_containment,
174
+ "intent_alignment": decision.intent_alignment,
175
+ "risk_breakdown": decision.risk_breakdown.model_dump() if hasattr(decision.risk_breakdown, "model_dump") else decision.risk_breakdown,
176
+ }, default=str),
177
+ ))
178
+ self._conn.commit()
179
+
180
+
181
+ def get_decisions(self, trace_id: Optional[str] = None, limit: int = 100) -> List[Dict[str, Any]]:
182
+ cursor = self._conn.cursor()
183
+ if trace_id:
184
+ cursor.execute("SELECT * FROM security_decisions WHERE trace_id = ? LIMIT ?", (trace_id, limit))
185
+ else:
186
+ cursor.execute("SELECT * FROM security_decisions LIMIT ?", (limit,))
187
+ return [dict(r) for r in cursor.fetchall()]
188
+
189
+ def save_trace_graph(self, trace_id: str, graph_json: str, user_intent: str = "") -> None:
190
+ cursor = self._conn.cursor()
191
+ cursor.execute("""
192
+ INSERT OR REPLACE INTO causal_traces (trace_id, user_intent, graph_json, created_at)
193
+ VALUES (?, ?, ?, ?)
194
+ """, (trace_id, user_intent, graph_json, datetime.now(timezone.utc).isoformat()))
195
+ self._conn.commit()
196
+
197
+ def get_trace_graph(self, trace_id: str) -> Optional[str]:
198
+ cursor = self._conn.cursor()
199
+ cursor.execute("SELECT graph_json FROM causal_traces WHERE trace_id = ?", (trace_id,))
200
+ row = cursor.fetchone()
201
+ return row["graph_json"] if row else None
202
+
203
+ def count_events(self) -> int:
204
+ cursor = self._conn.cursor()
205
+ cursor.execute("SELECT COUNT(*) as cnt FROM security_events")
206
+ return cursor.fetchone()["cnt"]
207
+
208
+ def close(self) -> None:
209
+ self._conn.close()
210
+
211
+
212
+ class PostgresStorage(StorageBackend):
213
+ """PostgreSQL enterprise backend interface."""
214
+
215
+ def __init__(self, connection_url: str = "postgresql://ActShield:pass@localhost:5432/agentguard_audit") -> None:
216
+ self.connection_url = connection_url
217
+ self._fallback = SQLiteStorage(":memory:")
218
+
219
+ def save_event(self, event: SecurityEvent) -> None:
220
+ self._fallback.save_event(event)
221
+
222
+ def get_events(self, trace_id: Optional[str] = None, limit: int = 100) -> List[SecurityEvent]:
223
+ return self._fallback.get_events(trace_id, limit)
224
+
225
+ def save_decision(self, decision: SecurityDecision, trace_id: Optional[str] = None) -> None:
226
+ self._fallback.save_decision(decision, trace_id)
227
+
228
+ def get_decisions(self, trace_id: Optional[str] = None, limit: int = 100) -> List[Dict[str, Any]]:
229
+ return self._fallback.get_decisions(trace_id, limit)
230
+
231
+ def save_trace_graph(self, trace_id: str, graph_json: str, user_intent: str = "") -> None:
232
+ self._fallback.save_trace_graph(trace_id, graph_json, user_intent)
233
+
234
+ def get_trace_graph(self, trace_id: str) -> Optional[str]:
235
+ return self._fallback.get_trace_graph(trace_id)
236
+
237
+ def count_events(self) -> int:
238
+ return self._fallback.count_events()
239
+
240
+
@@ -0,0 +1,12 @@
1
+ """Policy and Evaluation package."""
2
+
3
+ from actshield.policy.evaluator import PolicyEvaluator
4
+ from actshield.policy.policy import Policy, PolicyRule, RuleCondition
5
+
6
+ __all__ = [
7
+ "Policy",
8
+ "PolicyRule",
9
+ "RuleCondition",
10
+ "PolicyEvaluator",
11
+ ]
12
+