Files
cc-ci/tests/drone/custom/test_scm_configured.py
autonomic-bot 44e02425ab
Some checks failed
continuous-integration/drone/push Build is failing
feat(cfold): canonicalize custom test layout
2026-06-12 16:08:18 +00:00

104 lines
4.3 KiB
Python

"""drone — SCM-configured functional test (phase drone).
Proves that drone is wired to the per-run gitea dep, not just healthy.
The negative control: a drone deployed WITHOUT DRONE_GITEA_CLIENT_ID + DRONE_GITEA_SERVER
(i.e., without compose.gitea.yml) would NOT redirect /login to the gitea dep's OAuth
authorize endpoint — it would error or redirect elsewhere. This test is therefore falsified
by a misconfigured drone.
Test: GET https://<drone>/login must issue a 303 redirect whose Location header points to
the per-run gitea dep's /login/oauth/authorize URL. We capture ONLY drone's first redirect
(not gitea's subsequent redirect to /user/login for unauthenticated users).
Per ADV-drone-01: following all redirects causes the assertion to land on gitea's /user/login
(200 OK after gitea redirects unauthenticated users away from /login/oauth/authorize), which
means the path assertion always fails. The fix is a no-follow handler that captures the
Location header from drone's 303 directly.
"""
from __future__ import annotations
import ssl
import urllib.error
import urllib.parse
import urllib.request
import pytest
class _CaptureOneRedirect(urllib.request.HTTPRedirectHandler):
"""Stop redirect-following after the FIRST hop; raise HTTPError so the caller can inspect
the Location header from drone's 303 without following gitea's subsequent redirects."""
def http_error_302(self, req, fp, code, msg, headers):
raise urllib.error.HTTPError(req.full_url, code, msg, headers, fp)
http_error_303 = http_error_302
@pytest.mark.requires_deps
def test_login_redirects_to_gitea_dep(live_app, deps):
"""Drone's /login must issue a 303 redirect to the per-run gitea dep's OAuth2 authorize
endpoint.
Proves: (a) gitea is the SCM backend (not github or unconfigured); (b) the OAuth2
client_id in the Location header matches the app the harness created in the dep gitea
instance; (c) the redirect targets the TEST-RUN gitea, not any hardcoded external provider.
ADV-drone-01 fix: only drone's first 303 is captured; gitea's own redirects (unauthenticated
user → /user/login) are not followed, so the path assertion is against the correct URL.
"""
assert "gitea" in deps, (
f"gitea dep not in deps — dep provisioning should have populated this. "
f"Got keys: {list(deps.keys())}"
)
gitea = deps["gitea"]
gitea_domain: str = gitea["domain"]
expected_client_id: str = gitea["client_id"]
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
opener = urllib.request.build_opener(
_CaptureOneRedirect(),
urllib.request.HTTPSHandler(context=ctx),
)
redirect_url = None
try:
opener.open(f"https://{live_app}/login", timeout=30)
pytest.fail(
f"Expected a 302/303 redirect from https://{live_app}/login but got 200 OK — "
f"drone may not have gitea SCM configured (check COMPOSE_FILE + GITEA_DOMAIN)"
)
except urllib.error.HTTPError as e:
if e.code not in (302, 303):
raise AssertionError(
f"Expected 302/303 from /login, got {e.code}"
f"drone may not have gitea SCM configured"
) from e
redirect_url = e.headers.get("Location") or e.headers.get("location", "")
assert redirect_url, (
"Drone /login returned a redirect but Location header is empty — "
"check drone gitea SCM configuration"
)
parsed = urllib.parse.urlparse(redirect_url)
assert parsed.scheme == "https", f"Redirect Location has unexpected scheme: {redirect_url!r}"
assert parsed.netloc == gitea_domain, (
f"Drone /login did not redirect to the gitea dep ({gitea_domain!r}); "
f"Location: {redirect_url!r} — check GITEA_DOMAIN + COMPOSE_FILE in drone's .env"
)
assert parsed.path == "/login/oauth/authorize", (
f"Redirect path is {parsed.path!r}, expected /login/oauth/authorize — "
f"drone may not have gitea SCM configured"
)
params = urllib.parse.parse_qs(parsed.query)
actual_client_id = params.get("client_id", [None])[0]
assert actual_client_id == expected_client_id, (
f"OAuth2 client_id mismatch: drone is using {actual_client_id!r} but the harness "
f"created app {expected_client_id!r} in the dep gitea — check install_steps.sh"
)