crca 1.4.0__py3-none-any.whl → 1.5.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 (306) hide show
  1. CRCA.py +172 -7
  2. MODEL_CARD.md +53 -0
  3. PKG-INFO +8 -2
  4. RELEASE_NOTES.md +17 -0
  5. STABILITY.md +19 -0
  6. architecture/hybrid/consistency_engine.py +362 -0
  7. architecture/hybrid/conversation_manager.py +421 -0
  8. architecture/hybrid/explanation_generator.py +452 -0
  9. architecture/hybrid/few_shot_learner.py +533 -0
  10. architecture/hybrid/graph_compressor.py +286 -0
  11. architecture/hybrid/hybrid_agent.py +4398 -0
  12. architecture/hybrid/language_compiler.py +623 -0
  13. architecture/hybrid/main,py +0 -0
  14. architecture/hybrid/reasoning_tracker.py +322 -0
  15. architecture/hybrid/self_verifier.py +524 -0
  16. architecture/hybrid/task_decomposer.py +567 -0
  17. architecture/hybrid/text_corrector.py +341 -0
  18. benchmark_results/crca_core_benchmarks.json +178 -0
  19. branches/crca_sd/crca_sd_realtime.py +6 -2
  20. branches/general_agent/__init__.py +102 -0
  21. branches/general_agent/general_agent.py +1400 -0
  22. branches/general_agent/personality.py +169 -0
  23. branches/general_agent/utils/__init__.py +19 -0
  24. branches/general_agent/utils/prompt_builder.py +170 -0
  25. {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/METADATA +8 -2
  26. {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/RECORD +303 -20
  27. crca_core/__init__.py +35 -0
  28. crca_core/benchmarks/__init__.py +14 -0
  29. crca_core/benchmarks/synthetic_scm.py +103 -0
  30. crca_core/core/__init__.py +23 -0
  31. crca_core/core/api.py +120 -0
  32. crca_core/core/estimate.py +208 -0
  33. crca_core/core/godclass.py +72 -0
  34. crca_core/core/intervention_design.py +174 -0
  35. crca_core/core/lifecycle.py +48 -0
  36. crca_core/discovery/__init__.py +9 -0
  37. crca_core/discovery/tabular.py +193 -0
  38. crca_core/identify/__init__.py +171 -0
  39. crca_core/identify/backdoor.py +39 -0
  40. crca_core/identify/frontdoor.py +48 -0
  41. crca_core/identify/graph.py +106 -0
  42. crca_core/identify/id_algorithm.py +43 -0
  43. crca_core/identify/iv.py +48 -0
  44. crca_core/models/__init__.py +67 -0
  45. crca_core/models/provenance.py +56 -0
  46. crca_core/models/refusal.py +39 -0
  47. crca_core/models/result.py +83 -0
  48. crca_core/models/spec.py +151 -0
  49. crca_core/models/validation.py +68 -0
  50. crca_core/scm/__init__.py +9 -0
  51. crca_core/scm/linear_gaussian.py +198 -0
  52. crca_core/timeseries/__init__.py +6 -0
  53. crca_core/timeseries/pcmci.py +181 -0
  54. crca_llm/__init__.py +12 -0
  55. crca_llm/client.py +85 -0
  56. crca_llm/coauthor.py +118 -0
  57. crca_llm/orchestrator.py +289 -0
  58. crca_llm/types.py +21 -0
  59. crca_reasoning/__init__.py +16 -0
  60. crca_reasoning/critique.py +54 -0
  61. crca_reasoning/godclass.py +206 -0
  62. crca_reasoning/memory.py +24 -0
  63. crca_reasoning/rationale.py +10 -0
  64. crca_reasoning/react_controller.py +81 -0
  65. crca_reasoning/tool_router.py +97 -0
  66. crca_reasoning/types.py +40 -0
  67. crca_sd/__init__.py +15 -0
  68. crca_sd/crca_sd_core.py +2 -0
  69. crca_sd/crca_sd_governance.py +2 -0
  70. crca_sd/crca_sd_mpc.py +2 -0
  71. crca_sd/crca_sd_realtime.py +2 -0
  72. crca_sd/crca_sd_tui.py +2 -0
  73. cuda-keyring_1.1-1_all.deb +0 -0
  74. cuda-keyring_1.1-1_all.deb.1 +0 -0
  75. docs/IMAGE_ANNOTATION_USAGE.md +539 -0
  76. docs/INSTALL_DEEPSPEED.md +125 -0
  77. docs/api/branches/crca-cg.md +19 -0
  78. docs/api/branches/crca-q.md +27 -0
  79. docs/api/branches/crca-sd.md +37 -0
  80. docs/api/branches/general-agent.md +24 -0
  81. docs/api/branches/overview.md +19 -0
  82. docs/api/crca/agent-methods.md +62 -0
  83. docs/api/crca/operations.md +79 -0
  84. docs/api/crca/overview.md +32 -0
  85. docs/api/image-annotation/engine.md +52 -0
  86. docs/api/image-annotation/overview.md +17 -0
  87. docs/api/schemas/annotation.md +34 -0
  88. docs/api/schemas/core-schemas.md +82 -0
  89. docs/api/schemas/overview.md +32 -0
  90. docs/api/schemas/policy.md +30 -0
  91. docs/api/utils/conversation.md +22 -0
  92. docs/api/utils/graph-reasoner.md +32 -0
  93. docs/api/utils/overview.md +21 -0
  94. docs/api/utils/router.md +19 -0
  95. docs/api/utils/utilities.md +97 -0
  96. docs/architecture/causal-graphs.md +41 -0
  97. docs/architecture/data-flow.md +29 -0
  98. docs/architecture/design-principles.md +33 -0
  99. docs/architecture/hybrid-agent/components.md +38 -0
  100. docs/architecture/hybrid-agent/consistency.md +26 -0
  101. docs/architecture/hybrid-agent/overview.md +44 -0
  102. docs/architecture/hybrid-agent/reasoning.md +22 -0
  103. docs/architecture/llm-integration.md +26 -0
  104. docs/architecture/modular-structure.md +37 -0
  105. docs/architecture/overview.md +69 -0
  106. docs/architecture/policy-engine-arch.md +29 -0
  107. docs/branches/crca-cg/corposwarm.md +39 -0
  108. docs/branches/crca-cg/esg-scoring.md +30 -0
  109. docs/branches/crca-cg/multi-agent.md +35 -0
  110. docs/branches/crca-cg/overview.md +40 -0
  111. docs/branches/crca-q/alternative-data.md +55 -0
  112. docs/branches/crca-q/architecture.md +71 -0
  113. docs/branches/crca-q/backtesting.md +45 -0
  114. docs/branches/crca-q/causal-engine.md +33 -0
  115. docs/branches/crca-q/execution.md +39 -0
  116. docs/branches/crca-q/market-data.md +60 -0
  117. docs/branches/crca-q/overview.md +58 -0
  118. docs/branches/crca-q/philosophy.md +60 -0
  119. docs/branches/crca-q/portfolio-optimization.md +66 -0
  120. docs/branches/crca-q/risk-management.md +102 -0
  121. docs/branches/crca-q/setup.md +65 -0
  122. docs/branches/crca-q/signal-generation.md +61 -0
  123. docs/branches/crca-q/signal-validation.md +43 -0
  124. docs/branches/crca-sd/core.md +84 -0
  125. docs/branches/crca-sd/governance.md +53 -0
  126. docs/branches/crca-sd/mpc-solver.md +65 -0
  127. docs/branches/crca-sd/overview.md +59 -0
  128. docs/branches/crca-sd/realtime.md +28 -0
  129. docs/branches/crca-sd/tui.md +20 -0
  130. docs/branches/general-agent/overview.md +37 -0
  131. docs/branches/general-agent/personality.md +36 -0
  132. docs/branches/general-agent/prompt-builder.md +30 -0
  133. docs/changelog/index.md +79 -0
  134. docs/contributing/code-style.md +69 -0
  135. docs/contributing/documentation.md +43 -0
  136. docs/contributing/overview.md +29 -0
  137. docs/contributing/testing.md +29 -0
  138. docs/core/crcagent/async-operations.md +65 -0
  139. docs/core/crcagent/automatic-extraction.md +107 -0
  140. docs/core/crcagent/batch-prediction.md +80 -0
  141. docs/core/crcagent/bayesian-inference.md +60 -0
  142. docs/core/crcagent/causal-graph.md +92 -0
  143. docs/core/crcagent/counterfactuals.md +96 -0
  144. docs/core/crcagent/deterministic-simulation.md +78 -0
  145. docs/core/crcagent/dual-mode-operation.md +82 -0
  146. docs/core/crcagent/initialization.md +88 -0
  147. docs/core/crcagent/optimization.md +65 -0
  148. docs/core/crcagent/overview.md +63 -0
  149. docs/core/crcagent/time-series.md +57 -0
  150. docs/core/schemas/annotation.md +30 -0
  151. docs/core/schemas/core-schemas.md +82 -0
  152. docs/core/schemas/overview.md +30 -0
  153. docs/core/schemas/policy.md +41 -0
  154. docs/core/templates/base-agent.md +31 -0
  155. docs/core/templates/feature-mixins.md +31 -0
  156. docs/core/templates/overview.md +29 -0
  157. docs/core/templates/templates-guide.md +75 -0
  158. docs/core/tools/mcp-client.md +34 -0
  159. docs/core/tools/overview.md +24 -0
  160. docs/core/utils/conversation.md +27 -0
  161. docs/core/utils/graph-reasoner.md +29 -0
  162. docs/core/utils/overview.md +27 -0
  163. docs/core/utils/router.md +27 -0
  164. docs/core/utils/utilities.md +97 -0
  165. docs/css/custom.css +84 -0
  166. docs/examples/basic-usage.md +57 -0
  167. docs/examples/general-agent/general-agent-examples.md +50 -0
  168. docs/examples/hybrid-agent/hybrid-agent-examples.md +56 -0
  169. docs/examples/image-annotation/image-annotation-examples.md +54 -0
  170. docs/examples/integration/integration-examples.md +58 -0
  171. docs/examples/overview.md +37 -0
  172. docs/examples/trading/trading-examples.md +46 -0
  173. docs/features/causal-reasoning/advanced-topics.md +101 -0
  174. docs/features/causal-reasoning/counterfactuals.md +43 -0
  175. docs/features/causal-reasoning/do-calculus.md +50 -0
  176. docs/features/causal-reasoning/overview.md +47 -0
  177. docs/features/causal-reasoning/structural-models.md +52 -0
  178. docs/features/hybrid-agent/advanced-components.md +55 -0
  179. docs/features/hybrid-agent/core-components.md +64 -0
  180. docs/features/hybrid-agent/overview.md +34 -0
  181. docs/features/image-annotation/engine.md +82 -0
  182. docs/features/image-annotation/features.md +113 -0
  183. docs/features/image-annotation/integration.md +75 -0
  184. docs/features/image-annotation/overview.md +53 -0
  185. docs/features/image-annotation/quickstart.md +73 -0
  186. docs/features/policy-engine/doctrine-ledger.md +105 -0
  187. docs/features/policy-engine/monitoring.md +44 -0
  188. docs/features/policy-engine/mpc-control.md +89 -0
  189. docs/features/policy-engine/overview.md +46 -0
  190. docs/getting-started/configuration.md +225 -0
  191. docs/getting-started/first-agent.md +164 -0
  192. docs/getting-started/installation.md +144 -0
  193. docs/getting-started/quickstart.md +137 -0
  194. docs/index.md +118 -0
  195. docs/js/mathjax.js +13 -0
  196. docs/lrm/discovery_proof_notes.md +25 -0
  197. docs/lrm/finetune_full.md +83 -0
  198. docs/lrm/math_appendix.md +120 -0
  199. docs/lrm/overview.md +32 -0
  200. docs/mkdocs.yml +238 -0
  201. docs/stylesheets/extra.css +21 -0
  202. docs_generated/crca_core/CounterfactualResult.md +12 -0
  203. docs_generated/crca_core/DiscoveryHypothesisResult.md +13 -0
  204. docs_generated/crca_core/DraftSpec.md +13 -0
  205. docs_generated/crca_core/EstimateResult.md +13 -0
  206. docs_generated/crca_core/IdentificationResult.md +17 -0
  207. docs_generated/crca_core/InterventionDesignResult.md +12 -0
  208. docs_generated/crca_core/LockedSpec.md +15 -0
  209. docs_generated/crca_core/RefusalResult.md +12 -0
  210. docs_generated/crca_core/ValidationReport.md +9 -0
  211. docs_generated/crca_core/index.md +13 -0
  212. examples/general_agent_example.py +277 -0
  213. examples/general_agent_quickstart.py +202 -0
  214. examples/general_agent_simple.py +92 -0
  215. examples/hybrid_agent_auto_extraction.py +84 -0
  216. examples/hybrid_agent_dictionary_demo.py +104 -0
  217. examples/hybrid_agent_enhanced.py +179 -0
  218. examples/hybrid_agent_general_knowledge.py +107 -0
  219. examples/image_annotation_quickstart.py +328 -0
  220. examples/test_hybrid_fixes.py +77 -0
  221. image_annotation/__init__.py +27 -0
  222. image_annotation/annotation_engine.py +2593 -0
  223. install_cuda_wsl2.sh +59 -0
  224. install_deepspeed.sh +56 -0
  225. install_deepspeed_simple.sh +87 -0
  226. mkdocs.yml +252 -0
  227. ollama/Modelfile +8 -0
  228. prompts/__init__.py +2 -1
  229. prompts/default_crca.py +9 -1
  230. prompts/general_agent.py +227 -0
  231. prompts/image_annotation.py +56 -0
  232. pyproject.toml +17 -2
  233. requirements-docs.txt +10 -0
  234. requirements.txt +21 -2
  235. schemas/__init__.py +26 -1
  236. schemas/annotation.py +222 -0
  237. schemas/conversation.py +193 -0
  238. schemas/hybrid.py +211 -0
  239. schemas/reasoning.py +276 -0
  240. schemas_export/crca_core/CounterfactualResult.schema.json +108 -0
  241. schemas_export/crca_core/DiscoveryHypothesisResult.schema.json +113 -0
  242. schemas_export/crca_core/DraftSpec.schema.json +635 -0
  243. schemas_export/crca_core/EstimateResult.schema.json +113 -0
  244. schemas_export/crca_core/IdentificationResult.schema.json +145 -0
  245. schemas_export/crca_core/InterventionDesignResult.schema.json +111 -0
  246. schemas_export/crca_core/LockedSpec.schema.json +646 -0
  247. schemas_export/crca_core/RefusalResult.schema.json +90 -0
  248. schemas_export/crca_core/ValidationReport.schema.json +62 -0
  249. scripts/build_lrm_dataset.py +80 -0
  250. scripts/export_crca_core_schemas.py +54 -0
  251. scripts/export_hf_lrm.py +37 -0
  252. scripts/export_ollama_gguf.py +45 -0
  253. scripts/generate_changelog.py +157 -0
  254. scripts/generate_crca_core_docs_from_schemas.py +86 -0
  255. scripts/run_crca_core_benchmarks.py +163 -0
  256. scripts/run_full_finetune.py +198 -0
  257. scripts/run_lrm_eval.py +31 -0
  258. templates/graph_management.py +29 -0
  259. tests/conftest.py +9 -0
  260. tests/test_core.py +2 -3
  261. tests/test_crca_core_discovery_tabular.py +15 -0
  262. tests/test_crca_core_estimate_dowhy.py +36 -0
  263. tests/test_crca_core_identify.py +18 -0
  264. tests/test_crca_core_intervention_design.py +36 -0
  265. tests/test_crca_core_linear_gaussian_scm.py +69 -0
  266. tests/test_crca_core_spec.py +25 -0
  267. tests/test_crca_core_timeseries_pcmci.py +15 -0
  268. tests/test_crca_llm_coauthor.py +12 -0
  269. tests/test_crca_llm_orchestrator.py +80 -0
  270. tests/test_hybrid_agent_llm_enhanced.py +556 -0
  271. tests/test_image_annotation_demo.py +376 -0
  272. tests/test_image_annotation_operational.py +408 -0
  273. tests/test_image_annotation_unit.py +551 -0
  274. tests/test_training_moe.py +13 -0
  275. training/__init__.py +42 -0
  276. training/datasets.py +140 -0
  277. training/deepspeed_zero2_0_5b.json +22 -0
  278. training/deepspeed_zero2_1_5b.json +22 -0
  279. training/deepspeed_zero3_0_5b.json +28 -0
  280. training/deepspeed_zero3_14b.json +28 -0
  281. training/deepspeed_zero3_h100_3gpu.json +20 -0
  282. training/deepspeed_zero3_offload.json +28 -0
  283. training/eval.py +92 -0
  284. training/finetune.py +516 -0
  285. training/public_datasets.py +89 -0
  286. training_data/react_train.jsonl +7473 -0
  287. utils/agent_discovery.py +311 -0
  288. utils/batch_processor.py +317 -0
  289. utils/conversation.py +78 -0
  290. utils/edit_distance.py +118 -0
  291. utils/formatter.py +33 -0
  292. utils/graph_reasoner.py +530 -0
  293. utils/rate_limiter.py +283 -0
  294. utils/router.py +2 -2
  295. utils/tool_discovery.py +307 -0
  296. webui/__init__.py +10 -0
  297. webui/app.py +229 -0
  298. webui/config.py +104 -0
  299. webui/static/css/style.css +332 -0
  300. webui/static/js/main.js +284 -0
  301. webui/templates/index.html +42 -0
  302. tests/test_crca_excel.py +0 -166
  303. tests/test_data_broker.py +0 -424
  304. tests/test_palantir.py +0 -349
  305. {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/WHEEL +0 -0
  306. {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/licenses/LICENSE +0 -0
tests/test_palantir.py DELETED
@@ -1,349 +0,0 @@
1
- """
2
- Unit tests for Palantir module.
3
-
4
- Tests core components without requiring Shodan API access.
5
- """
6
-
7
- import pytest
8
- from unittest.mock import Mock, patch, MagicMock
9
- from typing import List, Dict, Any
10
-
11
- from palantir.device_discovery import Device, DeviceType, DeviceDiscovery
12
- from palantir.network_mapper import NetworkGraph, NetworkMapper, RelationshipType
13
- from palantir.shodan_client import ShodanResult
14
-
15
-
16
- class TestDevice:
17
- """Tests for Device class."""
18
-
19
- def test_device_creation(self):
20
- """Test device creation."""
21
- device = Device(
22
- ip="192.168.1.1",
23
- port=80,
24
- service="http",
25
- banner="Apache/2.4.41",
26
- vulnerabilities=["CVE-2021-44228"],
27
- no_auth=True
28
- )
29
-
30
- assert device.ip == "192.168.1.1"
31
- assert device.port == 80
32
- assert device.service == "http"
33
- assert len(device.vulnerabilities) == 1
34
- assert device.no_auth is True
35
-
36
- def test_device_hashable(self):
37
- """Test that Device is hashable."""
38
- device1 = Device(ip="192.168.1.1", port=80, service="http")
39
- device2 = Device(ip="192.168.1.1", port=80, service="http")
40
- device3 = Device(ip="192.168.1.2", port=80, service="http")
41
-
42
- assert hash(device1) == hash(device2)
43
- assert hash(device1) != hash(device3)
44
-
45
- device_set = {device1, device2, device3}
46
- assert len(device_set) == 2
47
-
48
- def test_device_equality(self):
49
- """Test device equality."""
50
- device1 = Device(ip="192.168.1.1", port=80, service="http")
51
- device2 = Device(ip="192.168.1.1", port=80, service="http")
52
- device3 = Device(ip="192.168.1.1", port=443, service="https")
53
-
54
- assert device1 == device2
55
- assert device1 != device3
56
-
57
-
58
- class TestDeviceDiscovery:
59
- """Tests for DeviceDiscovery class."""
60
-
61
- def test_classify_device_type(self):
62
- """Test device type classification."""
63
- discovery = DeviceDiscovery()
64
-
65
- # Test web server
66
- result = ShodanResult(
67
- ip="192.168.1.1",
68
- port=80,
69
- service="http",
70
- product="Apache"
71
- )
72
- device_type = discovery.classify_device_type(result)
73
- assert device_type == DeviceType.WEB_SERVER
74
-
75
- # Test SSH server
76
- result = ShodanResult(
77
- ip="192.168.1.1",
78
- port=22,
79
- service="ssh"
80
- )
81
- device_type = discovery.classify_device_type(result)
82
- assert device_type == DeviceType.SSH_SERVER
83
-
84
- def test_detect_no_auth(self):
85
- """Test no-auth detection."""
86
- discovery = DeviceDiscovery()
87
-
88
- # Test with no-auth keyword
89
- result = ShodanResult(
90
- ip="192.168.1.1",
91
- port=21,
92
- service="ftp",
93
- banner="220 Anonymous access granted"
94
- )
95
- assert discovery.detect_no_auth(result) is True
96
-
97
- # Test without no-auth keyword
98
- result = ShodanResult(
99
- ip="192.168.1.1",
100
- port=22,
101
- service="ssh",
102
- banner="SSH-2.0-OpenSSH"
103
- )
104
- assert discovery.detect_no_auth(result) is False
105
-
106
- def test_filter_devices(self):
107
- """Test device filtering."""
108
- discovery = DeviceDiscovery(prefer_no_auth=True)
109
-
110
- devices = [
111
- Device(ip="192.168.1.1", port=80, service="http", no_auth=True, vulnerabilities=["CVE-1"]),
112
- Device(ip="192.168.1.2", port=80, service="http", no_auth=False, vulnerabilities=[]),
113
- Device(ip="192.168.1.3", port=22, service="ssh", no_auth=True, vulnerabilities=["CVE-1", "CVE-2"]),
114
- ]
115
-
116
- # Filter by no_auth
117
- filtered = discovery.filter_devices(devices, {"no_auth": True})
118
- assert len(filtered) == 2
119
- assert all(d.no_auth for d in filtered)
120
-
121
- # Filter by min vulnerabilities
122
- filtered = discovery.filter_devices(devices, {"min_vulnerabilities": 1})
123
- assert len(filtered) == 2
124
-
125
- # Filter by service
126
- filtered = discovery.filter_devices(devices, {"service": "http"})
127
- assert len(filtered) == 2
128
- assert all("http" in d.service.lower() for d in filtered)
129
-
130
-
131
- class TestNetworkMapper:
132
- """Tests for NetworkMapper class."""
133
-
134
- def test_same_subnet(self):
135
- """Test same-subnet detection."""
136
- mapper = NetworkMapper(subnet_threshold=24)
137
-
138
- device1 = Device(ip="192.168.1.10", port=80, service="http")
139
- device2 = Device(ip="192.168.1.20", port=80, service="http")
140
- device3 = Device(ip="192.168.2.10", port=80, service="http")
141
-
142
- assert mapper._same_subnet(device1, device2) is True
143
- assert mapper._same_subnet(device1, device3) is False
144
-
145
- def test_same_asn(self):
146
- """Test same-ASN detection."""
147
- mapper = NetworkMapper()
148
-
149
- device1 = Device(ip="192.168.1.1", port=80, service="http", asn="AS12345")
150
- device2 = Device(ip="192.168.1.2", port=80, service="http", asn="AS12345")
151
- device3 = Device(ip="192.168.1.3", port=80, service="http", asn="AS67890")
152
-
153
- assert mapper._same_asn(device1, device2) is True
154
- assert mapper._same_asn(device1, device3) is False
155
-
156
- def test_same_service(self):
157
- """Test same-service detection."""
158
- mapper = NetworkMapper()
159
-
160
- device1 = Device(ip="192.168.1.1", port=80, service="http")
161
- device2 = Device(ip="192.168.1.2", port=80, service="http")
162
- device3 = Device(ip="192.168.1.3", port=22, service="ssh")
163
-
164
- assert mapper._same_service(device1, device2) is True
165
- assert mapper._same_service(device1, device3) is False
166
-
167
- def test_map_network(self):
168
- """Test network mapping."""
169
- mapper = NetworkMapper()
170
-
171
- devices = [
172
- Device(ip="192.168.1.10", port=80, service="http", asn="AS12345"),
173
- Device(ip="192.168.1.20", port=80, service="http", asn="AS12345"),
174
- Device(ip="192.168.2.10", port=22, service="ssh", asn="AS67890"),
175
- ]
176
-
177
- network = mapper.map_network(devices)
178
-
179
- assert len(network.devices) == 3
180
- assert len(network.edges) > 0
181
-
182
- # Should have same-subnet and same-service relationships
183
- relationship_types = {rel for _, _, rel in network.edges}
184
- assert RelationshipType.SAME_SUBNET in relationship_types or \
185
- RelationshipType.SAME_SERVICE in relationship_types
186
-
187
-
188
- class TestNetworkGraph:
189
- """Tests for NetworkGraph class."""
190
-
191
- def test_network_graph_creation(self):
192
- """Test network graph creation."""
193
- devices = [
194
- Device(ip="192.168.1.1", port=80, service="http"),
195
- Device(ip="192.168.1.2", port=80, service="http"),
196
- ]
197
-
198
- graph = NetworkGraph(devices=devices)
199
-
200
- assert len(graph.devices) == 2
201
- assert graph.get_device_by_ip("192.168.1.1") is not None
202
- assert graph.get_device_by_ip("192.168.1.99") is None
203
-
204
- def test_get_neighbors(self):
205
- """Test getting neighbors."""
206
- device1 = Device(ip="192.168.1.1", port=80, service="http")
207
- device2 = Device(ip="192.168.1.2", port=80, service="http")
208
- device3 = Device(ip="192.168.1.3", port=22, service="ssh")
209
-
210
- graph = NetworkGraph(
211
- devices=[device1, device2, device3],
212
- edges=[
213
- (device1, device2, RelationshipType.SAME_SERVICE),
214
- (device1, device3, RelationshipType.SAME_SUBNET),
215
- ]
216
- )
217
-
218
- neighbors = graph.get_neighbors(device1)
219
- assert len(neighbors) == 2
220
- assert device2 in neighbors
221
- assert device3 in neighbors
222
-
223
-
224
- class TestCausalModeler:
225
- """Tests for CausalModeler class."""
226
-
227
- @patch('palantir.causal_modeler.CRCA_AVAILABLE', True)
228
- @patch('palantir.causal_modeler.CRCAAgent')
229
- def test_causal_modeler_initialization(self, mock_crca):
230
- """Test causal modeler initialization."""
231
- from palantir.causal_modeler import CausalModeler
232
-
233
- mock_agent = MagicMock()
234
- mock_crca.return_value = mock_agent
235
-
236
- modeler = CausalModeler()
237
-
238
- assert modeler.crca_agent is not None
239
- # Should have added causal relationships
240
- assert mock_agent.add_causal_relationship.called
241
-
242
- @patch('palantir.causal_modeler.CRCA_AVAILABLE', True)
243
- @patch('palantir.causal_modeler.CRCAAgent')
244
- def test_calculate_vulnerability_score(self, mock_crca):
245
- """Test vulnerability score calculation."""
246
- from palantir.causal_modeler import CausalModeler
247
-
248
- mock_agent = MagicMock()
249
- mock_crca.return_value = mock_agent
250
-
251
- modeler = CausalModeler()
252
-
253
- # Device with vulnerabilities
254
- device = Device(
255
- ip="192.168.1.1",
256
- port=80,
257
- service="http",
258
- vulnerabilities=["CVE-1", "CVE-2"],
259
- no_auth=True
260
- )
261
-
262
- score = modeler.calculate_device_vulnerability_score(device)
263
- assert 0.0 <= score <= 1.0
264
- assert score > 0.5 # Should be high with 2 vulns and no auth
265
-
266
-
267
- class TestShodanClient:
268
- """Tests for ShodanClient class."""
269
-
270
- @patch('palantir.shodan_client.SHODAN_AVAILABLE', True)
271
- @patch('palantir.shodan_client.shodan')
272
- def test_shodan_client_initialization(self, mock_shodan_module):
273
- """Test Shodan client initialization."""
274
- from palantir.shodan_client import ShodanClient
275
-
276
- mock_api = MagicMock()
277
- mock_shodan_module.Shodan.return_value = mock_api
278
-
279
- client = ShodanClient(api_key="test-key")
280
-
281
- assert client.api_key == "test-key"
282
- assert client.api is not None
283
-
284
- @patch('palantir.shodan_client.SHODAN_AVAILABLE', True)
285
- @patch('palantir.shodan_client.shodan')
286
- def test_rate_limiting(self, mock_shodan_module):
287
- """Test rate limiting."""
288
- from palantir.shodan_client import ShodanClient
289
- import time
290
-
291
- mock_api = MagicMock()
292
- mock_shodan_module.Shodan.return_value = mock_api
293
-
294
- client = ShodanClient(api_key="test-key", rate_limit=10.0)
295
-
296
- start_time = time.time()
297
- client._rate_limit_wait()
298
- client._rate_limit_wait()
299
- elapsed = time.time() - start_time
300
-
301
- # Should have waited at least 0.1 seconds (1/10)
302
- assert elapsed >= 0.05 # Allow some tolerance
303
-
304
-
305
- def test_integration_mock():
306
- """Integration test with mocked Shodan."""
307
- from palantir.palantir_agent import PalantirAgent
308
-
309
- # Mock Shodan client
310
- with patch('palantir.shodan_client.SHODAN_AVAILABLE', True), \
311
- patch('palantir.shodan_client.shodan') as mock_shodan:
312
-
313
- mock_api = MagicMock()
314
- mock_shodan.Shodan.return_value = mock_api
315
-
316
- # Mock search results
317
- mock_api.search.return_value = {
318
- "matches": [
319
- {
320
- "ip_str": "192.168.1.1",
321
- "port": 80,
322
- "product": "Apache",
323
- "data": "HTTP/1.1 200 OK",
324
- "hostnames": [],
325
- "location": {},
326
- "org": "Test Org",
327
- "asn": "AS12345",
328
- "os": "Linux",
329
- "vulns": {"CVE-2021-44228": {}}
330
- }
331
- ]
332
- }
333
-
334
- # Create agent
335
- agent = PalantirAgent(shodan_api_key="test-key")
336
-
337
- # Test discovery
338
- devices = agent.discover_devices(
339
- query="product:Apache",
340
- filters={"max_results": 1}
341
- )
342
-
343
- assert len(devices) > 0
344
- assert devices[0].ip == "192.168.1.1"
345
-
346
-
347
- if __name__ == "__main__":
348
- pytest.main([__file__, "-v"])
349
-
File without changes