fix(awooop): 遮罩前台專案與代理敏感識別
All checks were successful
Code Review / ai-code-review (push) Successful in 14s
CD Pipeline / tests (push) Successful in 1m30s
CD Pipeline / build-and-deploy (push) Successful in 4m46s
CD Pipeline / post-deploy-checks (push) Successful in 1m34s

This commit is contained in:
Your Name
2026-06-15 07:10:47 +08:00
parent e2ad14d34b
commit 9c4e754d33
8 changed files with 201 additions and 47 deletions

View File

@@ -75,6 +75,86 @@ export function publicContractText(value: string): string {
return labels[value] ?? "已脫敏只讀證據參照";
}
const PUBLIC_PROJECT_NAMES: Record<string, string> = {
"agent-bounty-protocol": "代理獎勵協議",
"awoooi": "核心營運平台",
"awooooi": "核心營運平台",
"bitan": "藥局服務前台",
"bitan-pharmacy": "藥局服務平台",
"clawbot-v5": "自動化助理平台",
"ewoooc": "行動商務平台",
"mo": "行動商務前台",
"open-design": "設計系統",
"source-control": "版本控管範圍",
"tsenyang-website": "品牌網站",
"vibework": "工作協作產品",
"wooo-aiops": "AI 維運平台",
"wooo-infra-config": "基礎設施設定",
};
const PUBLIC_AGENT_NAMES: Record<string, string> = {
"codex": "程式修正代理",
"openclaw": "決策分析代理",
"nemotron": "推理評估代理",
"hermes": "通訊協作代理",
"elephantalph": "資料評估代理",
"elephantalpha": "資料評估代理",
};
const RAW_REPOSITORY_IDENTIFIER_RE = /\b[a-z0-9][a-z0-9-]{1,}\/[A-Za-z0-9._-]+\b/;
const INTERNAL_CODE_RE = /^[a-z][a-z0-9]*(?:[_:.-][a-z0-9]+){1,}$/i;
const CJK_TEXT_RE = /[\u3400-\u9fff]/;
function normalizedIdentifier(value: string | null | undefined): string {
return String(value ?? "").trim().toLowerCase();
}
function hasUnsafePublicIdentifier(value: string): boolean {
const normalized = value.toLowerCase();
return (
RAW_REPOSITORY_IDENTIFIER_RE.test(value) ||
normalized.includes("owen" + "hytsai") ||
normalized.includes("nexu" + "-io") ||
normalized.includes("blocked" + "_waiting_") ||
normalized.includes("blockers" + "=") ||
normalized.includes("github.com")
);
}
export function publicProjectText(value: string | null | undefined, fallback = "已脫敏專案"): string {
const raw = String(value ?? "").trim();
if (!raw) return fallback;
const normalized = normalizedIdentifier(raw);
const key = normalized.split("/").pop() ?? normalized;
if (PUBLIC_PROJECT_NAMES[normalized]) return PUBLIC_PROJECT_NAMES[normalized];
if (PUBLIC_PROJECT_NAMES[key]) return PUBLIC_PROJECT_NAMES[key];
if (!hasUnsafePublicIdentifier(raw) && CJK_TEXT_RE.test(raw)) return raw;
return fallback;
}
export function publicAgentText(value: string | null | undefined, fallback = "已脫敏執行代理"): string {
const raw = String(value ?? "").trim();
if (!raw) return fallback;
const normalized = normalizedIdentifier(raw);
const knownKey = Object.keys(PUBLIC_AGENT_NAMES).find((key) => normalized.includes(key));
if (knownKey) return PUBLIC_AGENT_NAMES[knownKey];
if (!hasUnsafePublicIdentifier(raw) && CJK_TEXT_RE.test(raw)) return raw;
return fallback;
}
export function publicInternalCodeSummary(
values: Array<string | null | undefined> | string | null | undefined,
emptyLabel = "無公開阻塞項"
): string {
const items = Array.isArray(values) ? values.filter(Boolean) : [values].filter(Boolean);
if (items.length === 0) return emptyLabel;
const readable = items
.map((item) => String(item ?? "").trim())
.filter((item) => item && !hasUnsafePublicIdentifier(item) && CJK_TEXT_RE.test(item) && !INTERNAL_CODE_RE.test(item));
if (readable.length > 0) return readable.slice(0, 3).join("、");
return `已脫敏狀態 ${items.length}`;
}
export function redactPublicIdentifier(value: string): string {
if (value.includes("actions.runner.")) return "已脫敏 runner systemd 服務";
return value.replace(/\b[a-z0-9][a-z0-9-]{2,}\/[A-Za-z0-9._-]+\b/g, "已脫敏專案來源");