Commit 03e74bbb authored by Data Governance Dev's avatar Data Governance Dev

feat(backend): 详情接口返回 task 密码 + 守住 list/detail 可见性

旧设计:密码不进 API 响应(标榜'安全'),靠前端从匹配的 connection_preset 里拿。
问题:业务用户手动建的连接没匹配的预设 → form.password 永远空 →
     /api/connect/columns 因为缺密码连不上 → 编辑场景 cn/type 永远是 '—'/'空'。

改为:详情接口(GET /api/tasks/{id})直接返回 password 字段;列表接口不返回。

权衡:
- 明文传输:内部工具单用户部署,TLS 终端到终端,加密不加密收益相同
  (用户反正可以从 task.conn_json 复制、从前端 devtools 看)
- 真正权威的来源是 task.conn_json 里的密码(用户建任务时填的那个),
  而不是预设的密码(可能跟任务不同步)

测试 test_password_returned_in_detail_but_not_in_list 守住:
detail 接口 password 有值,list 接口 password 为 None。

如果以后需要让 list 也带,加 ?include_password=true 查询参数即可;
现在不预先暴露。
parent a07af9cc
......@@ -109,6 +109,7 @@ class TaskOut(BaseModel):
host: Optional[str] = None # 主机地址
port: Optional[str] = None # 端口
user: Optional[str] = None # 用户名
password: Optional[str] = None # 明文(内部工具;编辑场景回填用,避免每次重输)
jdbc_params: Optional[str] = None # JDBC 连接参数
schema: Optional[str] = None # Schema
oracle_client_dir: Optional[str] = None # Oracle Instant Client 路径(仅 Oracle 有效)
......@@ -253,6 +254,11 @@ def _row_to_out(db: Session, t: Task, *, include_field_list: bool = False) -> Ta
host=conn.get("host"),
port=(str(conn["port"]) if conn.get("port") is not None else None),
user=conn.get("user"),
# 密码:只在详情接口返回(编辑场景要回填;列表用不上)
# 旧设计是「不返回密码,让前端从匹配的 connection_preset 里拿」,
# 但任务不一定由预设建出来(手动填的),没有匹配预设就拿不到密码 →
# listColumns 会因为缺密码连不上。现在改为详情接口直接返回。
password=(conn.get("password") if include_field_list else None),
jdbc_params=conn.get("jdbcParams"),
schema=conn.get("schema"),
oracle_client_dir=conn.get("oracleClientDir"),
......
......@@ -288,4 +288,44 @@ def test_legacy_ai_regex_endpoint_still_works(client):
# 不强求成功(依赖 LLM key),但接口必须 200 + 结构合法
assert r.status_code == 200, r.text
body = r.json()
assert "ok" in body and "regex" in body and "note" in body
\ No newline at end of file
assert "ok" in body and "regex" in body and "note" in body
# ── 4) 密码在 list/detail 接口的可见性 ─────────────────────
def test_password_returned_in_detail_but_not_in_list(client):
"""详情接口要返回密码(编辑场景回填),列表接口不返回(避免不必要暴露)。
背景:之前为了「安全」详情接口也不返回密码,前端编辑靠 connection_preset
匹配回填,但手动建的任务没有匹配的预设 → listColumns 因为缺密码连不上。
改为详情接口返回密码(明文,内部工具不做加密)。
"""
c, _ = client
# 建一个任务,密码写在 conn_json 里
r = c.post("/api/tasks", json={
"name": "pwd-visibility-test",
"group": "身份证",
"db_type": "MySQL",
"source_table": "t_user",
"conn_json": json.dumps({
"host": "h", "port": 3306, "user": "u",
"password": "ORIGINAL_PWD_123", # ← 明文存进 conn_json
"db": "d",
}),
"fields": [{"key": "id_card", "show_default": True, "rules": []}],
})
assert r.status_code == 200, r.text
task_id = r.json()["id"]
# 1) 详情接口(GET /api/tasks/{id}):password 应有值
detail = c.get(f"/api/tasks/{task_id}")
assert detail.status_code == 200
assert detail.json()["password"] == "ORIGINAL_PWD_123", \
"详情接口必须返回密码(前端编辑场景需要回填)"
# 2) 列表接口(GET /api/tasks):password 应为 None
listing = c.get("/api/tasks")
assert listing.status_code == 200
listed = [t for t in listing.json() if t["id"] == task_id]
assert len(listed) == 1
assert listed[0]["password"] is None, \
"列表接口不应返回密码(带宽 + 减少不必要的明文暴露)"
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment