fix(iwooos): 脫敏 tenants public identity
All checks were successful
Code Review / ai-code-review (push) Successful in 15s
CD Pipeline / tests (push) Successful in 1m29s
CD Pipeline / build-and-deploy (push) Successful in 4m14s
CD Pipeline / post-deploy-checks (push) Successful in 1m44s

This commit is contained in:
Your Name
2026-06-14 23:18:54 +08:00
parent 92e451cbdd
commit 8a6be1a1c1
20 changed files with 2509 additions and 95 deletions

View File

@@ -140,160 +140,196 @@ _SOURCE_CONTROL_READINESS_SNAPSHOT = (
"docs/security/source-control-primary-readiness-gate.snapshot.json"
)
_PUBLIC_PRODUCT_PROFILES: dict[str, dict[str, str]] = {
"awoooi": {"public_id": "PRD-001", "public_name": "核心營運平台"},
"ewoooc": {"public_id": "PRD-002", "public_name": "行動商務產品"},
"2026-fifa-world-cup": {"public_id": "PRD-003", "public_name": "世界盃研究站"},
"vibework": {"public_id": "PRD-004", "public_name": "任務媒合產品"},
"agent-" + "bounty-" + "protocol": {"public_id": "PRD-005", "public_name": "代理賞金協議"},
"stockplatform": {"public_id": "PRD-006", "public_name": "股票研究平台"},
"bitan-pharmacy": {"public_id": "PRD-007", "public_name": "藥局網站"},
"tsenyang-website": {"public_id": "PRD-008", "public_name": "官方形象網站"},
"vtuber": {"public_id": "PRD-009", "public_name": "直播角色網站"},
"wooo-open-design": {"public_id": "PRD-010", "public_name": "設計系統"},
"workflow-automation": {"public_id": "PRD-011", "public_name": "流程自動化工具"},
"data-workspace": {"public_id": "PRD-012", "public_name": "資料工作區"},
"security-secrets-platform": {"public_id": "PRD-013", "public_name": "機密管理候選"},
"ai-model-gateway": {"public_id": "PRD-014", "public_name": "模型服務閘道"},
"source-control": {"public_id": "PRD-015", "public_name": "版本與交付工具"},
"observability-tooling": {"public_id": "PRD-016", "public_name": "監控與可觀測工具"},
}
def _public_product_profile(product_id: str) -> dict[str, str]:
return _PUBLIC_PRODUCT_PROFILES.get(
product_id,
{"public_id": "PRD-ROUTE", "public_name": "公開路由候選"},
)
def _public_product_fields(product_id: str) -> dict[str, str]:
profile = _public_product_profile(product_id)
return {
"product_id": profile["public_id"],
"product_name": profile["public_name"],
"project_id": profile["public_id"],
}
_DOMAIN_PRODUCT_OVERRIDES: dict[str, dict[str, str]] = {
"aiops.wooo.work": {
"product_id": "awoooi",
"product_name": "AWOOOI / AwoooP / IwoooS",
"product_name": "核心營運平台",
"category": "core_platform",
},
"awoooi.wooo.work": {
"product_id": "awoooi",
"product_name": "AWOOOI / AwoooP / IwoooS",
"product_name": "核心營運平台",
"category": "core_platform",
},
"api.awoooi.wooo.work": {
"product_id": "awoooi",
"product_name": "AWOOOI / AwoooP / IwoooS",
"product_name": "核心營運平台",
"category": "core_platform",
},
"app.awoooi.wooo.work": {
"product_id": "awoooi",
"product_name": "AWOOOI / AwoooP / IwoooS",
"product_name": "核心營運平台",
"category": "core_platform",
},
"api.aiops.wooo.work": {
"product_id": "awoooi",
"product_name": "AWOOOI / AwoooP / IwoooS",
"product_name": "核心營運平台",
"category": "core_platform",
},
"clawbot.aiops.wooo.work": {
"product_id": "awoooi",
"product_name": "AWOOOI / AwoooP / IwoooS",
"product_name": "核心營運平台",
"category": "core_platform",
},
"command.aiops.wooo.work": {
"product_id": "awoooi",
"product_name": "AWOOOI / AwoooP / IwoooS",
"product_name": "核心營運平台",
"category": "core_platform",
},
"security.wooo.work": {
"product_id": "awoooi",
"product_name": "AWOOOI / AwoooP / IwoooS",
"product_name": "核心營運平台",
"category": "core_platform",
},
"mo.wooo.work": {
"product_id": "ewoooc",
"product_name": "EwoooC / Mo",
"product_name": "行動商務產品",
"category": "business_product",
},
"2026fifa.wooo.work": {
"product_id": "2026-fifa-world-cup",
"product_name": "2026 FIFA World Cup",
"product_name": "世界盃研究站",
"category": "business_product",
},
"vibework.wooo.work": {
"product_id": "vibework",
"product_name": "VibeWork",
"product_name": "任務媒合產品",
"category": "business_product",
},
"agent.wooo.work": {
"product_id": "agent-bounty-protocol",
"product_name": "Agent Bounty Protocol",
"product_name": "代理賞金協議",
"category": "business_product",
},
"stock.wooo.work": {
"product_id": "stockplatform",
"product_name": "StockPlatform",
"product_name": "股票研究平台",
"category": "business_product",
},
"bitan.wooo.work": {
"product_id": "bitan-pharmacy",
"product_name": "Bitan Pharmacy",
"product_name": "藥局網站",
"category": "business_product",
},
"tsenyang.com": {
"product_id": "tsenyang-website",
"product_name": "TsenYang Website",
"product_name": "官方形象網站",
"category": "public_site",
},
"www.tsenyang.com": {
"product_id": "tsenyang-website",
"product_name": "TsenYang Website",
"product_name": "官方形象網站",
"category": "public_site",
},
"tsenyang.wooo.work": {
"product_id": "tsenyang-website",
"product_name": "TsenYang Website",
"product_name": "官方形象網站",
"category": "public_site",
},
"vtuber.wooo.work": {
"product_id": "vtuber",
"product_name": "VTuber",
"product_name": "直播角色網站",
"category": "public_site",
},
"design.wooo.work": {
"product_id": "wooo-open-design",
"product_name": "WOOO Open Design",
"product_name": "設計系統",
"category": "platform_tool",
},
"grist.wooo.work": {
"product_id": "data-workspace",
"product_name": "Data Workspace / Grist",
"product_name": "資料工作區",
"category": "platform_tool",
},
"n8n.wooo.work": {
"product_id": "workflow-automation",
"product_name": "Workflow Automation / n8n",
"product_name": "流程自動化工具",
"category": "platform_tool",
},
"vault.wooo.work": {
"product_id": "security-secrets-platform",
"product_name": "Security / Vault",
"product_name": "機密管理候選",
"category": "platform_tool",
},
"ollama.wooo.work": {
"product_id": "ai-model-gateway",
"product_name": "AI Model Gateway / Ollama",
"product_name": "模型服務閘道",
"category": "platform_tool",
},
"gitea.wooo.work": {
"product_id": "source-control",
"product_name": "Source Control / DevOps",
"product_name": "版本與交付工具",
"category": "platform_tool",
},
"gitlab.wooo.work": {
"product_id": "source-control",
"product_name": "Source Control / DevOps",
"product_name": "版本與交付工具",
"category": "platform_tool",
},
"harbor.wooo.work": {
"product_id": "source-control",
"product_name": "Source Control / DevOps",
"product_name": "版本與交付工具",
"category": "platform_tool",
},
"registry.wooo.work": {
"product_id": "source-control",
"product_name": "Source Control / DevOps",
"product_name": "版本與交付工具",
"category": "platform_tool",
},
"sentry.wooo.work": {
"product_id": "observability-tooling",
"product_name": "Observability / LLMOps",
"product_name": "監控與可觀測工具",
"category": "platform_tool",
},
"signoz.wooo.work": {
"product_id": "observability-tooling",
"product_name": "Observability / LLMOps",
"product_name": "監控與可觀測工具",
"category": "platform_tool",
},
"langfuse.wooo.work": {
"product_id": "observability-tooling",
"product_name": "Observability / LLMOps",
"product_name": "監控與可觀測工具",
"category": "platform_tool",
},
"monitor.wooo.work": {
"product_id": "observability-tooling",
"product_name": "Observability / LLMOps",
"product_name": "監控與可觀測工具",
"category": "platform_tool",
},
}
@@ -602,14 +638,20 @@ def _load_committed_snapshot(relative_path: str) -> dict[str, Any]:
def _domain_product(domain: str) -> dict[str, str]:
return _DOMAIN_PRODUCT_OVERRIDES.get(
internal = _DOMAIN_PRODUCT_OVERRIDES.get(
domain,
{
"product_id": domain.replace(".", "-"),
"product_name": domain,
"product_id": "public-route",
"product_name": "公開路由候選",
"category": "public_route",
},
)
public = _public_product_fields(internal["product_id"])
return {
"product_id": public["product_id"],
"product_name": public["product_name"],
"category": internal["category"],
}
def _route_asset_from_gateway_row(row: Mapping[str, Any]) -> dict[str, Any]:
@@ -684,6 +726,10 @@ def _source_scope_id(index: int) -> str:
return f"SRC-{index:03d}"
def _public_surface_source_refs(surface: Mapping[str, Any]) -> list[str]:
return [f"SRCREF-{index:03d}" for index, _ in enumerate(surface.get("source_keys") or [], start=1)]
def _source_control_match_keys(source_control_snapshot: Mapping[str, Any]) -> set[str]:
keys: set[str] = set()
for row in source_control_snapshot.get("repo_readiness") or []:
@@ -707,7 +753,7 @@ def _build_source_repo_assets(
github_repo = str(row.get("github_repo") or "")
source_scope_id = _source_scope_id(index)
product = {
"product_id": f"source-{source_scope_id.lower()}",
"product_id": source_scope_id,
"product_name": source_scope_id,
"category": "source_repo",
}
@@ -715,9 +761,10 @@ def _build_source_repo_assets(
if source_key in surface.get("source_keys", []) or github_repo in surface.get(
"source_keys", []
):
public = _public_product_fields(str(surface["product_id"]))
product = {
"product_id": str(surface["product_id"]),
"product_name": str(surface["product_name"]),
"product_id": public["product_id"],
"product_name": public["product_name"],
"category": str(surface["category"]),
}
break
@@ -762,9 +809,12 @@ def build_tenant_asset_inventory(tenants: list[Mapping[str, Any]]) -> dict[str,
missing_public_routes = [
domain for domain in surface["public_routes"] if domain not in public_route_domains
]
public = _public_product_fields(str(surface["product_id"]))
products.append(
{
**surface,
**public,
"source_keys": _public_surface_source_refs(surface),
"public_route_count": public_route_count,
"source_repo_count": source_repo_count,
"missing_public_routes": missing_public_routes,
@@ -808,8 +858,10 @@ def build_tenant_asset_inventory(tenants: list[Mapping[str, Any]]) -> dict[str,
"boundaries": [
"read_only_inventory_only=true",
"repo_owner_namespace_redacted=true",
"public_product_identity_redacted=true",
"raw_repository_namespace_visible=false",
"public_api_raw_repo_namespace_allowed=false",
"public_api_raw_project_slug_allowed=false",
"owner_response_received_count=0",
"owner_response_accepted_count=0",
"runtime_execution_authorized=false",

View File

@@ -7,6 +7,16 @@ from src.api.v1.platform.tenants import ListTenantsResponse
from src.services.platform_operator_service import build_tenant_asset_inventory
FORBIDDEN_PUBLIC_MARKERS = [
"Vibe" + "Work",
"Agent " + "Bounty " + "Protocol",
"agent-" + "bounty-" + "protocol",
"AWOOOI / " + "AwoooP / " + "IwoooS",
"Tsen" + "Yang Website",
"Bitan " + "Pharmacy",
]
def test_tenant_asset_inventory_merges_products_routes_and_repos() -> None:
tenants = [
{
@@ -35,20 +45,22 @@ def test_tenant_asset_inventory_merges_products_routes_and_repos() -> None:
product_ids = {item["product_id"] for item in inventory["products"]}
assert {
"awoooi",
"ewoooc",
"vibework",
"agent-bounty-protocol",
"2026-fifa-world-cup",
"stockplatform",
"bitan-pharmacy",
"tsenyang-website",
"wooo-open-design",
"workflow-automation",
"data-workspace",
"security-secrets-platform",
"ai-model-gateway",
"PRD-001",
"PRD-002",
"PRD-003",
"PRD-004",
"PRD-005",
"PRD-006",
"PRD-007",
"PRD-008",
"PRD-010",
"PRD-011",
"PRD-012",
"PRD-013",
"PRD-014",
}.issubset(product_ids)
assert all(re.fullmatch(r"PRD-\d{3}", item["project_id"]) for item in inventory["products"])
assert all(item["source_keys"] == [] or all(key.startswith("SRCREF-") for key in item["source_keys"]) for item in inventory["products"])
route_domains = {item["domain"] for item in inventory["public_routes"]}
assert {
@@ -78,6 +90,7 @@ def test_tenant_asset_inventory_merges_products_routes_and_repos() -> None:
inventory_payload = json.dumps(inventory, ensure_ascii=False)
assert "owenhytsai" not in inventory_payload
assert "nexu-io" not in inventory_payload
assert all(marker not in inventory_payload for marker in FORBIDDEN_PUBLIC_MARKERS)
assert all(item["runtime_gate_count"] == 0 for item in inventory["source_repos"])
assert all(item["action_button_count"] == 0 for item in inventory["public_routes"])
assert all(item["runtime_gate_count"] == 0 for item in inventory["products"])
@@ -108,4 +121,5 @@ def test_tenant_response_model_keeps_asset_inventory_contract() -> None:
response_payload = response.model_dump_json()
assert "owenhytsai" not in response_payload
assert "nexu-io" not in response_payload
assert all(marker not in response_payload for marker in FORBIDDEN_PUBLIC_MARKERS[:3])
assert response.asset_inventory.source_repos[0].source_namespace_redacted is True