chore: import verified syly2 maintenance baseline without embedded credentials
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Restore the user-supplied dump only to the new isolated MySQL container."""
|
||||
import json, os, subprocess, sys, time
|
||||
from pathlib import Path
|
||||
os.umask(0o077)
|
||||
ROOT=Path('/home/ubuntu/apps/syly2-uat')
|
||||
DC=['docker','compose','-f',str(ROOT/'compose.json')]
|
||||
cid=subprocess.check_output(DC+['ps','-q','db'],text=True).strip()
|
||||
assert cid
|
||||
label=subprocess.check_output(['docker','inspect','--format','{{index .Config.Labels "com.docker.compose.project"}}',cid],text=True).strip()
|
||||
assert label=='syly2-uat'
|
||||
phase=sys.argv[1]
|
||||
cmd=['docker','exec','-i',cid,'/opt/mysql/bin/mysql','--max-allowed-packet=512M','--default-character-set=utf8mb4','-uroot','-N','-B']
|
||||
if phase=='inventory': cmd.insert(-4,'--defaults-extra-file=/run/secrets/mysql-client.cnf')
|
||||
def query(sql):
|
||||
p=subprocess.run(cmd,input=sql,text=True,capture_output=True)
|
||||
if p.returncode:
|
||||
(ROOT/'evidence/db-last-error.log').write_text(p.stderr)
|
||||
raise RuntimeError('SQL failed; private error log saved')
|
||||
return p.stdout.strip()
|
||||
if phase=='restore':
|
||||
assert not (ROOT/'evidence/restore-complete.json').exists(), 'Refusing repeated restore over existing UAT'
|
||||
assert query("SELECT COUNT(*) FROM information_schema.schemata WHERE schema_name='sanya_ch'")=='0'
|
||||
started=time.time()
|
||||
with (ROOT/'incoming/sanya_ch_full.sql').open('rb') as inp,(ROOT/'evidence/restore.log').open('wb') as log:
|
||||
p=subprocess.run(cmd,stdin=inp,stdout=log,stderr=log)
|
||||
if p.returncode: raise RuntimeError('Restore failed; inspect private log')
|
||||
tables=query("SELECT table_name FROM information_schema.tables WHERE table_schema='sanya_ch' AND table_type='BASE TABLE' ORDER BY table_name").splitlines()
|
||||
counts={t:int(query('SELECT COUNT(*) FROM sanya_ch.`'+t+'`')) for t in tables}
|
||||
info={'mysql_version':query('SELECT VERSION()'),'tables':len(tables),'rows':sum(counts.values()),'row_counts':counts,'seconds':round(time.time()-started,1)}
|
||||
(ROOT/'evidence/restore-complete.json').write_text(json.dumps(info,indent=2))
|
||||
cols=query("SELECT column_name FROM information_schema.columns WHERE table_schema='sanya_ch' AND table_name='t_s_base_user'").splitlines()
|
||||
(ROOT/'evidence/base-user-columns.json').write_text(json.dumps(cols))
|
||||
print(json.dumps({k:v for k,v in info.items() if k!='row_counts'}))
|
||||
elif phase=='seed':
|
||||
assert (ROOT/'evidence/restore-complete.json').exists()
|
||||
assert query("SELECT COUNT(*) FROM sanya_ch.t_s_base_user WHERE username='uat_admin'")=='0', 'Refusing to change an existing account'
|
||||
creds=json.loads((ROOT/'secrets/credentials.json').read_text())
|
||||
jdk='/home/ubuntu/.local/opt/syly2-build/corretto-8.512.09.1/bin/'
|
||||
helper=ROOT/'scripts/HashUat.java'
|
||||
helper.write_text('import java.io.*; import org.mindrot.jbcrypt.BCrypt; public class HashUat { public static void main(String[] a) throws Exception { String p=new BufferedReader(new InputStreamReader(System.in)).readLine(); System.out.print(BCrypt.hashpw(p,BCrypt.gensalt(12))); }}')
|
||||
cp=str(ROOT/'runtime/webapp/WEB-INF/lib/*')
|
||||
subprocess.run([jdk+'javac','-cp',cp,str(helper)],check=True)
|
||||
hashed=subprocess.check_output([jdk+'java','-cp',str(ROOT/'scripts')+':'+cp,'HashUat'],input=creds['uat_password'],text=True)
|
||||
columns=json.loads((ROOT/'evidence/base-user-columns.json').read_text())
|
||||
added=[]
|
||||
if 'password_update_date' not in columns:
|
||||
query('ALTER TABLE sanya_ch.t_s_base_user ADD COLUMN password_update_date datetime NULL;')
|
||||
added.append('t_s_base_user.password_update_date')
|
||||
# All IDs belong to this synthetic UAT fixture, never to a restored account.
|
||||
uid='01a186a4e1407e328d2bfe6687e68b01'
|
||||
org='01a186a4e1407e328d2bfe6687e68b02'
|
||||
role='01a186a4e1407e328d2bfe6687e68b03'
|
||||
sql=f"""USE sanya_ch;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t_s_depart(ID,departname,description,org_code,org_type) VALUES('{org}','UAT验证组织','仅用于隔离测试','UAT','1');
|
||||
INSERT INTO t_s_base_user(ID,username,password,realname,status,activitiSync,area,login_fail_count,is_locked,password_update_date) VALUES('{uid}','uat_admin','{hashed}','UAT验证管理员',1,0,'460200',0,0,NOW());
|
||||
INSERT INTO t_s_user(id,create_date,create_by,create_name) VALUES('{uid}',NOW(),'uat-deploy','UAT deployment');
|
||||
INSERT INTO t_s_user_org(ID,user_id,org_id) VALUES(REPLACE(UUID(),'-',''),'{uid}','{org}');
|
||||
INSERT INTO t_s_role(ID,rolecode,rolename) VALUES('{role}','uat_admin','UAT验证角色');
|
||||
INSERT INTO t_s_role_user(ID,roleid,userid) VALUES(REPLACE(UUID(),'-',''),'{role}','{uid}');
|
||||
INSERT INTO t_s_role_function(ID,functionid,roleid) SELECT REPLACE(UUID(),'-',''),ID,'{role}' FROM t_s_function;
|
||||
COMMIT;
|
||||
CREATE USER 'syly_uat'@'%' IDENTIFIED BY '{creds['mysql_app']}';
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE, SHOW VIEW ON sanya_ch.* TO 'syly_uat'@'%';
|
||||
ALTER USER 'root'@'localhost' IDENTIFIED BY '{creds['mysql_root']}';
|
||||
"""
|
||||
query(sql)
|
||||
(ROOT/'evidence/uat-seed.json').write_text(json.dumps({'username':'uat_admin','user_id':uid,'org_id':org,'role_id':role,'added_columns':added,'existing_account_passwords_changed':False,'business_rows_changed':False},indent=2))
|
||||
print('Dedicated UAT account added; original accounts preserved; DB credentials initialized.')
|
||||
else:
|
||||
raise ValueError(phase)
|
||||
Reference in New Issue
Block a user