mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-11-02 03:33:04 +08:00
Drop Python 3.8 support in 5 Pulsar-compatible packages (job_metrics, tool_util, tool_util_models, util, objectstore) and run pyupgrade --py310-plus on their source code. - Bump requires-python from >=3.8 to >=3.10 in all 5 packages - Remove Python 3.8 and 3.9 classifiers - Remove ruff per-file-ignores for UP rules on these paths - Remove backports.zoneinfo conditional dependency - Remove pydyf<0.11 pin from conditional-requirements.txt - Update Makefile pyupgrade target (remove PY38_PYUPGRADE_PATHS) - Update CI workflow to test with Python 3.10 instead of 3.8 Clean up unused deprecated typing imports after pyupgrade Remove now-unused typing imports (Dict, List, Optional, Set, Tuple, Type, Union) that became dead after pyupgrade --py310-plus converted annotations to use built-in types and | syntax. Also run ruff check --fix --select=UP007,UP045 across the entire codebase to convert remaining Optional[X] -> X | None and Union[X, Y] -> X | Y patterns. Enable ruff UP007/UP045 for Python 3.10 union syntax Remove UP007 (Union[X,Y] -> X | Y) and UP045 (Optional[X] -> X | None) from the ruff ignore list and convert all type aliases across the codebase. These rules were deferred while Python 3.9 was supported; requires-python is now >=3.10. A custom script was used because neither ruff --fix nor pyupgrade --py310-plus converts Optional[X]/Union[X,Y] in type alias positions (e.g. X = Union[A, B]) — they only handle annotation positions (e.g. def f(x: Optional[int])). All 167 violations were module-level type aliases. A few edge cases were fixed manually: single-element Union[X,], typing.Union qualified refs, runtime Optional[type] calls, and Annotated[Optional[...]] pydantic fields. Fix UP007 autofix regression with string forward reference type aliases Commit fa6bd955a0 enabled ruff UP007/UP045 and auto-fixed module-level type aliases using Union with string forward references, producing invalid 'str | str' expressions. This was a known ruff bug (charliermarsh/ruff#826) that has since been fixed in later ruff versions, but this codebase was converted before the fix was in place. Revert to Union syntax and restore TYPE_CHECKING imports that ruff's TCH rule cleaned up as a side effect when it thought the forward references were unused.
115 lines
5.1 KiB
Python
115 lines
5.1 KiB
Python
import pytest
|
|
|
|
from galaxy import config
|
|
from galaxy.security import validate_user_input
|
|
from galaxy.security.validate_user_input import (
|
|
extract_domain,
|
|
is_email_banned,
|
|
validate_email_domain_name,
|
|
validate_email_str,
|
|
validate_publicname_str,
|
|
)
|
|
|
|
|
|
@pytest.fixture()
|
|
def appconfig():
|
|
return config.GalaxyAppConfiguration(override_tempdir=False)
|
|
|
|
|
|
def test_extract_full_domain():
|
|
assert extract_domain("jack@foo.com") == "foo.com"
|
|
assert extract_domain("jack@foo.bar.com") == "foo.bar.com"
|
|
assert extract_domain("foo.bar.com") == "foo.bar.com"
|
|
assert extract_domain('"i-like-to-break-email-valid@tors"@foo.com') == "foo.com"
|
|
|
|
|
|
def test_extract_base_domain():
|
|
# Use case: ignore subdomains to filter out disposable email addresses
|
|
assert extract_domain("jack@foo.com", base_only=True) == "foo.com"
|
|
assert extract_domain("jack@foo.bar.com", base_only=True) == "bar.com"
|
|
|
|
|
|
def test_validate_email_domain_name():
|
|
assert validate_email_domain_name("example.org") == ""
|
|
assert validate_email_domain_name("this is an invalid domain!") != ""
|
|
|
|
|
|
def test_validate_username():
|
|
assert validate_publicname_str("testuser") == ""
|
|
assert validate_publicname_str("test.user") == ""
|
|
assert validate_publicname_str("test-user") == ""
|
|
assert validate_publicname_str("test@user") != ""
|
|
assert validate_publicname_str("test user") != ""
|
|
|
|
|
|
def test_validate_email_str():
|
|
assert validate_email_str("test@foo.com") == ""
|
|
assert validate_email_str("test-dot.user@foo.com") == ""
|
|
assert validate_email_str("test-plus+user@foo.com") == ""
|
|
assert validate_email_str("test-ünicode-user@foo.com") == ""
|
|
assert validate_email_str("test@ünicode-domain.com") == ""
|
|
assert validate_email_str("test-missing-domain@") != ""
|
|
assert validate_email_str("@test-missing-local") != ""
|
|
assert validate_email_str("test-invalid-local\\character@foo.com") != ""
|
|
assert validate_email_str("test@invalid-domain-character!com") != ""
|
|
assert validate_email_str("test@newlines.in.address.are.invalid\n\n.com") != ""
|
|
assert validate_email_str('"i-like-to-break-email-valid@tors"@foo.com') != ""
|
|
too_long_email = "N" * 255 + "@foo.com"
|
|
assert validate_email_str(too_long_email) != ""
|
|
|
|
|
|
class TestIsEmailBanned:
|
|
mock_ban_list = ["ab@foo.com", "ab@gmail.com", "Not.Canonical+email+gmail+address@gmail.com"]
|
|
|
|
def test_default_canonical_rules(self, monkeypatch, appconfig):
|
|
"""Rules loaded from schema."""
|
|
monkeypatch.setattr(validate_user_input, "_read_email_ban_list", lambda a: self.mock_ban_list)
|
|
|
|
rules = appconfig.canonical_email_rules
|
|
assert is_email_banned("ab@foo.com", "_", rules)
|
|
assert not is_email_banned("Ab@foo.com", "_", rules)
|
|
assert not is_email_banned("a.b@foo.com", "_", rules)
|
|
assert not is_email_banned("ab+bar@foo.com", "_", rules)
|
|
assert not is_email_banned("something-else@foo.com", "_", rules)
|
|
|
|
# default rules for gmail are applied:
|
|
assert is_email_banned("ab@googlemail.com", "_", rules)
|
|
assert is_email_banned("Ab@gmail.com", "_", rules)
|
|
assert is_email_banned("a.b@gmail.com", "_", rules)
|
|
assert is_email_banned("ab+bar@gmail.com", "_", rules)
|
|
assert not is_email_banned("ab-bar@gmail.com", "_", rules) # different sub-addressing delimiter
|
|
|
|
def test_no_canonical_rules(self, monkeypatch):
|
|
"""No rules loaded."""
|
|
monkeypatch.setattr(validate_user_input, "_read_email_ban_list", lambda a: self.mock_ban_list)
|
|
|
|
rules = None
|
|
assert is_email_banned("ab@foo.com", "_", rules)
|
|
assert not is_email_banned("Ab@foo.com", "_", rules)
|
|
assert not is_email_banned("a.b@foo.com", "_", rules)
|
|
assert not is_email_banned("ab+bar@foo.com", "_", rules)
|
|
assert not is_email_banned("something-else@foo.com", "_", rules)
|
|
|
|
# default rules for gmail are NOT applied:
|
|
assert not is_email_banned("ab@googlemail.com", "_", rules)
|
|
assert not is_email_banned("Ab@gmail.com", "_", rules)
|
|
assert not is_email_banned("a.b@gmail.com", "_", rules)
|
|
assert not is_email_banned("ab+bar@gmail.com", "_", rules)
|
|
|
|
def test_custom_canonical_rules(self, monkeypatch):
|
|
"""No rules loaded."""
|
|
monkeypatch.setattr(validate_user_input, "_read_email_ban_list", lambda a: self.mock_ban_list)
|
|
|
|
rules = {"all": {"ignore_case": True}, "foo.com": {"ignore_dots": True}}
|
|
assert is_email_banned("ab@foo.com", "_", rules)
|
|
assert is_email_banned("Ab@foo.com", "_", rules) # ignore_case for all
|
|
assert is_email_banned("a.b@foo.com", "_", rules) # ignore_dots for foo.com
|
|
assert not is_email_banned("ab+bar@foo.com", "_", rules)
|
|
assert not is_email_banned("something-else@foo.com", "_", rules)
|
|
|
|
# default rules for gmail are NOT applied:
|
|
assert not is_email_banned("ab@googlemail.com", "_", rules)
|
|
assert is_email_banned("Ab@gmail.com", "_", rules) # ignore_case for all
|
|
assert not is_email_banned("a.b@gmail.com", "_", rules)
|
|
assert not is_email_banned("ab+bar@gmail.com", "_", rules)
|