70 lines
4.2 KiB
Python
70 lines
4.2 KiB
Python
"""Run the actual controller migration/stream framing in pinned Forgejo userspace."""
|
|
from pathlib import Path
|
|
import importlib.util
|
|
import json
|
|
import subprocess
|
|
|
|
HERE=Path(__file__).resolve().parent
|
|
IMAGE='code.forgejo.org/forgejo/forgejo@sha256:691657c7e64af7730a2e885e6d022cf16ae60724931c5392bd61838afadcaeba'
|
|
spec=importlib.util.spec_from_file_location('r4',HERE/'rollout.py');r=importlib.util.module_from_spec(spec);spec.loader.exec_module(r)
|
|
m=r.support();C=json.loads((r.ORIGINAL/'inputs.json').read_bytes())
|
|
|
|
|
|
def main():
|
|
argv=['docker','run','-d','--rm','--network=none','--user=1000:1000','--read-only','--cap-drop=ALL','--security-opt=no-new-privileges:true',
|
|
'--tmpfs','/tmp:rw,size=64m,uid=1000,gid=1000','--tmpfs','/data:rw,size=64m,uid=1000,gid=1000',
|
|
'--mount','type=bind,src='+str(r.ORIGINAL)+',dst=/original,readonly','--entrypoint=/bin/sh',IMAGE,'-c','tail -f /dev/null']
|
|
created=subprocess.run(argv,capture_output=True,timeout=30)
|
|
if created.returncode:raise RuntimeError('fixture-container-start-failed')
|
|
cid=created.stdout.decode().strip();events=[];phase='setup'
|
|
def shell(script,args=(),data=None,timeout=180):
|
|
q=subprocess.run(['docker','exec','-i',cid,'/bin/sh','-c',script,'sh',*args],input=data,capture_output=True,timeout=timeout)
|
|
if q.returncode:raise RuntimeError('fixture-command-failed:'+phase)
|
|
return q.stdout
|
|
try:
|
|
script=r'''set -eu
|
|
n=0
|
|
while test "$n" -lt 171; do
|
|
name=$(printf test%03d "$n")
|
|
repo=/data/git/gitea-repositories/coulomb/$name.git
|
|
for hook in pre-receive post-receive update pre-receive.d/gitea post-receive.d/gitea update.d/gitea pre-receive.d/20-authorize post-receive.d/20-notify; do
|
|
path="$repo/hooks/$hook";mkdir -p "${path%/*}"
|
|
printf 'unchanged generated hook\n' > "$path";chmod 775 "$path"
|
|
done
|
|
file="$repo/hooks/pre-receive.d/10-custodian-secret-scan"
|
|
cp /original/before-hook "$file";chmod 775 "$file"
|
|
if test "$n" -lt 3; then chmod 755 "$file"; fi
|
|
if test "$n" -lt 16; then chmod 755 "$repo/hooks/pre-receive"; fi
|
|
n=$((n+1))
|
|
done
|
|
'''
|
|
shell(script)
|
|
class TestRunner(r.make_runner(m)):
|
|
def shell(self,pod,script,args=(),data=None,timeout=90):return shell(script,args,data,max(timeout,180))
|
|
def event(self,name,**fields):events.append({'event':name,**fields})
|
|
runner=TestRunner(C);before=runner.inventory('fixture',{C['old_hook_sha256']});runner.receipt['before_hooks']=before
|
|
phase='initial-migration';runner.migrate('fixture','apply')
|
|
phase='simulate-fsgroup';shell("find /data -type f -exec chmod g+w {} +")
|
|
phase='post-recreate-migration';runner.migrate('fixture','apply')
|
|
assert events[-1]['group_write_additions_reversed']==19
|
|
phase='simulate-second-fsgroup';shell("find /data -type f -exec chmod g+w {} +")
|
|
phase='rollback-migration';runner.migrate('fixture','rollback')
|
|
after=runner.inventory('fixture',{C['old_hook_sha256']});assert after==before
|
|
# Unknown protected data must stop before any scanner rewrite.
|
|
phase='protected-drift';shell("printf 'owner content drift\\n' > /data/git/gitea-repositories/coulomb/test000.git/hooks/pre-receive")
|
|
try:runner.migrate('fixture','apply')
|
|
except RuntimeError as exc:assert str(exc)=='protected-hook-content-drift'
|
|
else:raise AssertionError('protected-drift-not-refused')
|
|
still=runner.inventory('fixture',{C['old_hook_sha256']});assert len(still)==171
|
|
result={'result':'passed','image':IMAGE,'repositories':171,'hooks':sum(len(x) for x in before.values()),
|
|
'cases':['initial-migration','post-recreate-mode-restoration','rollback-mode-restoration','protected-drift-before-write'],
|
|
'group_write_additions_reversed':19,'events':events,'native_mutation':False}
|
|
(HERE/'controller-image-tests.json').write_text(json.dumps(result,indent=2)+'\n');print(json.dumps(result))
|
|
except Exception as exc:
|
|
(HERE/'controller-image-tests-failed.json').write_text(json.dumps({'result':'unverified','phase':phase,'error':type(exc).__name__,'image':IMAGE,'native_mutation':False},indent=2)+'\n')
|
|
raise
|
|
finally:
|
|
subprocess.run(['docker','stop','--time=0',cid],capture_output=True,timeout=30)
|
|
|
|
|
|
if __name__=='__main__':main()
|