128 lines
6.0 KiB
Python
128 lines
6.0 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from codexpi.commands import CommandResult
|
|
from codexpi.gitlab_service import (
|
|
GitLabError,
|
|
connect,
|
|
connect_repository,
|
|
create_repository,
|
|
namespaces,
|
|
normalize_server_url,
|
|
status,
|
|
)
|
|
|
|
|
|
def test_gitlab_server_url_requires_safe_explicit_transport():
|
|
assert normalize_server_url("https://gitlab.local/") == "https://gitlab.local"
|
|
assert normalize_server_url("http://gitlab.local", True) == "http://gitlab.local"
|
|
with pytest.raises(GitLabError, match="HTTP"):
|
|
normalize_server_url("http://gitlab.local")
|
|
for value in ("gitlab.local", "https://user:password@gitlab.local", "https://gitlab.local/?token=secret"):
|
|
with pytest.raises(GitLabError):
|
|
normalize_server_url(value)
|
|
|
|
|
|
def test_gitlab_connection_adds_ssh_key_and_encrypts_token(tmp_path: Path, monkeypatch):
|
|
calls: list[tuple[str, str, dict | None]] = []
|
|
|
|
def fake_request(_config, path, method="GET", payload=None):
|
|
calls.append((path, method, payload))
|
|
if path == "user":
|
|
return {"username": "alice", "name": "Alice"}
|
|
if path.startswith("user/keys?"):
|
|
return []
|
|
return {"id": 42}
|
|
|
|
monkeypatch.setattr("codexpi.gitlab_service._request", fake_request)
|
|
monkeypatch.setattr("codexpi.gitlab_service.generate_key", lambda _data: {"public_key": "ssh-ed25519 AAAATEST codexpi"})
|
|
value = connect(tmp_path, "application-secret", "https://gitlab.local", "glpat-top-secret")
|
|
encrypted = (tmp_path / "gitlab" / "connection.json").read_bytes()
|
|
assert value["configured"] is True
|
|
assert value["account"] == "alice"
|
|
assert "token" not in value
|
|
assert b"glpat-top-secret" not in encrypted
|
|
assert any(path == "user/keys" and method == "POST" for path, method, _ in calls)
|
|
|
|
|
|
def test_gitlab_does_not_add_an_existing_ssh_key(tmp_path: Path, monkeypatch):
|
|
calls: list[str] = []
|
|
|
|
def fake_request(_config, path, method="GET", payload=None):
|
|
calls.append(f"{method} {path}")
|
|
if path == "user":
|
|
return {"username": "alice"}
|
|
return [{"key": "ssh-ed25519 AAAATEST another-comment"}]
|
|
|
|
monkeypatch.setattr("codexpi.gitlab_service._request", fake_request)
|
|
monkeypatch.setattr("codexpi.gitlab_service.generate_key", lambda _data: {"public_key": "ssh-ed25519 AAAATEST codexpi"})
|
|
connect(tmp_path, "secret", "https://gitlab.local", "glpat-example")
|
|
assert "POST user/keys" not in calls
|
|
|
|
|
|
def test_gitlab_namespaces_and_repository_creation_use_saved_connection(tmp_path: Path, monkeypatch):
|
|
def connect_request(_config, path, method="GET", payload=None):
|
|
if path == "user":
|
|
return {"username": "alice"}
|
|
if path.startswith("user/keys?"):
|
|
return [{"key": "ssh-ed25519 AAAATEST"}]
|
|
raise AssertionError(path)
|
|
|
|
monkeypatch.setattr("codexpi.gitlab_service._request", connect_request)
|
|
monkeypatch.setattr("codexpi.gitlab_service.generate_key", lambda _data: {"public_key": "ssh-ed25519 AAAATEST"})
|
|
connect(tmp_path, "secret", "https://gitlab.local", "glpat-example")
|
|
|
|
def api_request(config, path, method="GET", payload=None):
|
|
assert config["token"] == "glpat-example"
|
|
if path.startswith("namespaces?"):
|
|
return [{"id": 7, "name": "Alice", "full_path": "alice", "kind": "user"}]
|
|
assert method == "POST" and payload["namespace_id"] == 7
|
|
return {"id": 9, "name": "Demo", "path_with_namespace": "alice/demo", "visibility": "private", "web_url": "https://gitlab.local/alice/demo", "ssh_url_to_repo": "git@gitlab.local:alice/demo.git"}
|
|
|
|
monkeypatch.setattr("codexpi.gitlab_service._request", api_request)
|
|
assert namespaces(tmp_path, "secret")[0]["full_path"] == "alice"
|
|
repository = create_repository(tmp_path, "secret", "Demo", "demo", 7, "private")
|
|
assert repository["ssh_url_to_repo"] == "git@gitlab.local:alice/demo.git"
|
|
|
|
|
|
def test_gitlab_repository_is_initialized_and_linked(tmp_path: Path, monkeypatch):
|
|
data = tmp_path / "data"
|
|
key = data / "github" / "id_ed25519"
|
|
key.parent.mkdir(parents=True)
|
|
key.write_text("private", encoding="utf-8")
|
|
root = tmp_path / "project"
|
|
root.mkdir()
|
|
|
|
async def fake_command(*_args, **_kwargs):
|
|
return CommandResult([], 0, "", "")
|
|
|
|
monkeypatch.setattr("codexpi.gitlab_service.run_command", fake_command)
|
|
value = asyncio.run(connect_repository(root, data, "git@gitlab.local:alice/demo.git"))
|
|
assert value["is_repository"] is True
|
|
assert value["remote_url"] == "git@gitlab.local:alice/demo.git"
|
|
|
|
|
|
def test_gitlab_api_connects_and_creates_repository(logged_in, monkeypatch):
|
|
client, _app, projects, _, headers = logged_in
|
|
root = projects / "gitlab-project"
|
|
root.mkdir()
|
|
project = client.post("/api/projects", headers=headers, json={"name": "GitLab", "path": str(root)}).json()
|
|
|
|
monkeypatch.setattr("codexpi.main.connect_gitlab", lambda *_args: {"configured": True, "server_url": "https://gitlab.local", "account": "alice", "name": "Alice", "verified_at": "now", "verify_tls": True})
|
|
monkeypatch.setattr("codexpi.main.create_gitlab_repository", lambda *_args: {"name": "Demo", "path_with_namespace": "alice/demo", "web_url": "https://gitlab.local/alice/demo", "ssh_url_to_repo": "git@gitlab.local:alice/demo.git"})
|
|
|
|
async def fake_link(*_args):
|
|
return {"is_repository": True, "remote_url": "git@gitlab.local:alice/demo.git"}
|
|
|
|
monkeypatch.setattr("codexpi.main.connect_gitlab_repository", fake_link)
|
|
assert client.post("/api/gitlab/connect", json={"server_url": "https://gitlab.local", "token": "secret"}).status_code == 403
|
|
connected = client.post("/api/gitlab/connect", headers=headers, json={"server_url": "https://gitlab.local", "token": "secret"})
|
|
assert connected.status_code == 200
|
|
created = client.post(f"/api/projects/{project['id']}/gitlab/repositories", headers=headers, json={"name": "Demo", "path": "demo", "namespace_id": 7, "visibility": "private"})
|
|
assert created.status_code == 201
|
|
assert created.json()["git"]["remote_url"] == "git@gitlab.local:alice/demo.git"
|