Files
wehub-resource-sync 3e779be6f3
CI / lint (push) Failing after 13m4s
CI / test (3.11, ubuntu-latest) (push) Failing after 2m4s
CI / test (3.13, ubuntu-latest) (push) Successful in 13m30s
CI / test (3.14, ubuntu-latest) (push) Successful in 17m21s
CI / test (3.12, ubuntu-latest) (push) Successful in 17m55s
CI / discover-apps-ps (push) Successful in 1m56s
CI / test (3.9, ubuntu-latest) (push) Successful in 13m17s
CI / test (3.10, ubuntu-latest) (push) Successful in 26m21s
CI / audit (push) Successful in 13m38s
Deploy site / deploy (push) Has been cancelled
CI / test (3.14, ubuntu-24.04-arm) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:32:37 +08:00

81 lines
2.8 KiB
Python

# SPDX-License-Identifier: MIT
"""Canonical URL-scheme policy (#421 / #694)."""
from __future__ import annotations
import pytest
from winpodx.core.url_schemes import (
DANGEROUS_SCHEMES,
is_safe_scheme,
sanitize_url_arg,
url_scheme_of,
)
@pytest.mark.parametrize(
"s", ["mailto", "https", "http", "slack", "vnc", "tel", "zoommtg", "webcal"]
)
def test_is_safe_scheme_accepts_common(s: str) -> None:
assert is_safe_scheme(s)
assert is_safe_scheme(s.upper()) # case-insensitive
assert is_safe_scheme(s + ":") # trailing colon tolerated
@pytest.mark.parametrize("s", sorted(DANGEROUS_SCHEMES))
def test_is_safe_scheme_rejects_denylist(s: str) -> None:
assert not is_safe_scheme(s)
@pytest.mark.parametrize(
"bad",
[
"",
"1abc",
"a b",
"has:colon",
"way-too-long-scheme-name-that-exceeds-the-thirty-two-char-cap",
],
)
def test_is_safe_scheme_rejects_malformed(bad: str) -> None:
assert not is_safe_scheme(bad)
def test_url_scheme_of_routes_urls_not_paths() -> None:
assert url_scheme_of("mailto:a@b.com") == "mailto"
assert url_scheme_of("https://example.com/x") == "https"
def test_never_auto_default_covers_web_schemes_only() -> None:
# http/https stay routable (is_safe_scheme True) but must be flagged so the
# host never auto-seizes their system default from a guest app; mailto and
# vendor schemes are intentionally NOT flagged (the #421 auto-route goal).
from winpodx.core.url_schemes import NEVER_AUTO_DEFAULT_SCHEMES
assert "http" in NEVER_AUTO_DEFAULT_SCHEMES
assert "https" in NEVER_AUTO_DEFAULT_SCHEMES
assert "mailto" not in NEVER_AUTO_DEFAULT_SCHEMES
assert "slack" not in NEVER_AUTO_DEFAULT_SCHEMES
# still routable -- this is a default-grab policy, not a routing denylist
assert is_safe_scheme("http") and is_safe_scheme("https")
assert url_scheme_of("SLACK://team") == "slack"
# file paths + file: URIs are NOT routed (file: is denylisted -> UNC path)
assert url_scheme_of("/home/me/doc.txt") is None
assert url_scheme_of("file:///home/me/doc.txt") is None
assert url_scheme_of("relative/path") is None
# dangerous schemes are not routed
assert url_scheme_of("javascript:alert(1)") is None
assert url_scheme_of("data:text/html,x") is None
def test_sanitize_neutralises_app_cmd_injection() -> None:
# comma splits FreeRDP3 /app: sub-keys; double-quote wraps the cmd value;
# CR/LF/control chars could smuggle extra argv.
out = sanitize_url_arg('slack://team,chan"x\r\n\tbell\x07')
assert "," not in out
assert '"' not in out
assert "\r" not in out and "\n" not in out and "\t" not in out
assert "\x07" not in out
# the rest of the URL survives
assert out.startswith("slack://team")