1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"""Local account → browser-issued HTTP key → git push to an empty project."""
from __future__ import annotations
import json
import os
import subprocess
from pathlib import Path
import pytest
from integration.harness import running_server
sync_api = pytest.importorskip("playwright.sync_api")
_USERNAME = "alice"
_PASSWORD = "secretsecret"
_KEY_ID = "laptop"
_PROJECT = "emptyproj"
def _write_local_auth_config(path: Path) -> None:
path.write_text(
json.dumps(
{
"salt": "0123456789abcdef",
"auth_mode": "local",
"oauth_permissions": {
"*": [],
"pgw.read.*": ["*"],
"pgw.write.*": ["*"],
},
"local_users": [
{
"user": _USERNAME,
"pass": _PASSWORD,
"email": "alice@example.com",
}
],
},
indent=2,
)
+ "\n",
encoding="utf-8",
)
if os.name != "nt":
path.chmod(0o600)
def _run_git(repo_dir: Path, *args: str, git_config: tuple[str, ...] = ()) -> str:
completed = subprocess.run(
["git", *git_config, *args],
cwd=repo_dir,
capture_output=True,
text=True,
check=True,
env={**os.environ, "GIT_TERMINAL_PROMPT": "0"},
)
return completed.stdout.strip()
def _key_git_config(username: str, secret: str) -> tuple[str, ...]:
helper = f"!f() {{ echo username={username}; echo password={secret}; }}; f"
return ("-c", "credential.helper=", "-c", f"credential.helper={helper}")
def _issue_key_via_browser(base: str) -> str:
with sync_api.sync_playwright() as playwright:
browser = playwright.chromium.launch(headless=True)
try:
page = browser.new_page()
page.goto(f"{base}login?next=/user", wait_until="domcontentloaded")
page.fill("#login_username", _USERNAME)
page.fill("#login_password", _PASSWORD)
page.get_by_role("button", name="Sign in").click()
page.wait_for_url("**/user")
sync_api.expect(page.get_by_role("heading", name="Account")).to_be_visible()
page.fill("#api-key-id", _KEY_ID)
page.get_by_role("button", name="Create key").click()
page.locator("#api-key-secret-panel").wait_for(state="visible")
secret = page.locator("#api-key-secret").input_value()
assert secret, "expected a plaintext API key after Create key"
return secret
finally:
browser.close()
@pytest.mark.playwright
def test_local_account_issues_key_and_pushes(tmp_path: Path) -> None:
projects = tmp_path / "projects"
projects.mkdir()
bare = projects / _PROJECT
subprocess.run(["git", "init", "--bare", "-b", "main", str(bare)], check=True, capture_output=True)
auth_path = tmp_path / "auth.json"
_write_local_auth_config(auth_path)
with running_server(
tmp_path=tmp_path,
projects=projects,
auth=True,
auth_config_file=auth_path,
) as base:
secret = _issue_key_via_browser(base)
work = tmp_path / "work"
work.mkdir()
_run_git(work, "init", "-b", "main")
_run_git(work, "config", "user.name", "tester")
_run_git(work, "config", "user.email", "tester@example.com")
(work / "README.md").write_text("from key\n", encoding="utf-8")
_run_git(work, "add", "README.md")
_run_git(work, "commit", "-m", "initial via http key")
remote = f"{base}http/{_PROJECT}.git"
_run_git(work, "remote", "add", "origin", remote)
git_config = _key_git_config(_USERNAME, secret)
_run_git(work, "push", "-u", "origin", "main", git_config=git_config)
head = _run_git(bare, "rev-parse", "refs/heads/main")
assert head
subject = _run_git(bare, "log", "-1", "--format=%s", "refs/heads/main")
assert subject == "initial via http key"