Default dependencies to HTTPS with opt-in SSH fallback

This commit is contained in:
TheBadRoger committed 2026-10-15 21:12:36 +08:00
1 parent 959dba988c
commit 1e535c83eb
8 files changed
+49 -55

No files matched your search

+3 -7
View File
@@ -1,12 +1,8 @@
#!/bin/sh
# Fetch/build external dependencies as deploy, then start Docker Compose as root.
# Prepare configured external dependencies, then build and start Docker Compose.
set -eu
PROJECT_ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
if [ "$(id -u)" -ne 0 ]; then
echo 'Run with sudo; Git/compilation run as deploy, Docker runs as root.' >&2
exit 1
fi
sudo -H -u deploy python3 "$PROJECT_ROOT/scripts/init-deps.py"
sudo -H -u deploy python3 "$PROJECT_ROOT/scripts/prepare-deploy.py" --build-database
python3 "$PROJECT_ROOT/scripts/init-deps.py"
python3 "$PROJECT_ROOT/scripts/prepare-deploy.py" --build-database
docker compose --env-file "$PROJECT_ROOT/.env" -f "$PROJECT_ROOT/deploy/compose.yaml" up -d --build
printf '%s\n' 'When the database is ready, run the documented db-init command once.'
+14 -7
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
"""Initialize pinned dependencies via localhost SSH, falling back to GitHub."""
"""Initialize pinned dependencies over GitHub HTTPS; optionally prefer authorized SSH."""
import argparse
import os
from pathlib import Path
import subprocess
import sys
@@ -13,7 +14,7 @@ def git(*args, **kwargs):
return subprocess.run(['git', *args], cwd=ROOT, **kwargs)
def initialize(name, override):
def initialize(name, override, prefer_ssh=False):
path = f'external/{name}'
checkout = ROOT / path
pin = git('ls-files', '--stage', '--', path, text=True, capture_output=True, check=True).stdout.split()
@@ -33,20 +34,25 @@ def initialize(name, override):
raise RuntimeError(f'Local repository does not exist: {source}')
sources = [source.as_uri()]
else:
sources = [f'ssh://git@localhost/srv/git/{name}.git', f'git@github.com:TheBadRoger/{name}.git']
sources = [f'https://github.com/TheBadRoger/{name}.git']
if prefer_ssh:
sources.insert(0, f'ChuGit:/srv/git/{name}.git')
transport_env = {**os.environ, 'GIT_TERMINAL_PROMPT': '0'}
configured_ssh = git('config', '--get', 'core.sshCommand', capture_output=True, check=False)
if configured_ssh.returncode != 0 and not any(name in transport_env for name in ['GIT_SSH', 'GIT_SSH_COMMAND']):
transport_env['GIT_SSH_COMMAND'] = 'ssh -o BatchMode=yes -o ConnectTimeout=10 -o ConnectionAttempts=1'
for url in sources:
print(f'{name}: trying {url}', flush=True)
git('config', '--local', f'submodule.{path}.url', url, check=True)
options = ['-c', 'protocol.file.allow=always'] if override else []
options += ['-c', 'core.sshCommand=ssh -o BatchMode=yes -o ConnectTimeout=10 -o ConnectionAttempts=1']
if (checkout / '.git').exists():
git('-C', str(checkout), 'remote', 'set-url', 'origin', url, check=True)
result = git(*options, '-C', str(checkout), 'fetch', '--no-tags', 'origin', pin[1], check=False)
result = git(*options, '-C', str(checkout), 'fetch', '--no-tags', 'origin', pin[1], env=transport_env, check=False)
if result.returncode == 0:
git('-C', str(checkout), 'checkout', '--detach', pin[1], check=True)
return
else:
result = git(*options, 'submodule', 'update', '--init', '--checkout', '--', path, check=False)
result = git(*options, 'submodule', 'update', '--init', '--checkout', '--', path, env=transport_env, check=False)
if result.returncode == 0:
return
print(f'{name}: source failed; trying next configured source', file=sys.stderr, flush=True)
@@ -57,9 +63,10 @@ def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--database-repo', type=Path, help='explicit local development source for ChuSQL')
parser.add_argument('--driver-repo', type=Path, help='explicit local development source for the driver')
parser.add_argument('--prefer-ssh', action='store_true', help='authorized devices: try ChuGit SSH first, then GitHub HTTPS')
args = parser.parse_args()
for name, override in zip(PROJECTS, [args.database_repo, args.driver_repo]):
initialize(name, override)
initialize(name, override, args.prefer_ssh)
if __name__ == '__main__':
+14 -7
View File
@@ -11,7 +11,7 @@ SCRIPT = Path(__file__).with_name('init-deps.py')
class InitializeDependencies(unittest.TestCase):
def test_local_rewrite_fetches_only_pinned_dependency_commits(self):
def test_https_default_and_authorized_ssh_fallback_preserve_pins(self):
with tempfile.TemporaryDirectory(prefix='chublog deps ') as temporary:
root = Path(temporary)
project = root / 'blog'
@@ -46,7 +46,7 @@ class InitializeDependencies(unittest.TestCase):
for name in ['ChuSQL', 'ChuSQL-RustDriver']:
self.assertEqual((project / f'external/{name}/source.txt').read_text(), f'{name} committed source')
self.assertTrue(all(line.startswith('160000') for line in git(project, 'ls-files', '--stage', 'external').splitlines()))
# A fresh clone must fall back when localhost SSH fails. Redirect only the test's
# A fresh clone must use HTTPS without attempting SSH. Redirect only the test's
# GitHub remotes to local fixtures, so this verifies fallback without network access.
fresh = root / 'fresh'
git(project, '-c', 'user.name=Test', '-c', 'user.email=test@example.invalid', 'commit', '-m', 'Pinned dependencies')
@@ -56,12 +56,19 @@ class InitializeDependencies(unittest.TestCase):
fallback_env = {**env, 'GIT_ALLOW_PROTOCOL': 'file', 'GIT_CONFIG_COUNT': '2'}
for i, (name, source) in enumerate(zip(['ChuSQL', 'ChuSQL-RustDriver'], sources)):
fallback_env[f'GIT_CONFIG_KEY_{i}'] = f'url.{Path(source).as_uri()}.insteadOf'
fallback_env[f'GIT_CONFIG_VALUE_{i}'] = f'git@github.com:TheBadRoger/{name}.git'
fallback_env[f'GIT_CONFIG_VALUE_{i}'] = f'https://github.com/TheBadRoger/{name}.git'
subprocess.run(['python3', 'scripts/init-deps.py'], cwd=fresh, env=fallback_env, check=True, capture_output=True)
for name in ['ChuSQL', 'ChuSQL-RustDriver']:
self.assertEqual((fresh / f'external/{name}/source.txt').read_text(), f'{name} committed source')
self.assertEqual(git(fresh / f'external/{name}', 'config', '--get', 'remote.origin.url'), f'git@github.com:TheBadRoger/{name}.git')
# Also cover an accessible but empty localhost bare repository: the initial
self.assertEqual(git(fresh / f'external/{name}', 'config', '--get', 'remote.origin.url'), f'https://github.com/TheBadRoger/{name}.git')
unavailable = root / 'unavailable'
git(root, 'clone', '--no-local', str(project), str(unavailable))
(unavailable / 'scripts').mkdir()
shutil.copy2(SCRIPT, unavailable / 'scripts/init-deps.py')
subprocess.run(['python3', 'scripts/init-deps.py', '--prefer-ssh'], cwd=unavailable, env=fallback_env, check=True, capture_output=True)
for name in ['ChuSQL', 'ChuSQL-RustDriver']:
self.assertEqual((unavailable / f'external/{name}/source.txt').read_text(), f'{name} committed source')
# Also cover an accessible but empty authorized SSH bare repository: the initial
# submodule clone succeeds, fetching the pinned commit fails, then GitHub recovers.
empty = root / 'empty.git'
git(root, 'init', '--bare', str(empty))
@@ -74,8 +81,8 @@ class InitializeDependencies(unittest.TestCase):
empty_source = root / f'empty-{name}.git'
git(root, 'clone', '--bare', str(empty), str(empty_source))
partial_env[f'GIT_CONFIG_KEY_{i}'] = f'url.{empty_source.as_uri()}.insteadOf'
partial_env[f'GIT_CONFIG_VALUE_{i}'] = f'ssh://git@localhost/srv/git/{name}.git'
result = subprocess.run(['python3', 'scripts/init-deps.py'], cwd=partial, env=partial_env, text=True, capture_output=True)
partial_env[f'GIT_CONFIG_VALUE_{i}'] = f'ChuGit:/srv/git/{name}.git'
result = subprocess.run(['python3', 'scripts/init-deps.py', '--prefer-ssh'], cwd=partial, env=partial_env, text=True, capture_output=True)
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
for name in ['ChuSQL', 'ChuSQL-RustDriver']:
self.assertEqual((partial / f'external/{name}/source.txt').read_text(), f'{name} committed source')