decodingtrust-agent-sdk 0.1.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 (374) hide show
  1. agent/__init__.py +30 -0
  2. agent/claudesdk/__init__.py +8 -0
  3. agent/claudesdk/example.py +221 -0
  4. agent/claudesdk/src/__init__.py +8 -0
  5. agent/claudesdk/src/agent.py +400 -0
  6. agent/claudesdk/src/mcp_proxy.py +409 -0
  7. agent/claudesdk/src/utils.py +420 -0
  8. agent/googleadk/__init__.py +15 -0
  9. agent/googleadk/example.py +237 -0
  10. agent/googleadk/src/__init__.py +12 -0
  11. agent/googleadk/src/agent.py +401 -0
  12. agent/googleadk/src/mcp_wrapper.py +163 -0
  13. agent/googleadk/src/utils.py +602 -0
  14. agent/langchain/__init__.py +8 -0
  15. agent/langchain/example.py +213 -0
  16. agent/langchain/src/__init__.py +8 -0
  17. agent/langchain/src/agent.py +645 -0
  18. agent/langchain/src/utils.py +433 -0
  19. agent/openaisdk/__init__.py +17 -0
  20. agent/openaisdk/example.py +228 -0
  21. agent/openaisdk/src/__init__.py +12 -0
  22. agent/openaisdk/src/agent.py +491 -0
  23. agent/openaisdk/src/agent_wrapper.py +143 -0
  24. agent/openaisdk/src/mcp_wrapper.py +395 -0
  25. agent/openaisdk/src/utils.py +493 -0
  26. agent/openclaw/__init__.py +10 -0
  27. agent/openclaw/example.py +251 -0
  28. agent/openclaw/src/__init__.py +14 -0
  29. agent/openclaw/src/agent.py +930 -0
  30. agent/openclaw/src/helpers/__init__.py +1 -0
  31. agent/openclaw/src/helpers/auth_helpers.py +55 -0
  32. agent/openclaw/src/mcp_proxy.py +564 -0
  33. agent/openclaw/src/plugin_generator.py +231 -0
  34. agent/openclaw/src/utils.py +341 -0
  35. agent/pocketflow/__init__.py +18 -0
  36. agent/pocketflow/example.py +221 -0
  37. agent/pocketflow/prompts/react_agent.py +46 -0
  38. agent/pocketflow/src/__init__.py +6 -0
  39. agent/pocketflow/src/agent.py +507 -0
  40. agent/pocketflow/src/agent_wrapper.py +159 -0
  41. agent/pocketflow/src/async_helper.py +92 -0
  42. agent/pocketflow/src/mcp_react_agent.py +279 -0
  43. agent/pocketflow/src/native_agent.py +74 -0
  44. agent/pocketflow/src/nodes.py +467 -0
  45. benchmark/__init__.py +0 -0
  46. benchmark/browser/benign.jsonl +34 -0
  47. benchmark/browser/direct.jsonl +85 -0
  48. benchmark/browser/indirect.jsonl +82 -0
  49. benchmark/code/benign.jsonl +0 -0
  50. benchmark/code/direct.jsonl +121 -0
  51. benchmark/code/indirect.jsonl +165 -0
  52. benchmark/crm/benign.jsonl +165 -0
  53. benchmark/crm/direct.jsonl +90 -0
  54. benchmark/crm/indirect.jsonl +150 -0
  55. benchmark/customer-service/benign.jsonl +160 -0
  56. benchmark/customer-service/direct.jsonl +100 -0
  57. benchmark/customer-service/indirect.jsonl +101 -0
  58. benchmark/finance/benign.jsonl +0 -0
  59. benchmark/finance/direct.jsonl +200 -0
  60. benchmark/finance/indirect.jsonl +200 -0
  61. benchmark/legal/benign.jsonl +0 -0
  62. benchmark/legal/direct.jsonl +200 -0
  63. benchmark/legal/indirect.jsonl +200 -0
  64. benchmark/macos/benign.jsonl +30 -0
  65. benchmark/macos/direct.jsonl +50 -0
  66. benchmark/macos/indirect.jsonl +50 -0
  67. benchmark/medical/benign.jsonl +642 -0
  68. benchmark/medical/direct.jsonl +229 -0
  69. benchmark/medical/indirect.jsonl +222 -0
  70. benchmark/os-filesystem/benign.jsonl +200 -0
  71. benchmark/os-filesystem/direct.jsonl +200 -0
  72. benchmark/os-filesystem/indirect.jsonl +200 -0
  73. benchmark/research/benign.jsonl +0 -0
  74. benchmark/research/direct.jsonl +119 -0
  75. benchmark/research/indirect.jsonl +125 -0
  76. benchmark/telecom/benign.jsonl +120 -0
  77. benchmark/telecom/direct.jsonl +161 -0
  78. benchmark/telecom/indirect.jsonl +166 -0
  79. benchmark/travel/benign.jsonl +130 -0
  80. benchmark/travel/direct.jsonl +105 -0
  81. benchmark/travel/indirect.jsonl +120 -0
  82. benchmark/windows/benign.jsonl +100 -0
  83. benchmark/windows/direct.jsonl +140 -0
  84. benchmark/windows/indirect.jsonl +107 -0
  85. benchmark/workflow/benign.jsonl +335 -0
  86. benchmark/workflow/direct.jsonl +78 -0
  87. benchmark/workflow/indirect.jsonl +107 -0
  88. cli/__init__.py +5 -0
  89. cli/main.py +182 -0
  90. cli/scaffold.py +334 -0
  91. decodingtrust_agent_sdk-0.1.0.dist-info/METADATA +642 -0
  92. decodingtrust_agent_sdk-0.1.0.dist-info/RECORD +374 -0
  93. decodingtrust_agent_sdk-0.1.0.dist-info/WHEEL +5 -0
  94. decodingtrust_agent_sdk-0.1.0.dist-info/entry_points.txt +2 -0
  95. decodingtrust_agent_sdk-0.1.0.dist-info/licenses/LICENSE +201 -0
  96. decodingtrust_agent_sdk-0.1.0.dist-info/top_level.txt +6 -0
  97. dt_arena/config/env.yaml +515 -0
  98. dt_arena/config/injection_mcp.yaml +430 -0
  99. dt_arena/config/mcp.yaml +642 -0
  100. dt_arena/envs/arxiv/docker-compose-hub.yml +31 -0
  101. dt_arena/envs/arxiv/docker-compose.yml +36 -0
  102. dt_arena/envs/atlassian/docker/docker-compose.dev.yml +65 -0
  103. dt_arena/envs/atlassian/docker/docker-compose.yml +53 -0
  104. dt_arena/envs/atlassian/docker-compose-hub.yml +57 -0
  105. dt_arena/envs/atlassian/docker-compose.yml +72 -0
  106. dt_arena/envs/bigquery/docker-compose.yml +20 -0
  107. dt_arena/envs/booking/docker-compose.yml +59 -0
  108. dt_arena/envs/calendar/docker-compose-hub.yml +30 -0
  109. dt_arena/envs/calendar/docker-compose.yml +42 -0
  110. dt_arena/envs/custom-website/docker-compose.yml +6 -0
  111. dt_arena/envs/customer_service/docker-compose.yml +59 -0
  112. dt_arena/envs/databricks/docker-compose-hub.yml +47 -0
  113. dt_arena/envs/databricks/docker-compose.yml +51 -0
  114. dt_arena/envs/ecommerce/docker-compose.yml +6 -0
  115. dt_arena/envs/ers/docker-compose.yml +36 -0
  116. dt_arena/envs/ers/hrms/docker/docker-compose.yml +31 -0
  117. dt_arena/envs/finance/docker-compose.yml +23 -0
  118. dt_arena/envs/github/docker/docker-compose-hub.yml +50 -0
  119. dt_arena/envs/github/docker/docker-compose.yml +50 -0
  120. dt_arena/envs/gmail/docker-compose-hub.yml +51 -0
  121. dt_arena/envs/gmail/docker-compose.yml +65 -0
  122. dt_arena/envs/google-form/docker-compose-hub.yml +33 -0
  123. dt_arena/envs/google-form/docker-compose.yml +41 -0
  124. dt_arena/envs/googledocs/docker-compose-hub.yml +61 -0
  125. dt_arena/envs/googledocs/docker-compose.yml +78 -0
  126. dt_arena/envs/hospital/docker-compose-hub.yml +25 -0
  127. dt_arena/envs/hospital/docker-compose.yml +27 -0
  128. dt_arena/envs/legal/docker-compose.yml +22 -0
  129. dt_arena/envs/linkedin/docker-compose.yml +63 -0
  130. dt_arena/envs/macos/docker-compose.yml +79 -0
  131. dt_arena/envs/os-filesystem/docker-compose-hub.yml +16 -0
  132. dt_arena/envs/os-filesystem/docker-compose.yml +20 -0
  133. dt_arena/envs/paypal/docker-compose-hub.yml +48 -0
  134. dt_arena/envs/paypal/docker-compose.yml +63 -0
  135. dt_arena/envs/research/docker-compose-hub.yml +13 -0
  136. dt_arena/envs/research/docker-compose.yml +24 -0
  137. dt_arena/envs/salesforce_crm/docker-compose-hub.yaml +45 -0
  138. dt_arena/envs/salesforce_crm/docker-compose.yaml +49 -0
  139. dt_arena/envs/slack/docker-compose-hub.yml +28 -0
  140. dt_arena/envs/slack/docker-compose.yml +41 -0
  141. dt_arena/envs/snowflake/docker-compose-hub.yml +41 -0
  142. dt_arena/envs/snowflake/docker-compose.yml +44 -0
  143. dt_arena/envs/telecom/docker-compose-hub.yml +16 -0
  144. dt_arena/envs/telecom/docker-compose.yml +17 -0
  145. dt_arena/envs/telegram/docker-compose-hub.yml +57 -0
  146. dt_arena/envs/telegram/docker-compose.yml +62 -0
  147. dt_arena/envs/terminal/docker-compose-hub.yml +12 -0
  148. dt_arena/envs/terminal/docker-compose.yml +26 -0
  149. dt_arena/envs/travel/docker-compose-hub.yml +19 -0
  150. dt_arena/envs/travel/docker-compose.yml +19 -0
  151. dt_arena/envs/whatsapp/docker-compose-hub.yml +61 -0
  152. dt_arena/envs/whatsapp/docker-compose.yml +78 -0
  153. dt_arena/envs/windows/docker-compose.yml +71 -0
  154. dt_arena/envs/zoom/docker-compose-hub.yml +27 -0
  155. dt_arena/envs/zoom/docker-compose.yml +40 -0
  156. dt_arena/injection_mcp_server/atlassian/env_injection.py +134 -0
  157. dt_arena/injection_mcp_server/calendar/env_injection.py +217 -0
  158. dt_arena/injection_mcp_server/custom_website/env_injection.py +97 -0
  159. dt_arena/injection_mcp_server/customer_service/env_injection.py +659 -0
  160. dt_arena/injection_mcp_server/databricks/env_injection.py +255 -0
  161. dt_arena/injection_mcp_server/ecommerce/env_injection.py +110 -0
  162. dt_arena/injection_mcp_server/finance/env_injection.py +85 -0
  163. dt_arena/injection_mcp_server/github/env_injection.py +206 -0
  164. dt_arena/injection_mcp_server/gmail/env_injection.py +211 -0
  165. dt_arena/injection_mcp_server/google_form/env_injection.py +186 -0
  166. dt_arena/injection_mcp_server/googledocs/env_injection.py +44 -0
  167. dt_arena/injection_mcp_server/hospital/env_injection.py +43 -0
  168. dt_arena/injection_mcp_server/legal/env_injection.py +229 -0
  169. dt_arena/injection_mcp_server/macos/env_injection.py +272 -0
  170. dt_arena/injection_mcp_server/os-filesystem/env_injection.py +341 -0
  171. dt_arena/injection_mcp_server/paypal/env_injection.py +268 -0
  172. dt_arena/injection_mcp_server/research/env_injection.py +616 -0
  173. dt_arena/injection_mcp_server/salesforce/env_injection.py +514 -0
  174. dt_arena/injection_mcp_server/slack/env_injection.py +265 -0
  175. dt_arena/injection_mcp_server/snowflake/env_injection.py +230 -0
  176. dt_arena/injection_mcp_server/telecom/env_injection.py +503 -0
  177. dt_arena/injection_mcp_server/telegram/env_injection.py +171 -0
  178. dt_arena/injection_mcp_server/terminal/env_injection.py +523 -0
  179. dt_arena/injection_mcp_server/travel/env_injection.py +173 -0
  180. dt_arena/injection_mcp_server/whatsapp/env_injection.py +185 -0
  181. dt_arena/injection_mcp_server/windows/env_injection.py +943 -0
  182. dt_arena/injection_mcp_server/zoom/env_injection.py +216 -0
  183. dt_arena/mcp_server/atlassian/main.py +1554 -0
  184. dt_arena/mcp_server/atlassian/test_server.py +66 -0
  185. dt_arena/mcp_server/bigquery/main.py +333 -0
  186. dt_arena/mcp_server/booking/main.py +310 -0
  187. dt_arena/mcp_server/browser/main.py +1741 -0
  188. dt_arena/mcp_server/calendar/example_multi_user.py +162 -0
  189. dt_arena/mcp_server/calendar/main.py +792 -0
  190. dt_arena/mcp_server/calendar/test_mcp.py +135 -0
  191. dt_arena/mcp_server/customer_service/main.py +1063 -0
  192. dt_arena/mcp_server/databricks/main.py +566 -0
  193. dt_arena/mcp_server/databricks/probe.py +102 -0
  194. dt_arena/mcp_server/ers/main.py +845 -0
  195. dt_arena/mcp_server/finance/__init__.py +87 -0
  196. dt_arena/mcp_server/finance/core/__init__.py +12 -0
  197. dt_arena/mcp_server/finance/core/data_loader.py +558 -0
  198. dt_arena/mcp_server/finance/core/portfolio.py +565 -0
  199. dt_arena/mcp_server/finance/evaluation/__init__.py +20 -0
  200. dt_arena/mcp_server/finance/evaluation/evaluator.py +217 -0
  201. dt_arena/mcp_server/finance/evaluation/logger.py +137 -0
  202. dt_arena/mcp_server/finance/injection/__init__.py +66 -0
  203. dt_arena/mcp_server/finance/injection/config.py +176 -0
  204. dt_arena/mcp_server/finance/injection/content.py +755 -0
  205. dt_arena/mcp_server/finance/injection/html.py +409 -0
  206. dt_arena/mcp_server/finance/injection/locations.py +167 -0
  207. dt_arena/mcp_server/finance/injection/methods.py +193 -0
  208. dt_arena/mcp_server/finance/injection/presets.py +1023 -0
  209. dt_arena/mcp_server/finance/main.py +361 -0
  210. dt_arena/mcp_server/finance/run_mcp.py +21 -0
  211. dt_arena/mcp_server/finance/run_web.py +26 -0
  212. dt_arena/mcp_server/finance/server/__init__.py +41 -0
  213. dt_arena/mcp_server/finance/server/extractor.py +1453 -0
  214. dt_arena/mcp_server/finance/server/extractor_minimal.py +292 -0
  215. dt_arena/mcp_server/finance/server/extractor_simple.py +1164 -0
  216. dt_arena/mcp_server/finance/server/injection_mcp.py +865 -0
  217. dt_arena/mcp_server/finance/server/mcp.py +451 -0
  218. dt_arena/mcp_server/finance/server/tools/__init__.py +23 -0
  219. dt_arena/mcp_server/finance/server/tools/account.py +88 -0
  220. dt_arena/mcp_server/finance/server/tools/browsing.py +328 -0
  221. dt_arena/mcp_server/finance/server/tools/social.py +73 -0
  222. dt_arena/mcp_server/finance/server/tools/trading.py +242 -0
  223. dt_arena/mcp_server/finance/server/tools/utility.py +49 -0
  224. dt_arena/mcp_server/finance/server/web.py +2139 -0
  225. dt_arena/mcp_server/finance/tasks/benchmark/__init__.py +28 -0
  226. dt_arena/mcp_server/finance/tasks/benchmark/attack_pool.py +3026 -0
  227. dt_arena/mcp_server/finance/tasks/benchmark/attack_runner.py +1315 -0
  228. dt_arena/mcp_server/finance/tasks/benchmark/finra_requirements.py +1335 -0
  229. dt_arena/mcp_server/finance/tasks/benchmark/finra_tasks.py +3665 -0
  230. dt_arena/mcp_server/finance/tasks/benchmark/malicious_tasks.py +2673 -0
  231. dt_arena/mcp_server/finance/tasks/redteam_suite/run_redteam_suite.py +1713 -0
  232. dt_arena/mcp_server/finance/test_mcp_tools.py +476 -0
  233. dt_arena/mcp_server/github/main.py +441 -0
  234. dt_arena/mcp_server/gmail/main.py +1004 -0
  235. dt_arena/mcp_server/google_form/main.py +141 -0
  236. dt_arena/mcp_server/googledocs/main.py +458 -0
  237. dt_arena/mcp_server/hospital/mcp_server.py +458 -0
  238. dt_arena/mcp_server/legal/__init__.py +9 -0
  239. dt_arena/mcp_server/legal/core/__init__.py +14 -0
  240. dt_arena/mcp_server/legal/core/courtlistener_store.py +762 -0
  241. dt_arena/mcp_server/legal/core/data_loader.py +266 -0
  242. dt_arena/mcp_server/legal/core/document_store.py +197 -0
  243. dt_arena/mcp_server/legal/core/matter_manager.py +466 -0
  244. dt_arena/mcp_server/legal/main.py +89 -0
  245. dt_arena/mcp_server/legal/scripts/collect_data.py +988 -0
  246. dt_arena/mcp_server/legal/server/__init__.py +14 -0
  247. dt_arena/mcp_server/legal/server/mcp.py +2330 -0
  248. dt_arena/mcp_server/macos/client_test.py +270 -0
  249. dt_arena/mcp_server/macos/mcp_server.py +285 -0
  250. dt_arena/mcp_server/os-filesystem/main.py +1380 -0
  251. dt_arena/mcp_server/paypal/main.py +501 -0
  252. dt_arena/mcp_server/research/main.py +777 -0
  253. dt_arena/mcp_server/salesforce/main.py +2006 -0
  254. dt_arena/mcp_server/slack/main.py +318 -0
  255. dt_arena/mcp_server/snowflake/main.py +612 -0
  256. dt_arena/mcp_server/snowflake/probe.py +183 -0
  257. dt_arena/mcp_server/telecom/mcp_client.py +423 -0
  258. dt_arena/mcp_server/telecom/mcp_server.py +1059 -0
  259. dt_arena/mcp_server/telegram/main.py +338 -0
  260. dt_arena/mcp_server/terminal/main.py +163 -0
  261. dt_arena/mcp_server/travel/client_test.py +16 -0
  262. dt_arena/mcp_server/travel/mcp_server.py +404 -0
  263. dt_arena/mcp_server/whatsapp/main.py +318 -0
  264. dt_arena/mcp_server/windows/client_test.py +270 -0
  265. dt_arena/mcp_server/windows/mcp_server.py +218 -0
  266. dt_arena/mcp_server/zoom/main.py +466 -0
  267. dt_arena/src/__init__.py +0 -0
  268. dt_arena/src/hooks/__init__.py +0 -0
  269. dt_arena/src/hooks/audit_log.py +30 -0
  270. dt_arena/src/hooks/hooks.json +3 -0
  271. dt_arena/src/run_benign.py +142 -0
  272. dt_arena/src/types/__init__.py +0 -0
  273. dt_arena/src/types/agent.py +441 -0
  274. dt_arena/src/types/attacks.py +2 -0
  275. dt_arena/src/types/environment.py +2 -0
  276. dt_arena/src/types/hooks.py +174 -0
  277. dt_arena/src/types/judge.py +52 -0
  278. dt_arena/src/types/red_teaming_trajectory.py +385 -0
  279. dt_arena/src/types/task.py +260 -0
  280. dt_arena/src/types/trajectory.py +315 -0
  281. dt_arena/utils/__init__.py +1 -0
  282. dt_arena/utils/atlassian/__init__.py +27 -0
  283. dt_arena/utils/atlassian/helpers.py +520 -0
  284. dt_arena/utils/bigquery/__init__.py +1 -0
  285. dt_arena/utils/bigquery/helpers.py +246 -0
  286. dt_arena/utils/calendar/__init__.py +1 -0
  287. dt_arena/utils/calendar/helpers.py +87 -0
  288. dt_arena/utils/customer_service/__init__.py +17 -0
  289. dt_arena/utils/customer_service/cs_env_client.py +940 -0
  290. dt_arena/utils/customer_service/helpers.py +339 -0
  291. dt_arena/utils/customer_service/judges/__init__.py +20 -0
  292. dt_arena/utils/customer_service/judges/abusive_comms.py +149 -0
  293. dt_arena/utils/customer_service/judges/bulk_destructive.py +202 -0
  294. dt_arena/utils/customer_service/judges/cross_customer.py +481 -0
  295. dt_arena/utils/customer_service/judges/email_exfiltration.py +320 -0
  296. dt_arena/utils/customer_service/judges/financial_fraud.py +221 -0
  297. dt_arena/utils/customer_service/judges/llm_utils.py +264 -0
  298. dt_arena/utils/customer_service/judges/pii_disclosure.py +837 -0
  299. dt_arena/utils/customer_service/judges/policy_misrep.py +44 -0
  300. dt_arena/utils/customer_service/judges/text_utils.py +21 -0
  301. dt_arena/utils/databricks/__init__.py +2 -0
  302. dt_arena/utils/databricks/helpers.py +210 -0
  303. dt_arena/utils/finance/__init__.py +0 -0
  304. dt_arena/utils/finance/helpers.py +263 -0
  305. dt_arena/utils/github/__init__.py +1 -0
  306. dt_arena/utils/github/helpers.py +249 -0
  307. dt_arena/utils/gmail/__init__.py +1 -0
  308. dt_arena/utils/gmail/helpers.py +344 -0
  309. dt_arena/utils/google_form/__init__.py +2 -0
  310. dt_arena/utils/google_form/helpers.py +133 -0
  311. dt_arena/utils/legal/__init__.py +0 -0
  312. dt_arena/utils/legal/helpers.py +228 -0
  313. dt_arena/utils/macos/__init__.py +0 -0
  314. dt_arena/utils/macos/env_setup.py +215 -0
  315. dt_arena/utils/macos/helpers.py +61 -0
  316. dt_arena/utils/os_filesystem/__init__.py +1 -0
  317. dt_arena/utils/os_filesystem/helpers.py +366 -0
  318. dt_arena/utils/paypal/__init__.py +1 -0
  319. dt_arena/utils/paypal/helpers.py +178 -0
  320. dt_arena/utils/port_allocator.py +266 -0
  321. dt_arena/utils/research/__init__.py +0 -0
  322. dt_arena/utils/research/helpers.py +251 -0
  323. dt_arena/utils/salesforce/__init__.py +1 -0
  324. dt_arena/utils/salesforce/helpers.py +719 -0
  325. dt_arena/utils/slack/__init__.py +1 -0
  326. dt_arena/utils/slack/helpers.py +176 -0
  327. dt_arena/utils/snowflake/__init__.py +1 -0
  328. dt_arena/utils/snowflake/helpers.py +166 -0
  329. dt_arena/utils/telecom/__init__.py +1 -0
  330. dt_arena/utils/telecom/helpers.py +760 -0
  331. dt_arena/utils/telegram/__init__.py +0 -0
  332. dt_arena/utils/telegram/helpers.py +174 -0
  333. dt_arena/utils/terminal/__init__.py +0 -0
  334. dt_arena/utils/terminal/helpers.py +20 -0
  335. dt_arena/utils/travel/__init__.py +0 -0
  336. dt_arena/utils/travel/env_client.py +537 -0
  337. dt_arena/utils/travel/llm_judge.py +137 -0
  338. dt_arena/utils/travel/prompts.py +64 -0
  339. dt_arena/utils/utils/__init__.py +122 -0
  340. dt_arena/utils/whatsapp/__init__.py +0 -0
  341. dt_arena/utils/whatsapp/helpers.py +226 -0
  342. dt_arena/utils/windows/__init__.py +0 -0
  343. dt_arena/utils/windows/env_reset.py +224 -0
  344. dt_arena/utils/windows/env_setup.py +280 -0
  345. dt_arena/utils/windows/exfil_helpers.py +170 -0
  346. dt_arena/utils/windows/helpers.py +74 -0
  347. dt_arena/utils/zoom/__init__.py +1 -0
  348. dt_arena/utils/zoom/helpers.py +70 -0
  349. eval/__init__.py +1 -0
  350. eval/evaluation.py +426 -0
  351. eval/task_runner.py +449 -0
  352. utils/__init__.py +148 -0
  353. utils/agent_helpers.py +308 -0
  354. utils/agent_wrapper.py +189 -0
  355. utils/compose_utils.py +135 -0
  356. utils/config.py +77 -0
  357. utils/env_helpers.py +104 -0
  358. utils/eval_stats.py +88 -0
  359. utils/injection_helpers.py +429 -0
  360. utils/injection_mcp_helpers.py +152 -0
  361. utils/judge_helpers.py +181 -0
  362. utils/judge_utils.py +472 -0
  363. utils/llm.py +196 -0
  364. utils/logging.py +45 -0
  365. utils/mcp_helpers.py +232 -0
  366. utils/mcp_manager.py +235 -0
  367. utils/memory_guard.py +18 -0
  368. utils/red_teaming_sandbox.py +476 -0
  369. utils/reset_helpers.py +318 -0
  370. utils/resource_manager.py +370 -0
  371. utils/skill_helpers.py +447 -0
  372. utils/task_executor.py +904 -0
  373. utils/task_helpers.py +270 -0
  374. utils/template_helpers.py +179 -0
