58 lines
1.5 KiB
Python
58 lines
1.5 KiB
Python
"""Scope gating: in-scope kept, out-of-scope dropped, exclusions honoured."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from recon_triage.scope import Scope
|
|
|
|
FIXTURES = Path(__file__).parent / "fixtures"
|
|
|
|
|
|
def _scope() -> Scope:
|
|
return Scope.load(FIXTURES / "scope.yaml")
|
|
|
|
|
|
def test_in_scope_domain_and_subdomains():
|
|
sc = _scope()
|
|
assert sc.is_in_scope("example.com")
|
|
assert sc.is_in_scope("api.example.com")
|
|
assert sc.is_in_scope("deep.api.example.com")
|
|
|
|
|
|
def test_out_of_scope_domain_dropped():
|
|
sc = _scope()
|
|
assert not sc.is_in_scope("external.notmine.com")
|
|
assert not sc.is_in_scope("notexample.com")
|
|
|
|
|
|
def test_exclusion_precedence():
|
|
sc = _scope()
|
|
# internal-only.example.com is under example.com but explicitly excluded.
|
|
assert not sc.is_in_scope("internal-only.example.com")
|
|
|
|
|
|
def test_cidr_matching():
|
|
sc = _scope()
|
|
assert sc.is_in_scope("93.184.216.34")
|
|
assert not sc.is_in_scope("198.51.100.7")
|
|
|
|
|
|
def test_filter_drops_out_of_scope():
|
|
sc = _scope()
|
|
given = ["api.example.com", "external.notmine.com", "93.184.216.34", "8.8.8.8"]
|
|
kept = sc.filter(given)
|
|
assert kept == ["api.example.com", "93.184.216.34"]
|
|
|
|
|
|
def test_substring_domain_not_matched():
|
|
# "fakeexample.com" must not match "example.com"
|
|
sc = _scope()
|
|
assert not sc.is_in_scope("fakeexample.com")
|
|
|
|
|
|
def test_invalid_cidr_ignored():
|
|
sc = Scope.from_dict({"in_scope_cidrs": ["not-a-cidr", "10.0.0.0/8"]})
|
|
assert sc.cidrs == ["10.0.0.0/8"]
|
|
assert sc.is_in_scope("10.1.2.3")
|