test(sync): 完成 S-06 安全验收

This commit is contained in:
2026-09-09 14:36:55 +08:00
parent f133f5b257
commit 502d09980f
6 changed files with 617 additions and 67 deletions
+110 -62
View File
@@ -92,6 +92,10 @@ class SyncProductionStack:
self.minio = None
self.sync = None
self.handles = []
self.pg_log = None
self.minio_log = None
self.sync_log = None
self.minio_env = {}
initdb = Path(config["artifacts"]["postgres_initdb"]).resolve()
self.pg_bin = initdb.parent
@@ -146,10 +150,10 @@ class SyncProductionStack:
self.stack.mkdir()
self.minio_data.mkdir()
self.staging.mkdir()
pg_log = (self.stack / "postgres.log").open("wb")
minio_log = (self.stack / "minio.log").open("wb")
sync_log = (self.stack / "sync.log").open("wb")
self.handles.extend([pg_log, minio_log, sync_log])
self.pg_log = (self.stack / "postgres.log").open("wb")
self.minio_log = (self.stack / "minio.log").open("wb")
self.sync_log = (self.stack / "sync.log").open("wb")
self.handles.extend([self.pg_log, self.minio_log, self.sync_log])
subprocess.run(
[
@@ -164,29 +168,12 @@ class SyncProductionStack:
"-E",
"UTF8",
],
stdout=pg_log,
stdout=self.pg_log,
stderr=subprocess.STDOUT,
check=True,
timeout=120,
)
subprocess.run(
[
str(self.pg_ctl),
"-D",
str(self.postgres_data),
"-l",
str(self.stack / "postgres-server.log"),
"-o",
f"-p {self.pg_port} -h 127.0.0.1",
"-w",
"start",
],
stdout=pg_log,
stderr=subprocess.STDOUT,
check=True,
timeout=60,
)
self.postgres_started = True
self.start_postgres()
subprocess.run(
[
str(self.createdb),
@@ -198,30 +185,17 @@ class SyncProductionStack:
"postgres",
"opennexus",
],
stdout=pg_log,
stdout=self.pg_log,
stderr=subprocess.STDOUT,
check=True,
timeout=30,
)
minio_env = os.environ.copy()
minio_env.update(
self.minio_env = os.environ.copy()
self.minio_env.update(
{"MINIO_ROOT_USER": self.minio_user, "MINIO_ROOT_PASSWORD": self.minio_password}
)
self.minio = subprocess.Popen(
[
str(self.minio_server),
"server",
str(self.minio_data),
"--address",
f"127.0.0.1:{self.minio_port}",
"--console-address",
f"127.0.0.1:{self.console_port}",
],
stdout=minio_log,
stderr=subprocess.STDOUT,
env=minio_env,
)
self.start_minio()
wait_http(f"http://127.0.0.1:{self.minio_port}/minio/health/ready")
self.service_env = os.environ.copy()
@@ -251,7 +225,7 @@ class SyncProductionStack:
],
cwd=SERVICE,
env=self.service_env,
stdout=sync_log,
stdout=self.sync_log,
stderr=subprocess.STDOUT,
check=True,
timeout=60,
@@ -260,13 +234,13 @@ class SyncProductionStack:
[str(self.server_python), "-m", "sync_server", "serve", "--workers", "2"],
cwd=SERVICE,
env=self.service_env,
stdout=sync_log,
stdout=self.sync_log,
stderr=subprocess.STDOUT,
)
wait_http(self.origin + "/ready", timeout=60)
return self
def create_vault(self, label: str):
def login(self, username: str, password: str, label: str) -> dict:
session = None
for _ in range(5):
try:
@@ -274,8 +248,8 @@ class SyncProductionStack:
"POST",
self.origin + "/sync/v1/auth/sessions",
body={
"username": self.username,
"password": self.password,
"username": username,
"password": password,
"device_name": label,
},
timeout=10,
@@ -288,7 +262,9 @@ class SyncProductionStack:
time.sleep(0.2)
if session is None:
raise RuntimeError("ACCEPTANCE_LOGIN_FAILED")
auth = {"Authorization": "Bearer " + session["access_token"]}
return session
def create_vault_for_auth(self, auth: dict, label: str):
vault = None
for _ in range(5):
try:
@@ -309,6 +285,89 @@ class SyncProductionStack:
raise RuntimeError("ACCEPTANCE_VAULT_FAILED")
return auth, self.origin + "/sync/v1/vaults/" + vault["vault_id"], vault["vault_id"]
def create_vault(self, label: str):
session = self.login(self.username, self.password, label)
auth = {"Authorization": "Bearer " + session["access_token"]}
return self.create_vault_for_auth(auth, label)
def add_user(self, prefix: str) -> tuple[str, str]:
username = prefix + "-" + secrets.token_hex(8)
password = secrets.token_urlsafe(32)
environment = dict(self.service_env)
environment.update(
{"ACCEPTANCE_EXTRA_USERNAME": username, "ACCEPTANCE_EXTRA_PASSWORD": password}
)
subprocess.run(
[
str(self.server_python),
"-c",
"import os; from sync_server.database import Database; "
"Database(os.environ['SYNC_DATABASE_URL']).add_user("
"os.environ['ACCEPTANCE_EXTRA_USERNAME'],os.environ['ACCEPTANCE_EXTRA_PASSWORD'])",
],
cwd=SERVICE,
env=environment,
stdout=self.sync_log,
stderr=subprocess.STDOUT,
check=True,
timeout=30,
)
return username, password
def start_postgres(self) -> None:
subprocess.run(
[
str(self.pg_ctl),
"-D",
str(self.postgres_data),
"-l",
str(self.stack / "postgres-server.log"),
"-o",
f"-p {self.pg_port} -h 127.0.0.1",
"-w",
"start",
],
stdout=self.pg_log,
stderr=subprocess.STDOUT,
check=True,
timeout=60,
)
self.postgres_started = True
def stop_postgres(self) -> None:
if not self.postgres_started:
return
subprocess.run(
[str(self.pg_ctl), "-D", str(self.postgres_data), "-m", "fast", "-w", "stop"],
stdout=self.pg_log,
stderr=subprocess.STDOUT,
check=True,
timeout=30,
)
self.postgres_started = False
def start_minio(self) -> None:
if self.minio is not None and self.minio.poll() is None:
return
self.minio = subprocess.Popen(
[
str(self.minio_server),
"server",
str(self.minio_data),
"--address",
f"127.0.0.1:{self.minio_port}",
"--console-address",
f"127.0.0.1:{self.console_port}",
],
stdout=self.minio_log,
stderr=subprocess.STDOUT,
env=self.minio_env,
)
def stop_minio(self) -> None:
stop_tree(self.minio)
self.minio = None
def sql_scalar(self, statement: str) -> int:
output = subprocess.check_output(
[
@@ -361,22 +420,11 @@ class SyncProductionStack:
def stop(self) -> None:
stop_tree(self.sync)
stop_tree(self.minio)
self.stop_minio()
if self.postgres_started:
subprocess.run(
[
str(self.pg_ctl),
"-D",
str(self.postgres_data),
"-m",
"fast",
"-w",
"stop",
],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
check=False,
timeout=30,
)
try:
self.stop_postgres()
except (OSError, subprocess.SubprocessError):
pass
for handle in self.handles:
handle.close()