From a77a3645a1caa8bcbb16f92e186a90cd41a73f25 Mon Sep 17 00:00:00 2001 From: ragnarok-clanker Date: Mon, 26 Oct 2026 15:35:17 +0100 Subject: [PATCH] Keep private identities out of maintenance source --- deploy/rodecomp/README.md | 4 ++++ tools/rodecomp/rewrite-identity.py | 34 ++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/deploy/rodecomp/README.md b/deploy/rodecomp/README.md index e1c0b6b..822b5de 100644 --- a/deploy/rodecomp/README.md +++ b/deploy/rodecomp/README.md @@ -54,6 +54,10 @@ the coordinator's optional identity override sets both author and committer for future commits. Without those variables, upstream identity behavior is unchanged. The private `rodecomp_history_backup` volume retains pre-rewrite recovery data; it is not published. Public old Git objects were pruned. Clank progress was preserved. +The maintenance helper accepts the private identity at runtime: +`python tools/rodecomp/rewrite-identity.py --repo `. +It requires git-filter-repo and rewrites history; use a backed-up disposable clone, +keep private arguments out of published logs, and check out the renamed branch afterward. Installer presentation (`src/server/install.js` only): four numbered steps, a compact ASCII banner, color/status icons, explicit incomplete-installation reporting, and diff --git a/tools/rodecomp/rewrite-identity.py b/tools/rodecomp/rewrite-identity.py index a8bd8d7..435b7e5 100644 --- a/tools/rodecomp/rewrite-identity.py +++ b/tools/rodecomp/rewrite-identity.py @@ -1,10 +1,26 @@ +import argparse +import re import subprocess -repo='/data/repo' -subprocess.run(['git','-C',repo,'filter-repo','--force', - '--blob-callback', "import re; blob.data = re.sub(rb'(?i)[a-z0-9.!#$%&*+/=?^_`{|}~-]*spl3en[a-z0-9.!#$%&*+/=?^_`{|}~-]*@[a-z0-9.-]+', b'ragnarok-clanker', blob.data); blob.data = re.sub(rb'(?i)spl3en', b'ragnarok-clanker', blob.data)", - '--message-callback', "import re; message = re.sub(rb'(?i)[a-z0-9.!#$%&*+/=?^_`{|}~-]*spl3en[a-z0-9.!#$%&*+/=?^_`{|}~-]*@[a-z0-9.-]+', b'ragnarok-clanker', message); return re.sub(rb'(?i)spl3en', b'ragnarok-clanker', message)", - '--name-callback', "import re; return re.sub(rb'(?i)spl3en', b'ragnarok-clanker', name)", - '--email-callback', "return b'ragnarok-clanker' if b'spl3en' in email.lower() else email", - '--filename-callback', "import re; return re.sub(rb'(?i)spl3en', b'ragnarok-clanker', filename)", - '--refname-callback', "import re; return re.sub(rb'(?i)spl3en', b'ragnarok-clanker', refname)" -],check=True) + +parser = argparse.ArgumentParser(description='Replace a private identity with ragnarok-clanker in Git history.') +parser.add_argument('identity', help='Private identity to replace, case-insensitively') +parser.add_argument('--repo', default='/data/repo', help='Repository whose history will be rewritten') +args = parser.parse_args() +if not args.identity: + parser.error('identity must not be empty') + +identity = re.escape(args.identity.encode()) +pattern = b'(?i)' + identity +email_pattern = rb'(?i)[a-z0-9.!#$%&*+/=?^_`{|}~-]*' + identity + rb'[a-z0-9.!#$%&*+/=?^_`{|}~-]*@[a-z0-9.-]+' +replace = f"re.sub({pattern!r}, b'ragnarok-clanker', value)" +replace_email = f"re.sub({email_pattern!r}, b'ragnarok-clanker', value)" + +subprocess.run([ + 'git', '-C', args.repo, 'filter-repo', '--force', + '--blob-callback', f'import re; value = blob.data; value = {replace_email}; blob.data = {replace}', + '--message-callback', f'import re; value = message; value = {replace_email}; return {replace}', + '--name-callback', f'import re; value = name; return {replace}', + '--email-callback', f"import re; return b'ragnarok-clanker' if re.search({pattern!r}, email) else email", + '--filename-callback', f'import re; value = filename; return {replace}', + '--refname-callback', f'import re; value = refname; return {replace}', +], check=True)