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.
- CRCA.py +172 -7
- MODEL_CARD.md +53 -0
- PKG-INFO +8 -2
- RELEASE_NOTES.md +17 -0
- STABILITY.md +19 -0
- architecture/hybrid/consistency_engine.py +362 -0
- architecture/hybrid/conversation_manager.py +421 -0
- architecture/hybrid/explanation_generator.py +452 -0
- architecture/hybrid/few_shot_learner.py +533 -0
- architecture/hybrid/graph_compressor.py +286 -0
- architecture/hybrid/hybrid_agent.py +4398 -0
- architecture/hybrid/language_compiler.py +623 -0
- architecture/hybrid/main,py +0 -0
- architecture/hybrid/reasoning_tracker.py +322 -0
- architecture/hybrid/self_verifier.py +524 -0
- architecture/hybrid/task_decomposer.py +567 -0
- architecture/hybrid/text_corrector.py +341 -0
- benchmark_results/crca_core_benchmarks.json +178 -0
- branches/crca_sd/crca_sd_realtime.py +6 -2
- branches/general_agent/__init__.py +102 -0
- branches/general_agent/general_agent.py +1400 -0
- branches/general_agent/personality.py +169 -0
- branches/general_agent/utils/__init__.py +19 -0
- branches/general_agent/utils/prompt_builder.py +170 -0
- {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/METADATA +8 -2
- {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/RECORD +303 -20
- crca_core/__init__.py +35 -0
- crca_core/benchmarks/__init__.py +14 -0
- crca_core/benchmarks/synthetic_scm.py +103 -0
- crca_core/core/__init__.py +23 -0
- crca_core/core/api.py +120 -0
- crca_core/core/estimate.py +208 -0
- crca_core/core/godclass.py +72 -0
- crca_core/core/intervention_design.py +174 -0
- crca_core/core/lifecycle.py +48 -0
- crca_core/discovery/__init__.py +9 -0
- crca_core/discovery/tabular.py +193 -0
- crca_core/identify/__init__.py +171 -0
- crca_core/identify/backdoor.py +39 -0
- crca_core/identify/frontdoor.py +48 -0
- crca_core/identify/graph.py +106 -0
- crca_core/identify/id_algorithm.py +43 -0
- crca_core/identify/iv.py +48 -0
- crca_core/models/__init__.py +67 -0
- crca_core/models/provenance.py +56 -0
- crca_core/models/refusal.py +39 -0
- crca_core/models/result.py +83 -0
- crca_core/models/spec.py +151 -0
- crca_core/models/validation.py +68 -0
- crca_core/scm/__init__.py +9 -0
- crca_core/scm/linear_gaussian.py +198 -0
- crca_core/timeseries/__init__.py +6 -0
- crca_core/timeseries/pcmci.py +181 -0
- crca_llm/__init__.py +12 -0
- crca_llm/client.py +85 -0
- crca_llm/coauthor.py +118 -0
- crca_llm/orchestrator.py +289 -0
- crca_llm/types.py +21 -0
- crca_reasoning/__init__.py +16 -0
- crca_reasoning/critique.py +54 -0
- crca_reasoning/godclass.py +206 -0
- crca_reasoning/memory.py +24 -0
- crca_reasoning/rationale.py +10 -0
- crca_reasoning/react_controller.py +81 -0
- crca_reasoning/tool_router.py +97 -0
- crca_reasoning/types.py +40 -0
- crca_sd/__init__.py +15 -0
- crca_sd/crca_sd_core.py +2 -0
- crca_sd/crca_sd_governance.py +2 -0
- crca_sd/crca_sd_mpc.py +2 -0
- crca_sd/crca_sd_realtime.py +2 -0
- crca_sd/crca_sd_tui.py +2 -0
- cuda-keyring_1.1-1_all.deb +0 -0
- cuda-keyring_1.1-1_all.deb.1 +0 -0
- docs/IMAGE_ANNOTATION_USAGE.md +539 -0
- docs/INSTALL_DEEPSPEED.md +125 -0
- docs/api/branches/crca-cg.md +19 -0
- docs/api/branches/crca-q.md +27 -0
- docs/api/branches/crca-sd.md +37 -0
- docs/api/branches/general-agent.md +24 -0
- docs/api/branches/overview.md +19 -0
- docs/api/crca/agent-methods.md +62 -0
- docs/api/crca/operations.md +79 -0
- docs/api/crca/overview.md +32 -0
- docs/api/image-annotation/engine.md +52 -0
- docs/api/image-annotation/overview.md +17 -0
- docs/api/schemas/annotation.md +34 -0
- docs/api/schemas/core-schemas.md +82 -0
- docs/api/schemas/overview.md +32 -0
- docs/api/schemas/policy.md +30 -0
- docs/api/utils/conversation.md +22 -0
- docs/api/utils/graph-reasoner.md +32 -0
- docs/api/utils/overview.md +21 -0
- docs/api/utils/router.md +19 -0
- docs/api/utils/utilities.md +97 -0
- docs/architecture/causal-graphs.md +41 -0
- docs/architecture/data-flow.md +29 -0
- docs/architecture/design-principles.md +33 -0
- docs/architecture/hybrid-agent/components.md +38 -0
- docs/architecture/hybrid-agent/consistency.md +26 -0
- docs/architecture/hybrid-agent/overview.md +44 -0
- docs/architecture/hybrid-agent/reasoning.md +22 -0
- docs/architecture/llm-integration.md +26 -0
- docs/architecture/modular-structure.md +37 -0
- docs/architecture/overview.md +69 -0
- docs/architecture/policy-engine-arch.md +29 -0
- docs/branches/crca-cg/corposwarm.md +39 -0
- docs/branches/crca-cg/esg-scoring.md +30 -0
- docs/branches/crca-cg/multi-agent.md +35 -0
- docs/branches/crca-cg/overview.md +40 -0
- docs/branches/crca-q/alternative-data.md +55 -0
- docs/branches/crca-q/architecture.md +71 -0
- docs/branches/crca-q/backtesting.md +45 -0
- docs/branches/crca-q/causal-engine.md +33 -0
- docs/branches/crca-q/execution.md +39 -0
- docs/branches/crca-q/market-data.md +60 -0
- docs/branches/crca-q/overview.md +58 -0
- docs/branches/crca-q/philosophy.md +60 -0
- docs/branches/crca-q/portfolio-optimization.md +66 -0
- docs/branches/crca-q/risk-management.md +102 -0
- docs/branches/crca-q/setup.md +65 -0
- docs/branches/crca-q/signal-generation.md +61 -0
- docs/branches/crca-q/signal-validation.md +43 -0
- docs/branches/crca-sd/core.md +84 -0
- docs/branches/crca-sd/governance.md +53 -0
- docs/branches/crca-sd/mpc-solver.md +65 -0
- docs/branches/crca-sd/overview.md +59 -0
- docs/branches/crca-sd/realtime.md +28 -0
- docs/branches/crca-sd/tui.md +20 -0
- docs/branches/general-agent/overview.md +37 -0
- docs/branches/general-agent/personality.md +36 -0
- docs/branches/general-agent/prompt-builder.md +30 -0
- docs/changelog/index.md +79 -0
- docs/contributing/code-style.md +69 -0
- docs/contributing/documentation.md +43 -0
- docs/contributing/overview.md +29 -0
- docs/contributing/testing.md +29 -0
- docs/core/crcagent/async-operations.md +65 -0
- docs/core/crcagent/automatic-extraction.md +107 -0
- docs/core/crcagent/batch-prediction.md +80 -0
- docs/core/crcagent/bayesian-inference.md +60 -0
- docs/core/crcagent/causal-graph.md +92 -0
- docs/core/crcagent/counterfactuals.md +96 -0
- docs/core/crcagent/deterministic-simulation.md +78 -0
- docs/core/crcagent/dual-mode-operation.md +82 -0
- docs/core/crcagent/initialization.md +88 -0
- docs/core/crcagent/optimization.md +65 -0
- docs/core/crcagent/overview.md +63 -0
- docs/core/crcagent/time-series.md +57 -0
- docs/core/schemas/annotation.md +30 -0
- docs/core/schemas/core-schemas.md +82 -0
- docs/core/schemas/overview.md +30 -0
- docs/core/schemas/policy.md +41 -0
- docs/core/templates/base-agent.md +31 -0
- docs/core/templates/feature-mixins.md +31 -0
- docs/core/templates/overview.md +29 -0
- docs/core/templates/templates-guide.md +75 -0
- docs/core/tools/mcp-client.md +34 -0
- docs/core/tools/overview.md +24 -0
- docs/core/utils/conversation.md +27 -0
- docs/core/utils/graph-reasoner.md +29 -0
- docs/core/utils/overview.md +27 -0
- docs/core/utils/router.md +27 -0
- docs/core/utils/utilities.md +97 -0
- docs/css/custom.css +84 -0
- docs/examples/basic-usage.md +57 -0
- docs/examples/general-agent/general-agent-examples.md +50 -0
- docs/examples/hybrid-agent/hybrid-agent-examples.md +56 -0
- docs/examples/image-annotation/image-annotation-examples.md +54 -0
- docs/examples/integration/integration-examples.md +58 -0
- docs/examples/overview.md +37 -0
- docs/examples/trading/trading-examples.md +46 -0
- docs/features/causal-reasoning/advanced-topics.md +101 -0
- docs/features/causal-reasoning/counterfactuals.md +43 -0
- docs/features/causal-reasoning/do-calculus.md +50 -0
- docs/features/causal-reasoning/overview.md +47 -0
- docs/features/causal-reasoning/structural-models.md +52 -0
- docs/features/hybrid-agent/advanced-components.md +55 -0
- docs/features/hybrid-agent/core-components.md +64 -0
- docs/features/hybrid-agent/overview.md +34 -0
- docs/features/image-annotation/engine.md +82 -0
- docs/features/image-annotation/features.md +113 -0
- docs/features/image-annotation/integration.md +75 -0
- docs/features/image-annotation/overview.md +53 -0
- docs/features/image-annotation/quickstart.md +73 -0
- docs/features/policy-engine/doctrine-ledger.md +105 -0
- docs/features/policy-engine/monitoring.md +44 -0
- docs/features/policy-engine/mpc-control.md +89 -0
- docs/features/policy-engine/overview.md +46 -0
- docs/getting-started/configuration.md +225 -0
- docs/getting-started/first-agent.md +164 -0
- docs/getting-started/installation.md +144 -0
- docs/getting-started/quickstart.md +137 -0
- docs/index.md +118 -0
- docs/js/mathjax.js +13 -0
- docs/lrm/discovery_proof_notes.md +25 -0
- docs/lrm/finetune_full.md +83 -0
- docs/lrm/math_appendix.md +120 -0
- docs/lrm/overview.md +32 -0
- docs/mkdocs.yml +238 -0
- docs/stylesheets/extra.css +21 -0
- docs_generated/crca_core/CounterfactualResult.md +12 -0
- docs_generated/crca_core/DiscoveryHypothesisResult.md +13 -0
- docs_generated/crca_core/DraftSpec.md +13 -0
- docs_generated/crca_core/EstimateResult.md +13 -0
- docs_generated/crca_core/IdentificationResult.md +17 -0
- docs_generated/crca_core/InterventionDesignResult.md +12 -0
- docs_generated/crca_core/LockedSpec.md +15 -0
- docs_generated/crca_core/RefusalResult.md +12 -0
- docs_generated/crca_core/ValidationReport.md +9 -0
- docs_generated/crca_core/index.md +13 -0
- examples/general_agent_example.py +277 -0
- examples/general_agent_quickstart.py +202 -0
- examples/general_agent_simple.py +92 -0
- examples/hybrid_agent_auto_extraction.py +84 -0
- examples/hybrid_agent_dictionary_demo.py +104 -0
- examples/hybrid_agent_enhanced.py +179 -0
- examples/hybrid_agent_general_knowledge.py +107 -0
- examples/image_annotation_quickstart.py +328 -0
- examples/test_hybrid_fixes.py +77 -0
- image_annotation/__init__.py +27 -0
- image_annotation/annotation_engine.py +2593 -0
- install_cuda_wsl2.sh +59 -0
- install_deepspeed.sh +56 -0
- install_deepspeed_simple.sh +87 -0
- mkdocs.yml +252 -0
- ollama/Modelfile +8 -0
- prompts/__init__.py +2 -1
- prompts/default_crca.py +9 -1
- prompts/general_agent.py +227 -0
- prompts/image_annotation.py +56 -0
- pyproject.toml +17 -2
- requirements-docs.txt +10 -0
- requirements.txt +21 -2
- schemas/__init__.py +26 -1
- schemas/annotation.py +222 -0
- schemas/conversation.py +193 -0
- schemas/hybrid.py +211 -0
- schemas/reasoning.py +276 -0
- schemas_export/crca_core/CounterfactualResult.schema.json +108 -0
- schemas_export/crca_core/DiscoveryHypothesisResult.schema.json +113 -0
- schemas_export/crca_core/DraftSpec.schema.json +635 -0
- schemas_export/crca_core/EstimateResult.schema.json +113 -0
- schemas_export/crca_core/IdentificationResult.schema.json +145 -0
- schemas_export/crca_core/InterventionDesignResult.schema.json +111 -0
- schemas_export/crca_core/LockedSpec.schema.json +646 -0
- schemas_export/crca_core/RefusalResult.schema.json +90 -0
- schemas_export/crca_core/ValidationReport.schema.json +62 -0
- scripts/build_lrm_dataset.py +80 -0
- scripts/export_crca_core_schemas.py +54 -0
- scripts/export_hf_lrm.py +37 -0
- scripts/export_ollama_gguf.py +45 -0
- scripts/generate_changelog.py +157 -0
- scripts/generate_crca_core_docs_from_schemas.py +86 -0
- scripts/run_crca_core_benchmarks.py +163 -0
- scripts/run_full_finetune.py +198 -0
- scripts/run_lrm_eval.py +31 -0
- templates/graph_management.py +29 -0
- tests/conftest.py +9 -0
- tests/test_core.py +2 -3
- tests/test_crca_core_discovery_tabular.py +15 -0
- tests/test_crca_core_estimate_dowhy.py +36 -0
- tests/test_crca_core_identify.py +18 -0
- tests/test_crca_core_intervention_design.py +36 -0
- tests/test_crca_core_linear_gaussian_scm.py +69 -0
- tests/test_crca_core_spec.py +25 -0
- tests/test_crca_core_timeseries_pcmci.py +15 -0
- tests/test_crca_llm_coauthor.py +12 -0
- tests/test_crca_llm_orchestrator.py +80 -0
- tests/test_hybrid_agent_llm_enhanced.py +556 -0
- tests/test_image_annotation_demo.py +376 -0
- tests/test_image_annotation_operational.py +408 -0
- tests/test_image_annotation_unit.py +551 -0
- tests/test_training_moe.py +13 -0
- training/__init__.py +42 -0
- training/datasets.py +140 -0
- training/deepspeed_zero2_0_5b.json +22 -0
- training/deepspeed_zero2_1_5b.json +22 -0
- training/deepspeed_zero3_0_5b.json +28 -0
- training/deepspeed_zero3_14b.json +28 -0
- training/deepspeed_zero3_h100_3gpu.json +20 -0
- training/deepspeed_zero3_offload.json +28 -0
- training/eval.py +92 -0
- training/finetune.py +516 -0
- training/public_datasets.py +89 -0
- training_data/react_train.jsonl +7473 -0
- utils/agent_discovery.py +311 -0
- utils/batch_processor.py +317 -0
- utils/conversation.py +78 -0
- utils/edit_distance.py +118 -0
- utils/formatter.py +33 -0
- utils/graph_reasoner.py +530 -0
- utils/rate_limiter.py +283 -0
- utils/router.py +2 -2
- utils/tool_discovery.py +307 -0
- webui/__init__.py +10 -0
- webui/app.py +229 -0
- webui/config.py +104 -0
- webui/static/css/style.css +332 -0
- webui/static/js/main.js +284 -0
- webui/templates/index.html +42 -0
- tests/test_crca_excel.py +0 -166
- tests/test_data_broker.py +0 -424
- tests/test_palantir.py +0 -349
- {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/WHEEL +0 -0
- {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
|
|
File without changes
|