Files
Cloud-Tour-to-Libo/admin-web/tests/interfaceCenterSurface.test.ts
T
xuelong 3dd5731751 feat: streamline platform and secure data access
- move the relational data center to MySQL and a standalone workbench\n- add Interface Center API credentials, policies, logs, and DBeaver SSH guidance\n- harden authentication and deployment while retiring unused management surfaces
2026-08-25 02:06:28 -07:00

90 lines
3.6 KiB
TypeScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
const appSource = readFileSync(new URL("../src/App.tsx", import.meta.url), "utf8");
const panelSource = readFileSync(
new URL("../src/panels/system/InterfaceCenterPanel.tsx", import.meta.url),
"utf8",
);
const apiSource = readFileSync(new URL("../src/api.ts", import.meta.url), "utf8");
const composeSource = readFileSync(new URL("../../docker-compose.yml", import.meta.url), "utf8");
const serverComposeSource = readFileSync(
new URL("../../docker-compose.server.yml", import.meta.url),
"utf8",
);
const dockerfileSource = readFileSync(new URL("../../Dockerfile", import.meta.url), "utf8");
const dataCenterSource = readFileSync(
new URL("../src/panels/data-platform/DataCenterPanel.tsx", import.meta.url),
"utf8",
);
const interfaceServiceSource = readFileSync(
new URL("../../app/data_platform/interface_service.py", import.meta.url),
"utf8",
);
test("Interface Center is available under System", () => {
assert.match(appSource, /key: "\/system\/interfaces"[\s\S]*label: "接口中心"/);
assert.match(appSource, /path="\/admin\/system\/interfaces"/);
assert.match(appSource, /<InterfaceCenterPanel \/>/);
});
test("Interface Center is designed for inbound server access", () => {
for (const label of ["DBeaver 管理接入", "HTTPS API", "接入信息", "安全设置"]) {
assert.match(panelSource, new RegExp(label));
}
assert.match(panelSource, /SSH 隧道 \+ 独立 MySQL 账号/);
assert.match(panelSource, /不要在 Main 页填写服务器公网 IP/);
assert.match(panelSource, /Show all databases/);
assert.doesNotMatch(panelSource, /JDBC URL/);
assert.doesNotMatch(panelSource, /测试连接/);
});
test("DBeaver access defaults to a loopback-only MySQL endpoint", () => {
assert.match(composeSource, /MYSQL_HOST_BIND:-127\.0\.0\.1/);
assert.match(composeSource, /--local-infile=OFF/);
assert.match(composeSource, /DATA_MYSQL_SSH_TUNNEL_REQUIRED/);
assert.match(interfaceServiceSource, /"mysql_publicly_bound": publicly_bound/);
assert.match(interfaceServiceSource, /"database_host"/);
assert.match(interfaceServiceSource, /"ssh_host"/);
});
test("production deployment fails closed and preserves recoverability", () => {
for (const setting of [
"--secure-file-priv=NULL",
"--log-bin=mysql-bin",
"--binlog-format=ROW",
"--sync-binlog=1",
"--innodb-flush-log-at-trx-commit=1",
]) {
assert.match(composeSource, new RegExp(setting.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")));
}
assert.match(serverComposeSource, /SECURITY_STRICT_MODE: "true"/);
assert.match(serverComposeSource, /API_BIND_HOST:-127\.0\.0\.1/);
assert.match(serverComposeSource, /必须设置至少 32 位 AUTH_SECRET/);
assert.match(dockerfileSource, /USER appuser/);
assert.match(dataCenterSource, /安全只读模式/);
});
test("Interface Center keeps clients, credentials, policies, docs and logs", () => {
for (const label of ["客户端与密钥", "权限策略", "接口说明", "调用日志"]) {
assert.match(panelSource, new RegExp(label));
}
assert.match(panelSource, /完整密钥只在签发时显示一次/);
assert.match(panelSource, /留空默认 30 天,最长 90 天/);
assert.match(panelSource, /加密备份待部署/);
assert.match(panelSource, /接口不接受任意 SQL/);
});
test("frontend uses the administrative Interface Center API", () => {
for (const path of [
"/interface-center/summary",
"/interface-center/clients",
"/interface-center/credentials",
"/interface-center/policies",
"/interface-center/logs",
]) {
assert.match(apiSource, new RegExp(path));
}
});