Sanitized single-commit public mirror of recipe-maintainer. - Removed test-ssh/.testenv (live creds); added test-ssh/.testenv.example placeholders. - Removed plans/ and planned-updates/ (deployment-planning docs) so no client/ deployment domains appear in the public repo. - All other secret stores were already gitignored. - docs.coopcloud.tech retained as a submodule (public upstream).
162 lines
5.9 KiB
Python
162 lines
5.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Test creating a repo and pushing a commit via HTTPS on Gitea."""
|
|
import argparse
|
|
import base64
|
|
import json
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import time
|
|
import urllib.error
|
|
import urllib.request
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
|
from utils.tests.helpers import resolve_domain
|
|
|
|
|
|
WORKSPACE = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
|
|
|
|
|
def load_testsecrets(domain):
|
|
path = os.path.join(WORKSPACE, 'recipe-info', 'testsecrets', domain)
|
|
if not os.path.exists(path):
|
|
return {}
|
|
secrets = {}
|
|
with open(path) as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if '=' in line:
|
|
k, v = line.split('=', 1)
|
|
secrets[k.strip()] = v.strip()
|
|
return secrets
|
|
|
|
|
|
def api(method, url, data=None, token=None, username=None, password=None):
|
|
body = json.dumps(data).encode() if data is not None else None
|
|
req = urllib.request.Request(url, data=body, method=method)
|
|
req.add_header('Content-Type', 'application/json')
|
|
if token:
|
|
req.add_header('Authorization', f'token {token}')
|
|
elif username and password:
|
|
creds = base64.b64encode(f'{username}:{password}'.encode()).decode()
|
|
req.add_header('Authorization', f'Basic {creds}')
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=15) as resp:
|
|
raw = resp.read()
|
|
return resp.getcode(), json.loads(raw) if raw else {}
|
|
except urllib.error.HTTPError as e:
|
|
raw = e.read().decode(errors='replace')
|
|
try:
|
|
return e.code, json.loads(raw)
|
|
except Exception:
|
|
return e.code, {}
|
|
|
|
|
|
def run_git(args, cwd, env=None):
|
|
result = subprocess.run(
|
|
['git'] + args, cwd=cwd, capture_output=True, text=True,
|
|
env={**os.environ, **(env or {})},
|
|
timeout=30,
|
|
)
|
|
if result.returncode != 0:
|
|
raise RuntimeError(f"git {' '.join(args)} failed:\n{result.stderr}")
|
|
return result.stdout.strip()
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--domain', default=os.environ.get('TEST_DOMAIN'))
|
|
parser.add_argument('--username', default=os.environ.get('GITEA_ADMIN_USER'))
|
|
parser.add_argument('--password', default=os.environ.get('GITEA_ADMIN_PASS'))
|
|
args = parser.parse_args()
|
|
|
|
domain = args.domain or resolve_domain('gitea')
|
|
base_url = f'https://{domain}'
|
|
|
|
# Load credentials from testsecrets if not provided via args/env
|
|
username = args.username
|
|
password = args.password
|
|
if not username or not password:
|
|
secrets = load_testsecrets(domain)
|
|
username = username or secrets.get('admin_username')
|
|
password = password or secrets.get('admin_password')
|
|
|
|
if not username or not password:
|
|
print(f'FAIL: No credentials found. Pass --username/--password or add '
|
|
f'admin_username/admin_password to recipe-info/testsecrets/{domain}')
|
|
sys.exit(1)
|
|
|
|
repo_name = f'test-push-{int(time.time())}'
|
|
print(f'Testing git push on {base_url} as {username} ...')
|
|
|
|
# 1. Create a test repo via API
|
|
print(f' Creating repo {repo_name} ...')
|
|
status, body = api('POST', f'{base_url}/api/v1/user/repos',
|
|
data={'name': repo_name, 'private': False,
|
|
'auto_init': False},
|
|
username=username, password=password)
|
|
if status != 201:
|
|
print(f'FAIL: Could not create repo (HTTP {status}): {body}')
|
|
sys.exit(1)
|
|
clone_url = body.get('clone_url') or f'{base_url}/{username}/{repo_name}.git'
|
|
print(f' Repo created: {clone_url}')
|
|
|
|
tmpdir = tempfile.mkdtemp(prefix='gitea-test-')
|
|
try:
|
|
# 2. Clone (empty) and make a commit
|
|
git_env = {
|
|
'GIT_AUTHOR_NAME': 'Test Bot',
|
|
'GIT_AUTHOR_EMAIL': 'test@example.com',
|
|
'GIT_COMMITTER_NAME': 'Test Bot',
|
|
'GIT_COMMITTER_EMAIL': 'test@example.com',
|
|
# Embed credentials in the URL via a helper config
|
|
'GIT_CONFIG_COUNT': '1',
|
|
'GIT_CONFIG_KEY_0': f'url.https://{username}:{password}@{domain}/.insteadOf',
|
|
'GIT_CONFIG_VALUE_0': f'https://{domain}/',
|
|
}
|
|
|
|
print(' Cloning repo ...')
|
|
run_git(['clone', clone_url, tmpdir], cwd='/tmp', env=git_env)
|
|
|
|
# Write a test file
|
|
test_file = os.path.join(tmpdir, 'README.md')
|
|
with open(test_file, 'w') as f:
|
|
f.write(f'# {repo_name}\n\nAutomated test commit.\n')
|
|
|
|
run_git(['add', 'README.md'], cwd=tmpdir, env=git_env)
|
|
run_git(['commit', '-m', 'test: automated push test'], cwd=tmpdir, env=git_env)
|
|
|
|
# 3. Push
|
|
print(' Pushing commit ...')
|
|
run_git(['push', 'origin', 'HEAD:main'], cwd=tmpdir, env=git_env)
|
|
print(' Push succeeded.')
|
|
|
|
# 4. Verify via API — check the commit landed
|
|
print(' Verifying commit via API ...')
|
|
status, commits = api('GET',
|
|
f'{base_url}/api/v1/repos/{username}/{repo_name}/commits?limit=1',
|
|
username=username, password=password)
|
|
if status != 200 or not commits:
|
|
print(f'FAIL: Could not verify commit via API (HTTP {status}): {commits}')
|
|
sys.exit(1)
|
|
commit_msg = commits[0].get('commit', {}).get('message', '').strip()
|
|
if 'automated push test' not in commit_msg:
|
|
print(f'FAIL: Unexpected commit message: {commit_msg!r}')
|
|
sys.exit(1)
|
|
print(f' Commit verified: {commit_msg!r}')
|
|
|
|
finally:
|
|
shutil.rmtree(tmpdir, ignore_errors=True)
|
|
# 5. Delete the test repo
|
|
print(f' Deleting test repo {repo_name} ...')
|
|
api('DELETE', f'{base_url}/api/v1/repos/{username}/{repo_name}',
|
|
username=username, password=password)
|
|
|
|
print('PASS: git push test completed successfully')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|