feat(web): show GitHub readiness in AwoooP runs
This commit is contained in:
@@ -4018,6 +4018,44 @@
|
||||
"ownerResponse": "Owner response received / accepted remain 0, so any further Run movement waits for human intake.",
|
||||
"activeGates": "Active runtime gates remain 0. Do not open gates or create action buttons from Run Monitor."
|
||||
}
|
||||
},
|
||||
"githubRunReadinessBoundary": {
|
||||
"title": "GitHub Primary Readiness Run Boundary",
|
||||
"subtitle": "Run Monitor mirrors that GitHub primary readiness still cannot create a security run. This is not platform run, execution router, repo creation, or primary switch authorization.",
|
||||
"badge": "Run boundary",
|
||||
"openIwooos": "Open IwoooS",
|
||||
"runRefsTitle": "GitHub Readiness Run Refs",
|
||||
"boundaryLabel": "GitHub / Run Boundary",
|
||||
"boundaryTitle": "No GitHub primary run is executable",
|
||||
"boundaryDetail": "This panel only projects source-control readiness into Run Monitor language. It does not create platform runs, connect an execution router, create GitHub repos, mutate refs, change workflows / secrets, collect secret values, switch primary, or disable Gitea.",
|
||||
"metrics": {
|
||||
"candidateRepos": {
|
||||
"label": "Candidate Repos",
|
||||
"detail": "8 candidate repos are readiness visibility only and do not create GitHub repo creation runs."
|
||||
},
|
||||
"inScopeRepos": {
|
||||
"label": "In-scope Repos",
|
||||
"detail": "7 repos still wait for owner response. Run Monitor must not open tasks for them."
|
||||
},
|
||||
"securityRuns": {
|
||||
"label": "GitHub Security Runs",
|
||||
"detail": "Currently 0. Readiness visibility is not platform run creation."
|
||||
},
|
||||
"ownerResponses": {
|
||||
"label": "Owner Responses",
|
||||
"detail": "22 response templates remain 0 received / 0 accepted."
|
||||
},
|
||||
"workflowInventory": {
|
||||
"label": "Workflow Inventory",
|
||||
"detail": "Workflow / secret name inventory is still incomplete for 7 repos."
|
||||
}
|
||||
},
|
||||
"runRefs": {
|
||||
"primaryReadiness": "The primary readiness gate still reports ready=0 and cannot become a GitHub primary run.",
|
||||
"ownerValidation": "The owner response validation rollup is still 0/22 and must not be autofilled as accepted by Run Monitor.",
|
||||
"workflowInventory": "Workflow / secret name inventory only collects names and routing. It does not collect secret values or modify GitHub secrets.",
|
||||
"rollbackAdr": "The rollback ADR has no owner-approved dry-run, so no primary switch run can start."
|
||||
}
|
||||
}
|
||||
},
|
||||
"contracts": {
|
||||
|
||||
@@ -4019,6 +4019,44 @@
|
||||
"ownerResponse": "owner response received / accepted 仍為 0,任何 Run 進一步行動都要等待人工收件。",
|
||||
"activeGates": "active runtime gates 仍為 0,不從 Run 監控頁開 gate 或建立 action button。"
|
||||
}
|
||||
},
|
||||
"githubRunReadinessBoundary": {
|
||||
"title": "GitHub Primary Readiness Run 邊界",
|
||||
"subtitle": "Run 監控同步顯示 GitHub primary readiness 仍不可產生 security run;這不是 platform run、execution router、repo 建立或 primary 切換授權。",
|
||||
"badge": "Run 邊界",
|
||||
"openIwooos": "開啟 IwoooS",
|
||||
"runRefsTitle": "GitHub readiness run refs",
|
||||
"boundaryLabel": "GitHub / Run 邊界",
|
||||
"boundaryTitle": "目前沒有 GitHub primary run 可執行",
|
||||
"boundaryDetail": "這個面板只把 source-control readiness 投影到 Run 監控語境;不建立 platform run、不接 execution router、不建立 GitHub repo、不改 refs、不改 workflow / secrets、不收 secret value、不切 primary,也不停用 Gitea。",
|
||||
"metrics": {
|
||||
"candidateRepos": {
|
||||
"label": "Candidate repos",
|
||||
"detail": "8 個候選 repo 只顯示 readiness,不會產生 GitHub repo creation run。"
|
||||
},
|
||||
"inScopeRepos": {
|
||||
"label": "In-scope repos",
|
||||
"detail": "7 個 repo 仍等待 owner response;Run 監控不得替它們開任務。"
|
||||
},
|
||||
"securityRuns": {
|
||||
"label": "GitHub security runs",
|
||||
"detail": "目前為 0;readiness visibility 不等於 platform run created。"
|
||||
},
|
||||
"ownerResponses": {
|
||||
"label": "Owner responses",
|
||||
"detail": "22 個 response templates 仍為 0 received / 0 accepted。"
|
||||
},
|
||||
"workflowInventory": {
|
||||
"label": "Workflow inventory",
|
||||
"detail": "7 個 repo 的 workflow / secret name inventory 仍未完成。"
|
||||
}
|
||||
},
|
||||
"runRefs": {
|
||||
"primaryReadiness": "Primary readiness gate 仍顯示 ready=0,不能轉成 GitHub primary run。",
|
||||
"ownerValidation": "Owner response validation rollup 仍是 0/22,不能被 Run 監控自動補成 accepted。",
|
||||
"workflowInventory": "Workflow / secret name inventory 仍只收集名稱與路由,不收 secret value、不修改 GitHub secrets。",
|
||||
"rollbackAdr": "Rollback ADR 尚未完成 owner-approved dry-run,因此不能啟動 primary switch run。"
|
||||
}
|
||||
}
|
||||
},
|
||||
"contracts": {
|
||||
|
||||
@@ -19,7 +19,9 @@ import {
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Cpu,
|
||||
GitBranch,
|
||||
ListChecks,
|
||||
Lock,
|
||||
SearchCheck,
|
||||
ShieldCheck,
|
||||
TriangleAlert,
|
||||
@@ -110,6 +112,19 @@ interface RecentEventsResponse {
|
||||
limit: number;
|
||||
}
|
||||
|
||||
type GitHubRunReadinessMetric = {
|
||||
key: string;
|
||||
value: string;
|
||||
icon: typeof Activity;
|
||||
tone: "neutral" | "warn";
|
||||
};
|
||||
|
||||
type GitHubRunReadinessRef = {
|
||||
key: string;
|
||||
name: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// 常數
|
||||
// =============================================================================
|
||||
@@ -269,6 +284,51 @@ const REMEDIATION_FILTER_OPTIONS: RemediationStatus[] = [
|
||||
"no_evidence",
|
||||
];
|
||||
|
||||
const githubRunReadinessMetrics: GitHubRunReadinessMetric[] = [
|
||||
{ key: "candidateRepos", value: "8", icon: GitBranch, tone: "neutral" },
|
||||
{ key: "inScopeRepos", value: "7", icon: ListChecks, tone: "warn" },
|
||||
{ key: "securityRuns", value: "0", icon: Activity, tone: "warn" },
|
||||
{ key: "ownerResponses", value: "0/22", icon: ShieldCheck, tone: "warn" },
|
||||
{ key: "workflowInventory", value: "0/7", icon: SearchCheck, tone: "warn" },
|
||||
];
|
||||
|
||||
const githubRunReadinessRefs: GitHubRunReadinessRef[] = [
|
||||
{
|
||||
key: "primaryReadiness",
|
||||
name: "source_control_primary_readiness_gate_v1",
|
||||
status: "ready=0",
|
||||
},
|
||||
{
|
||||
key: "ownerValidation",
|
||||
name: "source_control_owner_response_validation_rollup_v1",
|
||||
status: "0/22",
|
||||
},
|
||||
{
|
||||
key: "workflowInventory",
|
||||
name: "source_control_workflow_secret_name_inventory_v1",
|
||||
status: "0/7",
|
||||
},
|
||||
{
|
||||
key: "rollbackAdr",
|
||||
name: "source_control_primary_rollback_adr_v1",
|
||||
status: "0/7",
|
||||
},
|
||||
];
|
||||
|
||||
const githubRunReadinessBoundaries = [
|
||||
"security_run_created=false",
|
||||
"github_primary_run_created=false",
|
||||
"execution_router_linked=false",
|
||||
"repo_creation_authorized=false",
|
||||
"refs_mutation_authorized=false",
|
||||
"workflow_secret_modification_authorized=false",
|
||||
"secret_value_collection_allowed=false",
|
||||
"github_primary_switch_authorized=false",
|
||||
"gitea_disablement_authorized=false",
|
||||
"runtime_execution_authorized=false",
|
||||
"action_buttons_allowed=false",
|
||||
];
|
||||
|
||||
function getRunLane(state: RunState): RunLane {
|
||||
if (state === "pending") return "intake";
|
||||
if (state === "waiting_tool") return "diagnosis";
|
||||
@@ -703,6 +763,111 @@ function SecurityRunStateCandidatePanel() {
|
||||
);
|
||||
}
|
||||
|
||||
function GitHubRunReadinessBoundaryPanel() {
|
||||
const t = useTranslations("awooop.runs.githubRunReadinessBoundary");
|
||||
|
||||
return (
|
||||
<section className="overflow-hidden border border-[#e0ddd4] bg-white">
|
||||
<div className="flex flex-wrap items-start justify-between gap-3 border-b border-[#e0ddd4] bg-[#faf9f3] px-4 py-3">
|
||||
<div className="flex min-w-0 items-start gap-2">
|
||||
<GitBranch className="mt-0.5 h-4 w-4 shrink-0 text-[#d97757]" aria-hidden="true" />
|
||||
<div className="min-w-0">
|
||||
<h3 className="text-sm font-semibold text-[#141413]">{t("title")}</h3>
|
||||
<p className="mt-1 max-w-3xl text-xs leading-5 text-[#77736a]">{t("subtitle")}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span className="inline-flex border border-[#d9b36f] bg-[#fff7e8] px-2 py-0.5 text-xs font-semibold text-[#8a5a08]">
|
||||
{t("badge")}
|
||||
</span>
|
||||
<Link
|
||||
href="/iwooos"
|
||||
className="inline-flex items-center gap-2 border border-[#d8d3c7] bg-white px-3 py-1.5 text-xs font-semibold text-[#141413] hover:border-[#d97757]"
|
||||
>
|
||||
{t("openIwooos")}
|
||||
<ArrowRight className="h-3.5 w-3.5 text-[#77736a]" aria-hidden="true" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-px bg-[#e0ddd4] md:grid-cols-2 xl:grid-cols-5">
|
||||
{githubRunReadinessMetrics.map((metric) => {
|
||||
const Icon = metric.icon;
|
||||
return (
|
||||
<div key={metric.key} className="min-h-[122px] bg-white px-4 py-3">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
<p className="text-xs font-semibold text-[#77736a]">
|
||||
{t(`metrics.${metric.key}.label` as never)}
|
||||
</p>
|
||||
<p className="mt-2 break-words font-mono text-2xl font-semibold text-[#141413]">
|
||||
{metric.value}
|
||||
</p>
|
||||
</div>
|
||||
<span
|
||||
className={cn(
|
||||
"flex h-8 w-8 shrink-0 items-center justify-center border",
|
||||
metric.tone === "warn" && "border-[#d9b36f] bg-[#fff7e8] text-[#8a5a08]",
|
||||
metric.tone === "neutral" && "border-[#d8d3c7] bg-[#faf9f3] text-[#5f5b52]"
|
||||
)}
|
||||
>
|
||||
<Icon className="h-4 w-4" aria-hidden="true" />
|
||||
</span>
|
||||
</div>
|
||||
<p className="mt-3 text-xs leading-5 text-[#5f5b52]">
|
||||
{t(`metrics.${metric.key}.detail` as never)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="grid min-w-0 gap-4 p-4 xl:grid-cols-[1.1fr_0.9fr]">
|
||||
<div className="min-w-0 border border-[#e0ddd4] bg-white">
|
||||
<div className="border-b border-[#e0ddd4] bg-[#faf9f3] px-4 py-3 text-xs font-semibold text-[#141413]">
|
||||
{t("runRefsTitle")}
|
||||
</div>
|
||||
<div className="divide-y divide-[#eee9dd]">
|
||||
{githubRunReadinessRefs.map((ref) => (
|
||||
<div key={ref.key} className="grid gap-3 px-4 py-3 md:grid-cols-[minmax(0,1fr)_96px]">
|
||||
<div className="min-w-0">
|
||||
<p className="break-all font-mono text-xs font-semibold text-[#141413]">
|
||||
{ref.name}
|
||||
</p>
|
||||
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
||||
{t(`runRefs.${ref.key}` as never)}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<span className="inline-flex border border-[#d9b36f] bg-[#fff7e8] px-2 py-0.5 font-mono text-xs font-semibold text-[#8a5a08]">
|
||||
{ref.status}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="min-w-0 border border-[#e0ddd4] bg-[#faf9f3] px-4 py-3">
|
||||
<div className="flex items-start gap-2">
|
||||
<Lock className="mt-0.5 h-4 w-4 shrink-0 text-[#8a5a08]" aria-hidden="true" />
|
||||
<div>
|
||||
<p className="text-xs font-semibold text-[#77736a]">{t("boundaryLabel")}</p>
|
||||
<p className="mt-2 text-sm font-semibold text-[#141413]">{t("boundaryTitle")}</p>
|
||||
</div>
|
||||
</div>
|
||||
<p className="mt-2 text-xs leading-5 text-[#5f5b52]">{t("boundaryDetail")}</p>
|
||||
<div className="mt-4 grid gap-2 break-all font-mono text-xs text-[#141413]">
|
||||
{githubRunReadinessBoundaries.map((boundary) => (
|
||||
<span key={boundary}>{boundary}</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Main Component
|
||||
// =============================================================================
|
||||
@@ -944,6 +1109,8 @@ export default function RunsPage() {
|
||||
|
||||
<SecurityRunStateCandidatePanel />
|
||||
|
||||
<GitHubRunReadinessBoundaryPanel />
|
||||
|
||||
<GroupedAlertEventsPanel events={groupedEvents} />
|
||||
|
||||
{/* Filters */}
|
||||
|
||||
Reference in New Issue
Block a user