feat: harden data access and simplify user management

This commit is contained in:
xuelong committed 2026-08-25 21:02:30 -07:00
1 parent 3dd5731751
commit adb780bc82
51 files changed
+3239 -2121

No files matched your search

+45 -4
View File
@@ -33,12 +33,12 @@ def _connection_options(*, include_database: bool) -> dict[str, object]:
parsed = urlparse(settings.data_mysql_url)
if parsed.scheme not in {"mysql", "mysql+aiomysql"}:
raise ValueError("DATA_MYSQL_URL 必须使用 mysql:// 协议")
database = unquote(parsed.path.lstrip("/")) or "platform_control"
if not _DATABASE_PATTERN.fullmatch(database):
control_database = unquote(parsed.path.lstrip("/")) or "platform_control"
if not _DATABASE_PATTERN.fullmatch(control_database):
raise ValueError("DATA_MYSQL_URL 中的控制数据库名称不合法")
global _control_database
_control_database = database
_control_database = control_database
options: dict[str, object] = {
"host": parsed.hostname or "localhost",
"port": parsed.port or 3306,
@@ -49,7 +49,7 @@ def _connection_options(*, include_database: bool) -> dict[str, object]:
"cursorclass": aiomysql.DictCursor,
}
if include_database:
options["db"] = database
options["db"] = control_database
return options
@@ -153,3 +153,44 @@ async def get_data_conn(database: str | None = None) -> AsyncIterator[aiomysql.C
await conn.select_db(_control_database)
except Exception:
logger.warning("Failed to reset a Data Center MySQL connection", exc_info=True)
@asynccontextmanager
async def get_provisioner_conn() -> AsyncIterator[aiomysql.Connection]:
"""Open the isolated account-provisioning connection.
The normal Data Center account must not hold ``CREATE USER`` or ``GRANT
OPTION``. This short-lived connection is used only by the admin-only
DBeaver issuance and revocation endpoints.
"""
username = settings.data_mysql_provisioner_user.strip()
password = settings.data_mysql_provisioner_password
if not username or not password:
raise DataCenterUnavailable("DBeaver账号签发服务尚未配置")
if not re.fullmatch(r"[A-Za-z][A-Za-z0-9_]{0,31}", username):
raise ValueError("MySQL账号签发用户名称不合法")
parsed = urlparse(settings.data_mysql_url)
database = unquote(parsed.path.lstrip("/")) or "platform_control"
if not _DATABASE_PATTERN.fullmatch(database):
raise ValueError("DATA_MYSQL_URL 中的控制数据库名称不合法")
conn = await aiomysql.connect(
host=parsed.hostname or "localhost",
port=parsed.port or 3306,
user=username,
password=password,
charset="utf8mb4",
autocommit=False,
cursorclass=aiomysql.DictCursor,
)
try:
yield conn
except Exception:
await conn.rollback()
raise
finally:
try:
await conn.rollback()
finally:
conn.close()