Files
2026-07-13 13:12:33 +08:00

233 lines
6.5 KiB
Python

from __future__ import annotations
import pytest
from opensquilla.sandbox.domain_validation import (
DomainDecision,
domain_matches,
normalize_domain,
validate_domain_pattern,
)
from opensquilla.sandbox.package_bundles import (
DEFAULT_PACKAGE_BUNDLE_IDS,
PACKAGE_BUNDLES,
expand_package_bundle,
)
@pytest.mark.parametrize(
("raw", "expected"),
[
("HTTPS://PyPI.org/simple", "pypi.org"),
("registry.npmjs.org/", "registry.npmjs.org"),
("*.PythonHosted.org", "*.pythonhosted.org"),
(".example.com", ".example.com"),
("..Example.com..", "..example.com.."),
("http://[v6.invalid]", ""),
],
)
def test_normalize_domain(raw: str, expected: str) -> None:
assert normalize_domain(raw) == expected
@pytest.mark.parametrize(
"raw",
[
"127.0.0.1",
"127.1",
"0177.0.0.1",
"0x7f.0.0.1",
"0x7f.1",
"10.0.0.2",
"169.254.169.254",
"8.8.8.8",
"[::1]",
"2606:4700:4700::1111",
"*.com",
"*.co.uk",
"*.github.io",
"*.pages.dev",
"*.appspot.com",
"*.cloudfront.net",
"*.azurewebsites.net",
"*.example.com",
"*",
"",
],
)
def test_validate_domain_pattern_blocks_unsafe_patterns(raw: str) -> None:
decision = validate_domain_pattern(raw)
assert decision.status == "blocked"
def test_validate_domain_pattern_allows_exact_and_narrow_wildcard() -> None:
assert validate_domain_pattern("pypi.org") == DomainDecision(
status="allowed",
normalized="pypi.org",
reason="exact_domain",
)
assert validate_domain_pattern("3m.com") == DomainDecision(
status="allowed",
normalized="3m.com",
reason="exact_domain",
)
assert validate_domain_pattern("example.com") == DomainDecision(
status="allowed",
normalized="example.com",
reason="exact_domain",
)
assert validate_domain_pattern("example.com:443") == DomainDecision(
status="allowed",
normalized="example.com",
reason="exact_domain",
)
assert validate_domain_pattern("*.pythonhosted.org") == DomainDecision(
status="allowed",
normalized="*.pythonhosted.org",
reason="wildcard_domain",
)
def test_package_bundles_expand_to_known_domains() -> None:
assert expand_package_bundle("python-package-install") == (
"pypi.org",
"files.pythonhosted.org",
"pypi.python.org",
"bootstrap.pypa.io",
"python-poetry.org",
"install.python-poetry.org",
)
assert expand_package_bundle("node-package-install") == (
"registry.npmjs.org",
"registry.yarnpkg.com",
"yarnpkg.com",
"nodejs.org",
"unpkg.com",
"cdn.jsdelivr.net",
)
assert expand_package_bundle("rust-package-install") == (
"crates.io",
"static.crates.io",
"index.crates.io",
"github.com",
"objects.githubusercontent.com",
)
assert expand_package_bundle("go-package-install") == (
"proxy.golang.org",
"sum.golang.org",
"go.dev",
"golang.org",
"storage.googleapis.com",
)
assert expand_package_bundle("java-package-install") == (
"repo.maven.apache.org",
"repo1.maven.org",
"plugins.gradle.org",
"services.gradle.org",
)
assert expand_package_bundle("php-package-install") == (
"packagist.org",
"repo.packagist.org",
"getcomposer.org",
)
assert "rust-package-install" in PACKAGE_BUNDLES
assert DEFAULT_PACKAGE_BUNDLE_IDS == tuple(PACKAGE_BUNDLES)
assert expand_package_bundle("unknown") == ()
@pytest.mark.parametrize(
"raw",
[
".example.com",
"..example.com..",
"example..com",
"-example.com",
"example.com-",
"exa_mple.com",
"*.*.example.com",
"foo.*.example.com",
"*.",
"example.com:abc",
"example.com:123",
],
)
def test_validate_domain_pattern_blocks_malformed_hostnames(raw: str) -> None:
decision = validate_domain_pattern(raw)
assert decision.status == "blocked"
@pytest.mark.parametrize(
"raw",
[
"https://[::1]foo",
"http://[]",
"http://[v6.invalid]",
],
)
def test_validate_domain_pattern_blocks_malformed_bracketed_url_hosts(raw: str) -> None:
try:
decision = validate_domain_pattern(raw)
except ValueError as exc:
pytest.fail(f"validate_domain_pattern raised {exc!r}")
assert decision.status == "blocked"
def test_validate_domain_pattern_blocks_huge_port_without_raising() -> None:
raw = "example.com:" + ("9" * 5000)
try:
decision = validate_domain_pattern(raw)
except ValueError as exc:
pytest.fail(f"validate_domain_pattern raised {exc!r}")
assert decision.status == "blocked"
def test_domain_matches_exact_domain() -> None:
assert domain_matches("pypi.org", "pypi.org")
assert not domain_matches("pypi.org", "files.pythonhosted.org")
assert domain_matches("example.com", "example.com:443")
def test_domain_matches_wildcard_subdomain_and_excludes_apex() -> None:
assert domain_matches("*.pythonhosted.org", "files.pythonhosted.org")
assert not domain_matches("*.pythonhosted.org", "pythonhosted.org")
def test_domain_matches_requires_label_boundary() -> None:
assert not domain_matches("*.pythonhosted.org", "notpythonhosted.org")
def test_domain_matches_returns_false_for_invalid_pattern() -> None:
assert not domain_matches("*.github.io", "project.github.io")
assert not domain_matches("*.example.com", "api.example.com")
assert not domain_matches("foo.*.example.com", "foo.api.example.com")
@pytest.mark.parametrize(
"host",
[
".pypi.org",
"pypi..org",
"pypi.org:abc",
"exa_mple.com",
"8.8.8.8",
"https://[::1]foo",
"http://[v6.invalid]",
"example.com:123",
],
)
def test_domain_matches_returns_false_for_invalid_host(host: str) -> None:
try:
matched = domain_matches("pypi.org", host)
except ValueError as exc:
pytest.fail(f"domain_matches raised {exc!r}")
assert not matched
def test_domain_matches_returns_false_for_huge_port_without_raising() -> None:
host = "example.com:" + ("9" * 5000)
try:
matched = domain_matches("example.com", host)
except ValueError as exc:
pytest.fail(f"domain_matches raised {exc!r}")
assert not matched