72 lines
4.4 KiB
Python
72 lines
4.4 KiB
Python
"""Run public dependency preparation or isolated actual consumer package tests."""
|
|
from pathlib import Path
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import subprocess
|
|
import time
|
|
|
|
HERE = Path(__file__).resolve().parent
|
|
WORK = Path('/tmp/custodian-forgejo-successor-attempt2')
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('action', choices=['download', 'tidy', 'test', 'build'])
|
|
parser.add_argument('--attempt', type=int, default=1)
|
|
parser.add_argument('--workspace', type=Path, default=WORK)
|
|
args = parser.parse_args()
|
|
WORK = args.workspace.resolve()
|
|
assert WORK.is_relative_to('/tmp') and WORK.is_dir()
|
|
stem = f'consumer-{args.action}-attempt{args.attempt}'
|
|
assert not (HERE / (stem + '.json')).exists()
|
|
argv = ['bwrap', '--unshare-pid', '--die-with-parent', '--new-session']
|
|
if args.action in ['test', 'build']:
|
|
argv += ['--unshare-net']
|
|
for name in ['/usr', '/lib', '/lib64']:
|
|
argv += ['--ro-bind', name, name]
|
|
argv += ['--symlink', 'usr/bin', '/bin', '--proc', '/proc', '--dev', '/dev',
|
|
'--tmpfs', '/tmp', '--bind', str(WORK), '/work',
|
|
'--ro-bind', '/home/worsch/go/pkg/mod/cache/download', '/cached',
|
|
'--ro-bind', '/etc/ssl/certs', '/etc/ssl/certs',
|
|
'--ro-bind', '/etc/resolv.conf', '/etc/resolv.conf', '--chdir', '/work/source', '--clearenv']
|
|
if args.action == 'test':
|
|
fixtures = WORK / 'descriptor-fixtures'
|
|
fixtures.mkdir(exist_ok=True)
|
|
for name, value in [('race', 'A' * 64), ('race-replacement', 'B' * 64)]:
|
|
file = fixtures / name
|
|
if file.exists():
|
|
file.chmod(0o600)
|
|
file.write_text(value)
|
|
file.chmod(0o400)
|
|
argv += ['--dir', '/run', '--ro-bind', str(fixtures), '/run/forgejo-oidc',
|
|
'--bind', str(fixtures), '/run/writable-input']
|
|
env = {'PATH': '/work/go/bin:/usr/bin:/bin', 'HOME': '/work/home', 'GOPATH': '/work/gopath',
|
|
'GOTOOLCHAIN': 'local', 'GOPROXY': 'off' if args.action in ['test', 'build'] else 'file:///cached,https://proxy.golang.org',
|
|
'GOSUMDB': 'off' if args.action in ['test', 'build'] else 'sum.golang.org', 'GOVCS': '*:off',
|
|
'GOMODCACHE': '/work/modules', 'GOCACHE': '/work/gocache', 'GOMAXPROCS': '4',
|
|
'CGO_ENABLED': '1', 'GIT_CONFIG_NOSYSTEM': '1', 'GIT_CONFIG_GLOBAL': '/work/home/test.gitconfig', 'GIT_TERMINAL_PROMPT': '0'}
|
|
for key, value in env.items():
|
|
argv += ['--setenv', key, value]
|
|
command = ['go', 'mod', args.action] if args.action != 'test' else ['go', 'test', '-p', '1', '-json', '-tags', 'sqlite sqlite_unlock_notify',
|
|
'./services/auth/source/oauth2', './cmd', './models/auth', './models/db', '-run',
|
|
'TestAccessEngine|TestVerifiedApplicationIdentity|TestRequired|TestCurrent|TestPrivateSecret|TestSourceOperation|TestSensitiveSQL', '-count=1']
|
|
if args.action == 'build':
|
|
command = ['go', 'build', '-p', '4', '-tags', 'sqlite sqlite_unlock_notify', '-o', '/work/forgejo', '.']
|
|
argv += ['--'] + command
|
|
if (HERE / 'composed-source-inventory.json').exists():
|
|
selected = {row['path'] for row in json.loads((HERE / 'composed-source-inventory.json').read_text())['files']}
|
|
else:
|
|
selected = {row['path'] for row in json.loads((HERE / 'consumer-reconstruction.json').read_text())['paths']}
|
|
selected.update(str(item.relative_to(HERE / 'forgejo-source')) for item in (HERE / 'forgejo-source').rglob('*') if item.is_file())
|
|
selected.update(str(item.relative_to(WORK / 'source')) for item in (WORK / 'source/third_party/access-engine-pep').rglob('*') if item.is_file())
|
|
selected.update(['go.mod', 'go.sum'])
|
|
source_pins = {name: hashlib.sha256((WORK / 'source' / name).read_bytes()).hexdigest() for name in sorted(selected)}
|
|
started = time.monotonic()
|
|
with (HERE / (stem + '.log')).open('xb') as log:
|
|
run = subprocess.run(argv, stdout=log, stderr=subprocess.STDOUT, timeout=900)
|
|
pins = {name: hashlib.sha256((WORK / 'source' / name).read_bytes()).hexdigest() for name in ['go.mod', 'go.sum']}
|
|
result = {'returncode': run.returncode, 'seconds': round(time.monotonic() - started, 2),
|
|
'argv': argv, 'workspace': str(WORK), 'module_hashes': pins,
|
|
'composed_source_pins': source_pins,
|
|
'network': 'disabled' if args.action in ['test', 'build'] else 'public module download only', 'pid_namespace': 'private', 'real_credentials': False}
|
|
(HERE / (stem + '.json')).write_text(json.dumps(result, indent=2) + '\n')
|
|
print(json.dumps({'action': args.action, 'returncode': run.returncode, 'seconds': result['seconds']}))
|
|
raise SystemExit(run.returncode)
|