feat: 强化打包配置与服务安全

This commit is contained in:
shen
2026-07-18 13:30:56 +08:00
parent d1f070b251
commit a48909f3bc
26 changed files with 779 additions and 203 deletions
+60
View File
@@ -0,0 +1,60 @@
"""公网部署安全回归测试。"""
import pytest
from fastapi.testclient import TestClient
from starlette.websockets import WebSocketDisconnect
from backend import config
from backend.main import app
from backend.security import hash_password, verify_password
def test_passwords_use_bcrypt_and_verify():
password_hash = hash_password("a-strong-password")
assert password_hash.startswith("$2")
assert verify_password("a-strong-password", password_hash) == (True, False)
assert verify_password("wrong-password", password_hash) == (False, False)
def test_websocket_rejects_connection_without_jwt():
with TestClient(app) as unauthenticated_client:
with pytest.raises(WebSocketDisconnect) as exc_info:
with unauthenticated_client.websocket_connect("/ws/tasks/task-1"):
pass
assert exc_info.value.code == 1008
def test_production_rejects_default_security_settings(monkeypatch):
monkeypatch.setattr(config, "APP_ENV", "production")
monkeypatch.setattr(config, "JWT_SECRET", "ios-build-server-secret-key-change-in-production")
monkeypatch.setattr(config, "ADMIN_PASSWORD", "admin123")
monkeypatch.setattr(config, "CORS_ALLOWED_ORIGINS", ["*"])
monkeypatch.setattr(config, "TRUSTED_HOSTS", ["*"])
monkeypatch.setenv("TRUSTED_HOSTS", "*")
with pytest.raises(RuntimeError, match="生产环境安全配置不完整"):
config.validate_production_security()
def test_config_routes_limit_regular_users_to_apps(client, tmp_config):
"""普通账号只能管理 Apps,不能读取或修改包含密钥的配置。"""
response = client.post("/api/users", json={
"username": "builder",
"password": "builder-password-123",
"is_admin": False,
})
assert response.status_code == 200
login = client.post("/api/auth/login", json={
"username": "builder",
"password": "builder-password-123",
})
token = login.json()["token"]
headers = {"Authorization": f"Bearer {token}"}
assert client.get("/api/config/apps", headers=headers).status_code == 200
assert client.post("/api/config/apps", json={"name": "普通用户 App"}, headers=headers).status_code == 200
assert client.get("/api/config", headers=headers).status_code == 403
assert client.get("/api/config/servers", headers=headers).status_code == 403
assert client.put("/api/config/upload", json={"mode": "oss"}, headers=headers).status_code == 403