From 121f11de6af454f49d4dd859e24c05308fbd8cfa Mon Sep 17 00:00:00 2001 From: codex Date: Sun, 6 Sep 2026 01:16:43 +0200 Subject: [PATCH] Allow bounded atomic import of full Forgejo SQL archive Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a06ecb-456a-71c2-b41e-0755d336e883 --- scripts/restore_forgejo_offsite_locally.py | 23 ++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/scripts/restore_forgejo_offsite_locally.py b/scripts/restore_forgejo_offsite_locally.py index 83f46d5..e287f5d 100644 --- a/scripts/restore_forgejo_offsite_locally.py +++ b/scripts/restore_forgejo_offsite_locally.py @@ -29,9 +29,24 @@ def run(archive, receipt): staging=archive.parent/(prefix+'-staging') staging.mkdir(mode=0o700) resources=[] - def command(args, payload=None, env=None, check=True): - r=subprocess.run(args,input=payload,capture_output=True,env=env,timeout=180) - if check and r.returncode: raise ValueError('isolated_command_failed') + def command(args, payload=None, env=None, check=True, timeout=180): + try: + r=subprocess.run(args,input=payload,capture_output=True,env=env,timeout=timeout) + except subprocess.TimeoutExpired: + receipt['failure_kind']='command_timeout' + raise ValueError('isolated_command_timeout') from None + if check and r.returncode: + receipt['failure_kind']='command_nonzero' + receipt['command_exit_code']=r.returncode + # Classify only fixed diagnostics; never publish captured output. + for marker, category in [(b'out of memory', 'memory_limit'), + (b'syntax error', 'sql_syntax'), + (b'does not exist', 'missing_database_object'), + (b'duplicate key', 'duplicate_database_key')]: + if marker in r.stderr.lower(): + receipt['failure_kind']=category + break + raise ValueError('isolated_command_failed') return r def docker(*args, **kw): return command(['docker',*args],**kw) try: @@ -95,7 +110,7 @@ LEVEL = Error time.sleep(2) else: raise ValueError('database_not_ready') sql=(staging/'forgejo-db.sql').read_bytes() - docker('exec','-i',db,'psql','-U','forgejo','-d','forgejo','-v','ON_ERROR_STOP=1',payload=sql) + docker('exec','-i',db,'psql','-U','forgejo','-d','forgejo','--single-transaction','-v','ON_ERROR_STOP=1',payload=sql,timeout=900) receipt['database_import']=True counts=docker('exec',db,'psql','-U','forgejo','-d','forgejo','-Atqc', 'SELECT (SELECT count(*) FROM repository),(SELECT count(*) FROM "user"),(SELECT count(*) FROM package_blob);').stdout.decode().strip()