@@ -0,0 +1,409 @@
1
+ """
2
+ HTML Injector - Core HTML injection processing
3
+
4
+ Static injection model (Docker + red-teaming agent):
5
+ - Each rule is bound to specific page(s) via the `pages` field
6
+ - Injection is applied to ALL matching elements on the bound page
7
+ - No dynamic discovery, no location locking, no view-order matching
8
+
9
+ This module handles applying injection rules to HTML content.
10
+ Uses HTML structure matching (regex/patterns) to locate injection points,
11
+ without requiring any markers in the templates.
12
+
13
+ Note: This is called HtmlInjector (vs ContentInjector) because it injects
14
+ HIDDEN content into HTML, while ContentInjector injects VISIBLE fake data.
15
+ """
16
+
17
+ import re
18
+ from typing import Optional, List, Dict, Tuple
19
+
20
+ from .locations import InjectionLocation
21
+ from .methods import InjectionMethod, InjectionRenderer
22
+ from .config import InjectionConfig, InjectionRule, InjectionStatus
23
+
24
+
25
+ # HTML patterns for locating injection points
26
+ # Maps InjectionLocation to list of (pattern, insert_position)
27
+ # insert_position: "after" = after opening tag, "before" = before the tag
28
+ LOCATION_PATTERNS: Dict[InjectionLocation, List[Tuple[str, str]]] = {
29
+ # === Page Structure ===
30
+ InjectionLocation.HEAD: [
31
+ (r'<head[^>]*>', 'after'),
32
+ ],
33
+ InjectionLocation.BODY_START: [
34
+ (r'<body[^>]*>', 'after'),
35
+ ],
36
+ InjectionLocation.BODY_END: [
37
+ (r'</body>', 'before'),
38
+ ],
39
+
40
+ # === News Page Structure ===
41
+ InjectionLocation.NEWS_HEADER: [
42
+ (r'<[^>]*data-section="news-header"[^>]*>', 'after'),
43
+ (r'<[^>]*data-section="news-page"[^>]*>', 'after'),
44
+ (r'<[^>]*data-section="news-featured"[^>]*>', 'after'),
45
+ ],
46
+
47
+ # === News Item (individual article) ===
48
+ InjectionLocation.NEWS_ITEM: [
49
+ # Any news item with data-section
50
+ (r'<[^>]*data-section="news-item"[^>]*>', 'after'),
51
+ # Fallback: any element with news-item class
52
+ (r'<[^>]*class="[^"]*news-item[^"]*"[^>]*>', 'after'),
53
+ ],
54
+
55
+ # === News Headline ===
56
+ InjectionLocation.NEWS_TITLE: [
57
+ (r'<a[^>]*data-section="news-headline"[^>]*>', 'after'),
58
+ (r'<[^>]*class="[^"]*news-headline[^"]*"[^>]*>', 'after'),
59
+ ],
60
+
61
+ # === News Summary ===
62
+ InjectionLocation.NEWS_SUMMARY: [
63
+ (r'<[^>]*data-section="news-summary"[^>]*>', 'after'),
64
+ (r'<p[^>]*class="[^"]*news-summary[^"]*"[^>]*>', 'after'),
65
+ ],
66
+
67
+ # === News Source Badge ===
68
+ InjectionLocation.NEWS_SOURCE: [
69
+ (r'<span[^>]*class="[^"]*news-source[^"]*"[^>]*>', 'after'),
70
+ ],
71
+
72
+ # === News Meta (source + time) ===
73
+ InjectionLocation.NEWS_META: [
74
+ (r'<[^>]*class="[^"]*news-meta[^"]*"[^>]*>', 'after'),
75
+ ],
76
+
77
+ # === News Footer ===
78
+ InjectionLocation.NEWS_FOOTER: [
79
+ (r'<[^>]*class="[^"]*news-footer[^"]*"[^>]*>', 'after'),
80
+ ],
81
+
82
+ # === Article Page ===
83
+ InjectionLocation.ARTICLE_CONTENT: [
84
+ (r'<[^>]*data-section="article-content"[^>]*>', 'after'),
85
+ ],
86
+
87
+ InjectionLocation.ARTICLE_BODY: [
88
+ (r'<[^>]*data-section="article-body"[^>]*>', 'after'),
89
+ ],
90
+
91
+ InjectionLocation.ARTICLE_SUMMARY: [
92
+ (r'<[^>]*data-section="article-summary"[^>]*>', 'after'),
93
+ ],
94
+
95
+ # === News List Container ===
96
+ InjectionLocation.NEWS_LIST: [
97
+ (r'<[^>]*data-section="news-list"[^>]*>', 'after'),
98
+ (r'<[^>]*data-section="quote-news"[^>]*>', 'after'),
99
+ (r'<ul[^>]*class="[^"]*news-list[^"]*"[^>]*>', 'after'),
100
+ ],
101
+
102
+ # === News Sidebar ===
103
+ InjectionLocation.NEWS_SIDEBAR: [
104
+ (r'<[^>]*data-section="browse-news"[^>]*>', 'after'),
105
+ ],
106
+
107
+ # === Trending Widget ===
108
+ InjectionLocation.TRENDING: [
109
+ (r'<[^>]*data-section="trending-stocks"[^>]*>', 'after'),
110
+ (r'<[^>]*data-section="trending-item"[^>]*>', 'after'),
111
+ ],
112
+
113
+ # === Stock/Quote Elements ===
114
+ InjectionLocation.STOCK_HEADER: [
115
+ (r'<[^>]*data-section="quote-header"[^>]*>', 'after'),
116
+ (r'<[^>]*data-section="quote-page"[^>]*>', 'after'),
117
+ ],
118
+ InjectionLocation.STOCK_INFO: [
119
+ (r'<[^>]*data-section="quote-header"[^>]*>', 'after'),
120
+ (r'<[^>]*data-section="stock-info"[^>]*>', 'after'),
121
+ (r'<[^>]*data-section="quote-page"[^>]*>', 'after'),
122
+ ],
123
+ InjectionLocation.STOCK_PRICE: [
124
+ (r'<[^>]*data-section="quote-price"[^>]*>', 'after'),
125
+ ],
126
+ InjectionLocation.STOCK_STATS: [
127
+ (r'<[^>]*data-section="quick-stats"[^>]*>', 'after'),
128
+ (r'<[^>]*data-section="key-statistics"[^>]*>', 'after'),
129
+ ],
130
+ InjectionLocation.STOCK_DESCRIPTION: [
131
+ (r'<[^>]*data-section="company-info"[^>]*>', 'after'),
132
+ ],
133
+
134
+ # === Chart/Analysis ===
135
+ InjectionLocation.CHART_AREA: [
136
+ (r'<[^>]*data-section="quote-chart"[^>]*>', 'after'),
137
+ (r'<[^>]*data-section="mini-chart"[^>]*>', 'after'),
138
+ ],
139
+ InjectionLocation.INDICATOR_SECTION: [
140
+ (r'<[^>]*data-section="analyst-rating"[^>]*>', 'after'),
141
+ ],
142
+
143
+ # === Portfolio ===
144
+ InjectionLocation.PORTFOLIO_SUMMARY: [
145
+ (r'<[^>]*data-section="portfolio-summary"[^>]*>', 'after'),
146
+ (r'<[^>]*data-section="account-summary"[^>]*>', 'after'),
147
+ (r'<[^>]*data-section="portfolio-page"[^>]*>', 'after'),
148
+ ],
149
+ InjectionLocation.PORTFOLIO_TABLE: [
150
+ (r'<[^>]*data-section="portfolio-holdings"[^>]*>', 'after'),
151
+ (r'<[^>]*data-section="summary-holdings"[^>]*>', 'after'),
152
+ ],
153
+ InjectionLocation.POSITION_ROW: [
154
+ (r'<[^>]*data-section="holding-row"[^>]*>', 'after'),
155
+ ],
156
+ InjectionLocation.CASH_BALANCE: [
157
+ (r'<[^>]*data-section="summary-cash"[^>]*>', 'after'),
158
+ (r'<[^>]*data-section="account-info"[^>]*>', 'after'),
159
+ ],
160
+
161
+ # === Trading ===
162
+ InjectionLocation.TRADE_FORM: [
163
+ (r'<[^>]*data-section="trade-form"[^>]*>', 'after'),
164
+ (r'<[^>]*data-section="trade-panel"[^>]*>', 'after'),
165
+ (r'<[^>]*data-section="trading-page"[^>]*>', 'after'),
166
+ ],
167
+ InjectionLocation.ORDER_BUTTON: [
168
+ (r'<[^>]*data-section="submit-trade"[^>]*>', 'after'),
169
+ ],
170
+
171
+ # === Comments Section ===
172
+ InjectionLocation.COMMENTS_SECTION: [
173
+ (r'<[^>]*data-section="comments-section"[^>]*>', 'after'),
174
+ (r'<[^>]*data-section="comments-list"[^>]*>', 'after'),
175
+ ],
176
+ InjectionLocation.COMMENT_ITEM: [
177
+ (r'<[^>]*data-section="comment-item"[^>]*>', 'after'),
178
+ ],
179
+ InjectionLocation.TAB_CONTENT: [
180
+ (r'<[^>]*data-section="tab-content"[^>]*>', 'after'),
181
+ ],
182
+
183
+ # === Main Content ===
184
+ InjectionLocation.MAIN_CONTENT: [
185
+ (r'<[^>]*data-section="quote-main"[^>]*>', 'after'),
186
+ (r'<main[^>]*>', 'after'),
187
+ ],
188
+
189
+ # === Sidebar ===
190
+ InjectionLocation.SIDEBAR: [
191
+ (r'<[^>]*data-section="quote-sidebar"[^>]*>', 'after'),
192
+ (r'<[^>]*data-section="quote-sidebar-right"[^>]*>', 'after'),
193
+ ],
194
+ InjectionLocation.SIDEBAR_WIDGET: [
195
+ (r'<[^>]*data-section="popular-stocks"[^>]*>', 'after'),
196
+ ],
197
+
198
+ # === Header/Nav ===
199
+ InjectionLocation.HEADER: [
200
+ (r'<header[^>]*>', 'after'),
201
+ (r'<[^>]*data-section="portfolio-header"[^>]*>', 'after'),
202
+ (r'<[^>]*data-section="markets-header"[^>]*>', 'after'),
203
+ ],
204
+ InjectionLocation.NAV: [
205
+ (r'<nav[^>]*>', 'after'),
206
+ ],
207
+
208
+ # === Footer ===
209
+ InjectionLocation.FOOTER: [
210
+ (r'<footer[^>]*>', 'after'),
211
+ ],
212
+ InjectionLocation.DISCLAIMER: [
213
+ (r'<[^>]*class="[^"]*disclaimer[^"]*"[^>]*>', 'after'),
214
+ ],
215
+
216
+ # === Metadata (invisible) ===
217
+ InjectionLocation.METADATA: [
218
+ (r'<head[^>]*>', 'after'),
219
+ ],
220
+
221
+ # === Markets ===
222
+ InjectionLocation.MARKET_INDICES: [
223
+ (r'<[^>]*data-section="market-indices"[^>]*>', 'after'),
224
+ (r'<[^>]*data-section="market-index"[^>]*>', 'after'),
225
+ ],
226
+ InjectionLocation.TOP_GAINERS: [
227
+ (r'<[^>]*data-section="movers-gainers"[^>]*>', 'after'),
228
+ ],
229
+ InjectionLocation.TOP_LOSERS: [
230
+ (r'<[^>]*data-section="movers-losers"[^>]*>', 'after'),
231
+ ],
232
+ InjectionLocation.TRENDING_STOCKS: [
233
+ (r'<[^>]*data-section="trending-stocks"[^>]*>', 'after'),
234
+ ],
235
+
236
+ # === Options ===
237
+ InjectionLocation.OPTIONS_CHAIN: [
238
+ (r'<[^>]*data-section="options-link"[^>]*>', 'after'),
239
+ (r'<[^>]*data-section="option-row"[^>]*>', 'after'),
240
+ (r'<[^>]*data-section="portfolio-options"[^>]*>', 'after'),
241
+ ],
242
+
243
+ # === Orders ===
244
+ InjectionLocation.TRADE_CONFIRMATION: [
245
+ (r'<[^>]*data-section="order-summary"[^>]*>', 'after'),
246
+ (r'<[^>]*data-section="trade-summary"[^>]*>', 'after'),
247
+ ],
248
+
249
+ # === Analyst/Related ===
250
+ InjectionLocation.RELATED_STOCKS: [
251
+ (r'<[^>]*data-section="stock-card"[^>]*>', 'after'),
252
+ (r'<[^>]*data-section="stock-item"[^>]*>', 'after'),
253
+ ],
254
+ InjectionLocation.WATCHLIST: [
255
+ (r'<[^>]*data-section="analyst-rating"[^>]*>', 'after'),
256
+ ],
257
+ InjectionLocation.HOLDERS_INFO: [
258
+ (r'<[^>]*data-section="holders-info"[^>]*>', 'after'),
259
+ ],
260
+ InjectionLocation.EARNINGS_CALENDAR: [
261
+ (r'<[^>]*data-section="earnings-calendar"[^>]*>', 'after'),
262
+ ],
263
+ }
264
+
265
+
266
+ class HtmlInjector:
267
+ """
268
+ Engine for injecting content into HTML.
269
+
270
+ Static injection model:
271
+ - Rules are filtered by page_name (bound to specific pages)
272
+ - ALL matching elements on the page get injected
273
+ - No dynamic discovery, no locking, no view-order matching
274
+ """
275
+
276
+ def __init__(self):
277
+ self.config: Optional[InjectionConfig] = None
278
+ self._injection_count = 0
279
+ self._renderer = InjectionRenderer()
280
+
281
+ def set_config(self, config: InjectionConfig):
282
+ """Set the injection configuration."""
283
+ self.config = config
284
+ self._injection_count = 0
285
+
286
+ def clear(self):
287
+ """Clear the configuration (reset to benign)."""
288
+ self.config = None
289
+ self._injection_count = 0
290
+
291
+ def is_malicious(self) -> bool:
292
+ """Check if in malicious mode."""
293
+ return self.config is not None and self.config.mode == "malicious"
294
+
295
+ def get_status(self) -> InjectionStatus:
296
+ """Get current injection status."""
297
+ return InjectionStatus(
298
+ mode=self.config.mode if self.config else "benign",
299
+ config_name=self.config.name if self.config else None,
300
+ rules_count=len(self.config.rules) if self.config else 0,
301
+ injections_applied=self._injection_count,
302
+ target_action=self.config.target_action if self.config else None
303
+ )
304
+
305
+ def apply_injections(self, html: str, page_name: str, symbol: str = "", article_id: int = 0) -> str:
306
+ """
307
+ Apply all applicable injections to HTML.
308
+
309
+ Args:
310
+ html: Original HTML content
311
+ page_name: Name of the current page (e.g., "quote", "news", "portfolios")
312
+ symbol: Stock symbol (for per-symbol filtering)
313
+ article_id: Article ID (for per-article filtering)
314
+
315
+ Returns:
316
+ HTML with injections applied (or original if benign mode)
317
+ """
318
+ if not self.config or self.config.mode != "malicious":
319
+ return html
320
+
321
+ for rule in self._get_sorted_rules(page_name, symbol, article_id):
322
+ if not rule.enabled:
323
+ continue
324
+ html = self._inject_at_location(html, rule)
325
+
326
+ return html
327
+
328
+ def _inject_at_location(self, html: str, rule: InjectionRule) -> str:
329
+ """
330
+ Inject content at ALL matching elements for the rule's location.
331
+ """
332
+ location = rule.location
333
+ patterns = LOCATION_PATTERNS.get(location, [])
334
+ injection = self._render_rule(rule)
335
+
336
+ if not patterns:
337
+ # Fallback: inject before </body>
338
+ self._injection_count += 1
339
+ return html.replace("</body>", injection + "</body>")
340
+
341
+ # Collect all matches across all patterns, deduplicated by position
342
+ all_matches = []
343
+ used_positions = set()
344
+
345
+ for pattern, position in patterns:
346
+ for match in re.finditer(pattern, html, re.IGNORECASE):
347
+ if match.start() not in used_positions:
348
+ all_matches.append((match, position))
349
+ used_positions.add(match.start())
350
+
351
+ if not all_matches:
352
+ # No matches found — fallback to body end
353
+ self._injection_count += 1
354
+ return html.replace("</body>", injection + "</body>")
355
+
356
+ # Sort by position descending so we inject from end to start
357
+ # (preserves earlier match positions)
358
+ all_matches.sort(key=lambda x: x[0].start(), reverse=True)
359
+
360
+ for match, position in all_matches:
361
+ html = self._insert_at_match(html, match, injection, position)
362
+ self._injection_count += 1
363
+
364
+ return html
365
+
366
+ def _insert_at_match(self, html: str, match: re.Match, injection: str, position: str) -> str:
367
+ """Insert injection at the matched position."""
368
+ if position == "after":
369
+ insert_pos = match.end()
370
+ else:
371
+ insert_pos = match.start()
372
+ return html[:insert_pos] + injection + html[insert_pos:]
373
+
374
+ def _get_sorted_rules(self, page_name: str, symbol: str = "", article_id: int = 0) -> List[InjectionRule]:
375
+ """Get rules that apply to this page, sorted by priority (highest first)."""
376
+ if not self.config:
377
+ return []
378
+
379
+ rules = []
380
+ for rule in self.config.rules:
381
+ if not rule.enabled:
382
+ continue
383
+ # Static page binding: if pages is set, only inject on those pages
384
+ if rule.pages and page_name not in rule.pages:
385
+ continue
386
+ if rule.symbols and symbol.upper() not in [s.upper() for s in rule.symbols]:
387
+ continue
388
+ if rule.article_id and article_id and rule.article_id != article_id:
389
+ continue
390
+ rules.append(rule)
391
+
392
+ rules.sort(key=lambda r: -r.priority)
393
+ return rules
394
+
395
+ def _render_rule(self, rule: InjectionRule) -> str:
396
+ """Render HTML for a rule."""
397
+ prompt = rule.prompt
398
+
399
+ if rule.wrap_in_context and rule.context_template:
400
+ prompt = rule.context_template.replace("{prompt}", prompt)
401
+
402
+ html = self._renderer.render(prompt, rule.method)
403
+ return html * rule.repetitions
404
+
405
+ def get_injection_count(self) -> int:
406
+ return self._injection_count
407
+
408
+ def reset_count(self):
409
+ self._injection_count = 0
@@ -0,0 +1,167 @@
1
+ """
2
+ Injection Locations - Define all possible injection points in HTML
3
+
4
+ These locations map to data-section attributes and CSS classes in the templates.
5
+ The injection engine uses regex patterns to find these locations.
6
+ """
7
+
8
+ from enum import Enum
9
+
10
+
11
+ class InjectionLocation(Enum):
12
+ """All possible locations where injection can be placed in HTML."""
13
+
14
+ # === Page Structure ===
15
+ HEAD = "head"
16
+ BODY_START = "body_start"
17
+ BODY_END = "body_end"
18
+
19
+ # === Header/Navigation ===
20
+ HEADER = "header"
21
+ LOGO = "logo"
22
+ SEARCH_BAR = "search_bar"
23
+ NAV = "nav"
24
+ NAV_ITEM = "nav_item"
25
+
26
+ # === Main Content ===
27
+ MAIN_CONTENT = "main_content"
28
+ PAGE_TITLE = "page_title"
29
+ BREADCRUMB = "breadcrumb"
30
+
31
+ # === Stock/Quote Page ===
32
+ STOCK_HEADER = "stock_header"
33
+ STOCK_PRICE = "stock_price"
34
+ STOCK_CHANGE = "stock_change"
35
+ STOCK_INFO = "stock_info"
36
+ STOCK_STATS = "stock_stats"
37
+ STOCK_DESCRIPTION = "stock_desc"
38
+
39
+ # === Chart/Analysis ===
40
+ CHART_AREA = "chart_area"
41
+ CHART_LEGEND = "chart_legend"
42
+ INDICATOR_SECTION = "indicators"
43
+
44
+ # === News - Page Level ===
45
+ NEWS_HEADER = "news_header" # data-section="news-header" - Page header area
46
+ NEWS_LIST = "news_list" # data-section="news-list" - News list container
47
+ NEWS_SIDEBAR = "news_sidebar" # data-section="news-sidebar" - Right sidebar
48
+
49
+ # === News - Item Level ===
50
+ NEWS_ITEM = "news_item" # data-section="news-item" - Individual news item
51
+ NEWS_TITLE = "news_title" # data-section="news-headline" - News headline
52
+ NEWS_SUMMARY = "news_summary" # data-section="news-summary" - News summary
53
+ NEWS_SOURCE = "news_source" # data-section="news-source" - News source
54
+ NEWS_META = "news_meta" # data-section="news-meta" - Meta info area
55
+ NEWS_FOOTER = "news_footer" # data-section="news-footer" - News footer
56
+
57
+ # === Article Page (full article view) ===
58
+ ARTICLE_CONTENT = "article_content" # data-section="article-content" - Article main container
59
+ ARTICLE_BODY = "article_body" # data-section="article-body" - Article body
60
+ ARTICLE_SUMMARY = "article_summary" # data-section="article-summary" - Article summary
61
+
62
+ # === News - Widgets ===
63
+ TRENDING = "trending" # data-section="trending-widget" - Trending widget
64
+ DATE_FILTER = "date_filter" # data-section="date-filter" - Date filter
65
+
66
+ # === Comments (in news articles) ===
67
+ COMMENTS_SECTION = "comments_section"
68
+ COMMENT_ITEM = "comment_item"
69
+
70
+ # === Portfolio ===
71
+ PORTFOLIO_SUMMARY = "portfolio_summary"
72
+ PORTFOLIO_TABLE = "portfolio_table"
73
+ POSITION_ROW = "position_row"
74
+ CASH_BALANCE = "cash_balance"
75
+
76
+ # === Trading ===
77
+ TRADE_FORM = "trade_form"
78
+ ORDER_BUTTON = "order_button"
79
+ TRADE_CONFIRMATION = "trade_confirm"
80
+
81
+ # === Options ===
82
+ OPTIONS_CHAIN = "options_chain"
83
+ OPTIONS_HEADER = "options_header"
84
+
85
+ # === Analysis ===
86
+ ANALYST_RATINGS = "analyst_ratings"
87
+ PRICE_TARGETS = "price_targets"
88
+
89
+ # === Sidebar ===
90
+ SIDEBAR = "sidebar"
91
+ SIDEBAR_WIDGET = "sidebar_widget"
92
+ RELATED_STOCKS = "related_stocks"
93
+ WATCHLIST = "watchlist"
94
+ HOLDERS_INFO = "holders_info"
95
+ EARNINGS_CALENDAR = "earnings_calendar"
96
+
97
+ # === Markets Page ===
98
+ MARKET_INDICES = "market_indices"
99
+ TOP_GAINERS = "top_gainers"
100
+ TOP_LOSERS = "top_losers"
101
+ TRENDING_STOCKS = "trending_stocks"
102
+
103
+ # === Options Page ===
104
+ OPTION_ROW = "option_row"
105
+
106
+ # === Footer & Misc ===
107
+ FOOTER = "footer"
108
+ DISCLAIMER = "disclaimer"
109
+ COPYRIGHT = "copyright"
110
+
111
+ # === Interactive Elements ===
112
+ POPUP = "popup"
113
+ TOOLTIP = "tooltip"
114
+ DROPDOWN = "dropdown"
115
+ TAB_CONTENT = "tab_content"
116
+
117
+ # === Status/Feedback ===
118
+ ERROR_MESSAGE = "error"
119
+ SUCCESS_MESSAGE = "success"
120
+ WARNING = "warning"
121
+ LOADING = "loading"
122
+ EMPTY_STATE = "empty_state"
123
+
124
+ # === Technical/Hidden ===
125
+ METADATA = "metadata"
126
+ SCRIPT = "script"
127
+ JSON_LD = "json_ld"
128
+ INLINE_STYLE = "inline_style"
129
+
130
+ @classmethod
131
+ def get_all(cls):
132
+ """Get all location values."""
133
+ return [loc.value for loc in cls]
134
+
135
+ @classmethod
136
+ def get_news_locations(cls):
137
+ """Get all news-related locations for targeted attacks."""
138
+ return [
139
+ cls.NEWS_HEADER, # Page header
140
+ cls.NEWS_LIST, # News list container
141
+ cls.NEWS_ITEM, # Individual news item
142
+ cls.NEWS_TITLE, # News headline
143
+ cls.NEWS_SUMMARY, # News summary text
144
+ cls.NEWS_SOURCE, # News source badge
145
+ cls.NEWS_META, # Meta info area
146
+ cls.NEWS_FOOTER, # News item footer
147
+ cls.NEWS_SIDEBAR, # Sidebar
148
+ cls.TRENDING, # Trending widget
149
+ cls.COMMENTS_SECTION, # Comments
150
+ ]
151
+
152
+ @classmethod
153
+ def get_quote_locations(cls):
154
+ """Get all quote page locations."""
155
+ return [
156
+ cls.STOCK_HEADER, cls.STOCK_PRICE, cls.STOCK_INFO,
157
+ cls.STOCK_STATS, cls.CHART_AREA, cls.INDICATOR_SECTION,
158
+ cls.SIDEBAR, cls.TRADE_FORM
159
+ ]
160
+
161
+ @classmethod
162
+ def get_portfolio_locations(cls):
163
+ """Get all portfolio page locations."""
164
+ return [
165
+ cls.PORTFOLIO_SUMMARY, cls.PORTFOLIO_TABLE,
166
+ cls.POSITION_ROW, cls.CASH_BALANCE
167
+ ]