From fc1d37f46c2c2dfe9663a468393ac6d34d62f1f0 Mon Sep 17 00:00:00 2001 From: Henrik Holmboe Date: Sun, 11 Jan 2026 17:40:33 +0100 Subject: [PATCH 1/2] Fix PHAB_URL validation to support port numbers The URL validation regex now accepts URLs with optional port numbers (e.g., http://phabricator.domain.tld:81/api/). Previously these URLs were rejected as malformed. Fixes #53 Co-Authored-By: Claude Opus 4.5 --- phabfive/constants.py | 2 +- tests/test_constants.py | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/phabfive/constants.py b/phabfive/constants.py index b5f76f5..c37cd0b 100644 --- a/phabfive/constants.py +++ b/phabfive/constants.py @@ -15,7 +15,7 @@ DEFAULTS = {"PHABFIVE_DEBUG": False, "PHAB_TOKEN": "", "PHAB_URL": ""} REQUIRED = ["PHAB_TOKEN", "PHAB_URL"] VALIDATORS = { - "PHAB_URL": "^http(s)?://[a-zA-Z0-9._-]+/api(/)?$", + "PHAB_URL": "^http(s)?://[a-zA-Z0-9._-]+(:[0-9]+)?/api(/)?$", "PHAB_TOKEN": "^[a-zA-Z0-9-]{32}$", } VALID_EXAMPLES = {"PHAB_URL": "example: http://127.0.0.1/api/"} diff --git a/tests/test_constants.py b/tests/test_constants.py index b436efd..b95b581 100644 --- a/tests/test_constants.py +++ b/tests/test_constants.py @@ -1,8 +1,47 @@ # -*- coding: utf-8 -*- +import re + def test_status_choices(): from phabfive.constants import REPO_STATUS_CHOICES assert "active" in REPO_STATUS_CHOICES assert "inactive" in REPO_STATUS_CHOICES + + +def test_phab_url_validator_without_port(): + from phabfive.constants import VALIDATORS + + pattern = VALIDATORS["PHAB_URL"] + + # Valid URLs without port + assert re.match(pattern, "http://127.0.0.1/api/") + assert re.match(pattern, "http://127.0.0.1/api") + assert re.match(pattern, "https://phabricator.example.com/api/") + assert re.match(pattern, "http://my-phab.domain.tld/api/") + + +def test_phab_url_validator_with_port(): + from phabfive.constants import VALIDATORS + + pattern = VALIDATORS["PHAB_URL"] + + # Valid URLs with port (issue #53) + assert re.match(pattern, "http://phabricator.domain.tld:81/api/") + assert re.match(pattern, "https://localhost:8080/api/") + assert re.match(pattern, "http://127.0.0.1:3000/api") + assert re.match(pattern, "http://dev.example.com:443/api/") + + +def test_phab_url_validator_invalid(): + from phabfive.constants import VALIDATORS + + pattern = VALIDATORS["PHAB_URL"] + + # Invalid URLs + assert not re.match(pattern, "ftp://example.com/api/") + assert not re.match(pattern, "http://example.com/") + assert not re.match(pattern, "http://example.com") + assert not re.match(pattern, "http://:80/api/") + assert not re.match(pattern, "example.com/api/") From 6fc03e9e3f7e4deeae018cf0ea21c54522636447 Mon Sep 17 00:00:00 2001 From: Henrik Holmboe Date: Sun, 11 Jan 2026 17:43:08 +0100 Subject: [PATCH 2/2] Add IPv6 address support to PHAB_URL validation The URL validation regex now accepts IPv6 addresses enclosed in brackets (e.g., http://[::1]/api/ or http://[2001:db8::1]:8080/api/). Co-Authored-By: Claude Opus 4.5 --- phabfive/constants.py | 2 +- tests/test_constants.py | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/phabfive/constants.py b/phabfive/constants.py index c37cd0b..733305a 100644 --- a/phabfive/constants.py +++ b/phabfive/constants.py @@ -15,7 +15,7 @@ DEFAULTS = {"PHABFIVE_DEBUG": False, "PHAB_TOKEN": "", "PHAB_URL": ""} REQUIRED = ["PHAB_TOKEN", "PHAB_URL"] VALIDATORS = { - "PHAB_URL": "^http(s)?://[a-zA-Z0-9._-]+(:[0-9]+)?/api(/)?$", + "PHAB_URL": r"^http(s)?://([a-zA-Z0-9._-]+|\[[a-fA-F0-9:\.]+\])(:[0-9]+)?/api(/)?$", "PHAB_TOKEN": "^[a-zA-Z0-9-]{32}$", } VALID_EXAMPLES = {"PHAB_URL": "example: http://127.0.0.1/api/"} diff --git a/tests/test_constants.py b/tests/test_constants.py index b95b581..16b93d3 100644 --- a/tests/test_constants.py +++ b/tests/test_constants.py @@ -34,6 +34,30 @@ def test_phab_url_validator_with_port(): assert re.match(pattern, "http://dev.example.com:443/api/") +def test_phab_url_validator_with_ipv6(): + from phabfive.constants import VALIDATORS + + pattern = VALIDATORS["PHAB_URL"] + + # Valid URLs with IPv6 addresses (must be in brackets) + assert re.match(pattern, "http://[::1]/api/") + assert re.match(pattern, "https://[::1]/api/") + assert re.match(pattern, "http://[2001:db8::1]/api/") + assert re.match(pattern, "http://[fe80::1]/api/") + assert re.match(pattern, "http://[::ffff:127.0.0.1]/api/") + + +def test_phab_url_validator_with_ipv6_and_port(): + from phabfive.constants import VALIDATORS + + pattern = VALIDATORS["PHAB_URL"] + + # Valid URLs with IPv6 addresses and port + assert re.match(pattern, "http://[::1]:8080/api/") + assert re.match(pattern, "https://[2001:db8::1]:443/api/") + assert re.match(pattern, "http://[fe80::1]:3000/api") + + def test_phab_url_validator_invalid(): from phabfive.constants import VALIDATORS @@ -45,3 +69,6 @@ def test_phab_url_validator_invalid(): assert not re.match(pattern, "http://example.com") assert not re.match(pattern, "http://:80/api/") assert not re.match(pattern, "example.com/api/") + # Invalid IPv6 (missing brackets) + assert not re.match(pattern, "http://::1/api/") + assert not re.match(pattern, "http://2001:db8::1/api/")