76 lines
3.7 KiB
Python
76 lines
3.7 KiB
Python
"""Publish the verified raw-input reconstruction; no tag or release operation."""
|
|
import base64
|
|
from datetime import datetime, timezone
|
|
import hashlib
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import subprocess
|
|
import tomllib
|
|
import urllib.request
|
|
|
|
BASE = Path(__file__).resolve().parent
|
|
SOURCE = BASE / 'source'
|
|
COMMIT = '802855f7e6f2f00a107a12196b458b267f586b8d'
|
|
BRANCH = 'codex/navigation-repair-prerelease-source-20260911'
|
|
ORIGIN = 'http://217.177.34.108:3000'
|
|
REMOTE = ORIGIN + '/sorokin.oleg.edu/ARCADIA-Studio.git'
|
|
RESULT = BASE / 'source-push-result.json'
|
|
assert not RESULT.exists()
|
|
readback_bytes = (BASE / 'package-readback.json').read_bytes()
|
|
assert hashlib.sha256(readback_bytes).hexdigest() == 'db0053ce70648b517942cfc8c915e826a7afd688129fcb4a813e11990820f498'
|
|
readback = json.loads(readback_bytes)
|
|
assert readback['status'] == 'PASS' and readback['source_commit'] == COMMIT
|
|
assert readback['archive_sha256'] == 'd7228c542f162663933ea002739a78c722bcca41e437df63b7c868ea2af201f1'
|
|
|
|
token = tomllib.loads((Path.home() / '.codex/config.toml').read_text(encoding='utf-8'))['mcp_servers']['gitea']['env']['GITEA_ACCESS_TOKEN']
|
|
|
|
class NoRedirect(urllib.request.HTTPRedirectHandler):
|
|
def redirect_request(self, req, fp, code, msg, headers, newurl):
|
|
raise RuntimeError('Unexpected redirect; credentials not forwarded')
|
|
|
|
opener = urllib.request.build_opener(urllib.request.ProxyHandler({}), NoRedirect)
|
|
with opener.open(urllib.request.Request(ORIGIN + '/api/v1/user', headers={'Authorization': 'token ' + token}), timeout=30) as response:
|
|
username = json.load(response)['login']
|
|
credential = base64.b64encode((username + ':' + token).encode()).decode()
|
|
env = {k: v for k, v in os.environ.items() if not k.startswith(('GIT_TRACE', 'GIT_CONFIG_', 'GIT_CURL_VERBOSE'))}
|
|
env.update({'GIT_TERMINAL_PROMPT': '0', 'GIT_CONFIG_COUNT': '4',
|
|
'GIT_CONFIG_KEY_0': 'credential.helper', 'GIT_CONFIG_VALUE_0': '',
|
|
'GIT_CONFIG_KEY_1': 'http.' + ORIGIN + '/.extraHeader', 'GIT_CONFIG_VALUE_1': 'Authorization: Basic ' + credential,
|
|
'GIT_CONFIG_KEY_2': 'http.followRedirects', 'GIT_CONFIG_VALUE_2': 'false',
|
|
'GIT_CONFIG_KEY_3': 'http.proxy', 'GIT_CONFIG_VALUE_3': ''})
|
|
|
|
def redact(value):
|
|
return value.replace(token, '[redacted]').replace(credential, '[redacted]')
|
|
|
|
def git(*args):
|
|
result = subprocess.run(['git', *args], cwd=SOURCE, env=env, capture_output=True, text=True, timeout=120)
|
|
if result.returncode:
|
|
raise RuntimeError(f'Git exit {result.returncode}: ' + redact(result.stderr))
|
|
return result.stdout.strip()
|
|
|
|
receipt = {'started': datetime.now(timezone.utc).isoformat(), 'branch': BRANCH, 'commit': COMMIT,
|
|
'scope': 'One exact raw-source branch; no force, tag, release or asset operation.'}
|
|
try:
|
|
assert git('rev-parse', 'HEAD') == COMMIT
|
|
assert git('branch', '--show-current') == BRANCH
|
|
assert not git('status', '--porcelain')
|
|
before = git('ls-remote', REMOTE, 'refs/heads/' + BRANCH)
|
|
receipt['before'] = before
|
|
# A prior independent publication must already be this exact immutable commit.
|
|
assert not before or before.split()[0] == COMMIT, 'Different source branch exists; review before publishing'
|
|
if not before:
|
|
git('push', REMOTE, COMMIT + ':refs/heads/' + BRANCH)
|
|
after = git('ls-remote', REMOTE, 'refs/heads/' + BRANCH)
|
|
assert after.split()[0] == COMMIT
|
|
receipt.update(success=True, after=after, user=username)
|
|
except BaseException as error:
|
|
receipt.update(success=False, error=redact(str(error)))
|
|
raise
|
|
finally:
|
|
receipt['finished'] = datetime.now(timezone.utc).isoformat()
|
|
with RESULT.open('x', encoding='utf-8', newline='\n') as output:
|
|
json.dump(receipt, output, indent=2)
|
|
output.write('\n')
|
|
print(json.dumps(receipt), flush=True)
|