Files
ModelForge-Public/.gitea/tests/test_security_origin_policy.py
T

112 lines
3.9 KiB
Python

from __future__ import annotations
import os
import re
import shutil
import subprocess
import unittest
from pathlib import Path
from urllib.parse import urlsplit
ROOT = Path(__file__).resolve().parents[2]
WORKFLOW = ROOT / ".gitea" / "workflows" / "managed-validation.yml"
CANONICAL_ORIGIN = "https://git.example.com"
def _origin_case_script() -> str:
text = WORKFLOW.read_text(encoding="utf-8")
match = re.search(
r'(?ms)^ case "\$\{GITHUB_SERVER_URL%/\}" in\n'
r'.*?^ esac$',
text,
)
if match is None:
raise AssertionError("managed validation has no GITHUB_SERVER_URL case policy")
# Remove workflow indentation before executing only the bounded origin policy.
return "\n".join(line[10:] for line in match.group(0).splitlines())
def _evaluate_origin(origin: str) -> subprocess.CompletedProcess[str]:
script = (
"set -euo pipefail\n"
+ _origin_case_script()
+ "\nprintf '%s\\n' \"${SOURCE_SERVER_URL}\"\n"
)
env = os.environ.copy()
env["GITHUB_SERVER_URL"] = origin
bash = shutil.which("bash") or "bash"
if os.name == "nt":
# System32/bash.exe starts WSL, which does not inherit arbitrary Windows environment
# variables. Git Bash runs natively and tests the exact environment used by this fixture.
git = shutil.which("git")
git_bash = Path(git).resolve().parents[1] / "bin" / "bash.exe" if git else None
if git_bash is None or not git_bash.is_file():
raise RuntimeError("Git Bash is required for Windows origin policy tests")
bash = str(git_bash)
return subprocess.run(
[bash, "--noprofile", "--norc", "-c", script],
cwd=ROOT,
env=env,
check=False,
capture_output=True,
text=True,
)
def _safe_origin(value: str) -> str:
parsed = urlsplit(value)
hostname = parsed.hostname or "(missing-host)"
port = f":{parsed.port}" if parsed.port is not None else ""
return f"{parsed.scheme or '(missing-scheme)'}://{hostname}{port}"
class SecurityOriginPolicyTests(unittest.TestCase):
def test_known_runner_and_public_origins_canonicalize_to_https(self) -> None:
accepted = (
"https://git.example.com",
"https://git.example.com/",
"http://git.example.com",
"http://git.example.com/",
"http://192.0.2.10:3000",
"http://192.0.2.10:3000/",
"http://gitea:3000",
"http://gitea:3000/",
"http://Gitea:3000",
"http://Gitea:3000/",
"http://gitea-runner-internal:3000",
"http://gitea-runner-internal:3000/",
)
for origin in accepted:
with self.subTest(origin=origin):
result = _evaluate_origin(origin)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(result.stdout.strip(), CANONICAL_ORIGIN)
def test_unknown_http_and_https_origins_fail_closed(self) -> None:
for origin in (
"http://untrusted.invalid",
"https://untrusted.invalid",
"http://192.0.2.151:3000",
"http://gitea:3001",
):
with self.subTest(origin=origin):
result = _evaluate_origin(origin)
self.assertNotEqual(result.returncode, 0)
self.assertIn("Untrusted Gitea server URL", result.stderr)
def test_live_runner_origin_is_explicitly_covered_when_present(self) -> None:
origin = os.environ.get("GITHUB_SERVER_URL")
if not origin:
self.skipTest("GITHUB_SERVER_URL is only expected inside the managed runner")
result = _evaluate_origin(origin)
self.assertEqual(
result.returncode,
0,
f"managed runner origin is not covered: {_safe_origin(origin)}; {result.stderr.strip()}",
)
if __name__ == "__main__":
unittest.main()