feat(governance): add agent market automation surfaces
Some checks failed
Some checks failed
This commit is contained in:
@@ -4,19 +4,57 @@
|
||||
|
||||
設計原則:
|
||||
- Python asyncio.create_task() 自動繼承父任務的 ContextVar 值
|
||||
- startup handler 設一次 PROJECT_ID.set("awoooi"),所有 31 個 loop 自動繼承
|
||||
- get_db_context() 讀此 contextvar 作為 fallback,確保 RLS SET LOCAL 正確
|
||||
- 起始流程不再在 lifespan 強制寫入固定 PROJECT_ID;呼叫端需明確提供 project_id
|
||||
- get_db_context() 僅接受明確參數或已注入的 contextvar 作為 tenant 來源
|
||||
- 多租戶未來:呼叫端傳入不同 project_id 即可隔離,無需改 loop 本體
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from contextvars import ContextVar
|
||||
from contextvars import ContextVar, Token
|
||||
|
||||
# 追蹤當前非同步任務的 project_id
|
||||
# default="awoooi" 確保未設時也能正常查詢(RLS fail-open 保護)
|
||||
PROJECT_ID: ContextVar[str] = ContextVar("project_id", default="awoooi")
|
||||
# Fail-Closed: 移除 default="awoooi",進 DB 路徑需要明確租戶標籤
|
||||
PROJECT_ID: ContextVar[str | None] = ContextVar("project_id")
|
||||
PROJECT_ID_SOURCE: ContextVar[str | None] = ContextVar("project_id_source")
|
||||
PROJECT_ID_REQUEST_ID: ContextVar[str | None] = ContextVar("project_id_request_id")
|
||||
|
||||
|
||||
def get_current_project_id() -> str:
|
||||
def set_project_context(
|
||||
project_id: str | None,
|
||||
source: str = "runtime",
|
||||
request_id: str | None = None,
|
||||
) -> tuple[Token[str | None], Token[str | None], Token[str | None]]:
|
||||
"""
|
||||
設定當前 request/context 的 project 上下文,並回傳 ContextVar token 供 restore。
|
||||
"""
|
||||
return (
|
||||
PROJECT_ID.set(project_id),
|
||||
PROJECT_ID_SOURCE.set(source),
|
||||
PROJECT_ID_REQUEST_ID.set(request_id),
|
||||
)
|
||||
|
||||
|
||||
def clear_project_context(tokens: tuple[Token[str | None], Token[str | None], Token[str | None]]) -> None:
|
||||
"""清除 request 上下文,回復前一個 ContextVar 狀態。"""
|
||||
PROJECT_ID_REQUEST_ID.reset(tokens[2])
|
||||
PROJECT_ID_SOURCE.reset(tokens[1])
|
||||
PROJECT_ID.reset(tokens[0])
|
||||
|
||||
|
||||
def get_project_context() -> dict[str, str | None]:
|
||||
"""取得目前上下文快照(可直接寫入 audit log)。"""
|
||||
return {
|
||||
"project_id": PROJECT_ID.get(None),
|
||||
"source": PROJECT_ID_SOURCE.get(None),
|
||||
"request_id": PROJECT_ID_REQUEST_ID.get(None),
|
||||
}
|
||||
|
||||
|
||||
def get_current_project_id() -> str | None:
|
||||
"""取得當前任務的 project_id(給 service 層使用)"""
|
||||
return PROJECT_ID.get()
|
||||
return PROJECT_ID.get(None)
|
||||
|
||||
|
||||
def get_current_project_context() -> dict[str, str | None]:
|
||||
"""取得可追溯上下文(同 get_project_context,保留 API 命名)。"""
|
||||
return get_project_context()
|
||||
|
||||
Reference in New Issue
Block a user