File size: 4,244 Bytes
8c486a8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
"""Tests for agent protocols and dynamic component resolution."""

import pytest

from open_range.protocols import (
    BuildContext,
    SnapshotBuilder,
    NPCBehavior,
    ValidatorCheck,
    SnapshotSpec,
    NPCPersona,
    Stimulus,
    NPCAction,
    CheckResult,
    ContainerSet,
)
from open_range.resolve import resolve_component


class TestProtocolCompliance:
    """Builder implementations satisfy the SnapshotBuilder protocol."""

    def test_template_only_builder_satisfies_protocol(self):
        from open_range.builder.builder import TemplateOnlyBuilder

        b = TemplateOnlyBuilder()
        assert isinstance(b, SnapshotBuilder)

    def test_file_builder_satisfies_protocol(self):
        from open_range.builder.builder import FileBuilder

        b = FileBuilder()
        assert isinstance(b, SnapshotBuilder)

    def test_llm_snapshot_builder_satisfies_protocol(self):
        from open_range.builder.builder import LLMSnapshotBuilder

        b = LLMSnapshotBuilder()
        assert isinstance(b, SnapshotBuilder)


class TestValidatorCheckProtocol:
    """Validator check classes satisfy ValidatorCheck protocol."""

    def test_build_boot_check(self):
        from open_range.validator.build_boot import BuildBootCheck

        assert isinstance(BuildBootCheck(), ValidatorCheck)

    def test_exploitability_check(self):
        from open_range.validator.exploitability import ExploitabilityCheck

        assert isinstance(ExploitabilityCheck(), ValidatorCheck)

    def test_difficulty_check(self):
        from open_range.validator.difficulty import DifficultyCheck

        assert isinstance(DifficultyCheck(), ValidatorCheck)

    def test_isolation_check(self):
        from open_range.validator.isolation import IsolationCheck

        assert isinstance(IsolationCheck(), ValidatorCheck)

    def test_evidence_check(self):
        from open_range.validator.evidence import EvidenceCheck

        assert isinstance(EvidenceCheck(), ValidatorCheck)

    def test_npc_consistency_check(self):
        from open_range.validator.npc_consistency import NPCConsistencyCheck

        assert isinstance(NPCConsistencyCheck(), ValidatorCheck)


class TestResolveComponent:
    """resolve_component imports and protocol-checks correctly."""

    def test_resolve_valid_builder(self):
        instance = resolve_component(
            "open_range.builder.builder.TemplateOnlyBuilder",
            {},
            SnapshotBuilder,
        )
        assert isinstance(instance, SnapshotBuilder)

    def test_resolve_valid_validator_check(self):
        instance = resolve_component(
            "open_range.validator.build_boot.BuildBootCheck",
            {},
            ValidatorCheck,
        )
        assert isinstance(instance, ValidatorCheck)

    def test_resolve_nonexistent_module_raises(self):
        with pytest.raises(ModuleNotFoundError):
            resolve_component(
                "nonexistent.module.FakeClass",
                {},
                SnapshotBuilder,
            )

    def test_resolve_nonexistent_class_raises(self):
        with pytest.raises(AttributeError):
            resolve_component(
                "open_range.builder.builder.DoesNotExist",
                {},
                SnapshotBuilder,
            )

    def test_resolve_non_compliant_class_raises(self):
        """A class that doesn't satisfy the protocol raises TypeError."""
        with pytest.raises(TypeError, match="does not satisfy"):
            resolve_component(
                "open_range.server.models.RangeAction",
                {"command": "x", "mode": "red"},
                SnapshotBuilder,
            )


class TestBuildContext:
    """BuildContext model basics."""

    def test_defaults(self):
        ctx = BuildContext()
        assert ctx.tier == 1
        assert ctx.seed is None
        assert ctx.previous_vuln_classes == []
        assert ctx.red_solve_rate == 0.0

    def test_with_values(self):
        ctx = BuildContext(
            seed=42,
            tier=3,
            previous_vuln_classes=["sqli", "xss"],
            weak_areas=["ssrf"],
        )
        assert ctx.seed == 42
        assert ctx.tier == 3
        assert "sqli" in ctx.previous_vuln_classes