fix(topology): secure and unify demo serving

This commit is contained in:
2026-07-09 21:45:53 +08:00
parent e5f004fea4
commit 270956c348
4 changed files with 68 additions and 7 deletions
+1 -1
View File
@@ -255,7 +255,7 @@
</div> </div>
<script> <script>
const API_BASE = 'http://localhost:5000'; const API_BASE = '';
let currentData = null; let currentData = null;
// Group node members for composite SVG elements // Group node members for composite SVG elements
+45
View File
@@ -0,0 +1,45 @@
from __future__ import annotations
import unittest
from pathlib import Path
from topology_api.app import create_app
ROOT = Path(__file__).resolve().parents[1]
HTML_PATH = ROOT / "data" / "wiki" / "guanghan_topology_demo.html"
CONFIG_PATH = ROOT / "topology_api" / "config.py"
class TopologyApiServingTests(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
app = create_app()
app.config.update(TESTING=True)
cls.client = app.test_client()
def test_app_serves_demo_page_and_health(self) -> None:
health = self.client.get("/health")
self.assertEqual(health.status_code, 200)
self.assertEqual(health.get_json(), {"status": "ok"})
page = self.client.get("/guanghan_topology_demo.html")
self.assertEqual(page.status_code, 200)
self.assertIn("广寒基地拓扑结构", page.get_data(as_text=True))
page.close()
def test_page_uses_same_origin_api(self) -> None:
html = HTML_PATH.read_text(encoding="utf-8")
self.assertNotIn("http://localhost:5000", html)
self.assertIn("const API_BASE = ''", html)
def test_config_has_no_default_password(self) -> None:
source = CONFIG_PATH.read_text(encoding="utf-8")
self.assertNotRegex(
source,
r'os\.environ\.get\(\s*["\']PGPASSWORD["\']\s*,',
)
if __name__ == "__main__":
unittest.main()
+10 -1
View File
@@ -1,10 +1,15 @@
# topology_api/app.py # topology_api/app.py
from flask import Flask from pathlib import Path
from flask import Flask, send_from_directory
from flask_cors import CORS from flask_cors import CORS
from topology_api.config import API_HOST, API_PORT, API_DEBUG from topology_api.config import API_HOST, API_PORT, API_DEBUG
from topology_api.routes.snapshot import snapshot_bp from topology_api.routes.snapshot import snapshot_bp
WIKI_DIR = Path(__file__).resolve().parents[1] / "data" / "wiki"
def create_app(): def create_app():
app = Flask(__name__) app = Flask(__name__)
CORS(app) CORS(app)
@@ -14,6 +19,10 @@ def create_app():
def health(): def health():
return {"status": "ok"} return {"status": "ok"}
@app.route("/guanghan_topology_demo.html")
def topology_demo():
return send_from_directory(WIKI_DIR, "guanghan_topology_demo.html")
return app return app
+12 -5
View File
@@ -1,11 +1,18 @@
# topology_api/config.py # topology_api/config.py
import os import os
from pathlib import Path
from dotenv import load_dotenv
PROJECT_ROOT = Path(__file__).resolve().parents[1]
load_dotenv(PROJECT_ROOT / ".env")
# PostgreSQL connection (from .env) # PostgreSQL connection (from .env)
PGHOST = os.environ.get("PGHOST", "192.168.195.241") PGHOST = os.environ["PGHOST"]
PGPORT = os.environ.get("PGPORT", "35432") PGPORT = os.environ["PGPORT"]
PGUSER = os.environ.get("PGUSER", "user_armor") PGUSER = os.environ["PGUSER"]
PGPASSWORD = os.environ.get("PGPASSWORD", "user_armor_1790990971") PGPASSWORD = os.environ["PGPASSWORD"]
TOPO_DATABASE = os.environ.get("TOPO_DATABASE", "ksp_wiki_topology") TOPO_DATABASE = os.environ.get("TOPO_DATABASE", "ksp_wiki_topology")
_BASE_DSN = f"postgresql://{PGUSER}:{PGPASSWORD}@{PGHOST}:{PGPORT}" _BASE_DSN = f"postgresql://{PGUSER}:{PGPASSWORD}@{PGHOST}:{PGPORT}"
@@ -26,5 +33,5 @@ WRITER_DATABASE_URL = os.environ.get(
) )
API_HOST = os.environ.get("TOPOLOGY_API_HOST", "0.0.0.0") API_HOST = os.environ.get("TOPOLOGY_API_HOST", "0.0.0.0")
API_PORT = int(os.environ.get("TOPOLOGY_API_PORT", "5000")) API_PORT = int(os.environ.get("TOPOLOGY_API_PORT", "8080"))
API_DEBUG = os.environ.get("TOPOLOGY_API_DEBUG", "false").lower() == "true" API_DEBUG = os.environ.get("TOPOLOGY_API_DEBUG", "false").lower() == "true"