feat(web): show IwoooS security contracts in AwoooP
This commit is contained in:
@@ -3764,6 +3764,34 @@
|
||||
"item4": "Open the AwoooP work map"
|
||||
}
|
||||
},
|
||||
"contracts": {
|
||||
"securityContractCandidate": {
|
||||
"title": "IwoooS Security Contract Read-only Candidate",
|
||||
"subtitle": "The contract dashboard only shows the schema, snapshot, and guard semantics that IwoooS / security mirror currently depends on. This is not contract publishing and does not trigger a runtime gate.",
|
||||
"badge": "Contract candidate",
|
||||
"contractRefsTitle": "Read-only contract refs",
|
||||
"boundaryLabel": "Contract Boundary",
|
||||
"boundaryTitle": "No security contract is publishable here",
|
||||
"boundaryDetail": "This panel does not publish contract revisions, change contract lifecycle, write to the platform contracts API, call GitHub / Gitea / Kali, or add scan, execute, deploy, primary switch, or refs actions.",
|
||||
"openIwooos": "Open IwoooS",
|
||||
"metrics": {
|
||||
"totalContracts": "Total contracts",
|
||||
"totalContractsDetail": "Security mirror currently rolls up 36 primary contracts.",
|
||||
"readyForMirror": "Ready for mirror",
|
||||
"readyForMirrorDetail": "33 ready, 2 partial, 1 contract-only, and 0 blocked.",
|
||||
"partialReady": "Partial",
|
||||
"partialReadyDetail": "Remaining gaps are owner response, payload ingestion, and source-control owner evidence.",
|
||||
"activeRuntimeGates": "Active runtime gates",
|
||||
"activeRuntimeGatesDetail": "Still 0; contract visibility is not runtime enforcement."
|
||||
},
|
||||
"contractRefs": {
|
||||
"statusRollup": "The shared state entrypoint for AwoooP and the Security Session; it only rolls up progress and safe gates.",
|
||||
"postureProjection": "The projection contract for IwoooS posture, host coverage, owner response focus, and forbidden actions.",
|
||||
"ownerValidation": "The S4.9-S4.12 owner response received / accepted separation and reviewer check semantics.",
|
||||
"rolloutPolicy": "The low-friction, observe-first rollout policy with owner review before blocking."
|
||||
}
|
||||
}
|
||||
},
|
||||
"approvals": {
|
||||
"securityOwnerResponseGate": {
|
||||
"title": "IwoooS Owner Response Read-only Review Focus",
|
||||
|
||||
@@ -3765,6 +3765,34 @@
|
||||
"item4": "查看 AwoooP 工作鏈路地圖"
|
||||
}
|
||||
},
|
||||
"contracts": {
|
||||
"securityContractCandidate": {
|
||||
"title": "IwoooS 資安契約只讀候選",
|
||||
"subtitle": "合約儀表板只顯示 IwoooS / security mirror 目前依賴的 schema、snapshot 與 guard 口徑;這不是 contract publish,也不會觸發 runtime gate。",
|
||||
"badge": "契約候選",
|
||||
"contractRefsTitle": "只讀 contract refs",
|
||||
"boundaryLabel": "合約邊界",
|
||||
"boundaryTitle": "目前沒有可發布的資安合約",
|
||||
"boundaryDetail": "這個面板不發布 contract revision、不改合約生命週期、不寫入 platform contracts API、不呼叫 GitHub / Gitea / Kali,也不新增 scan、execute、deploy、primary switch 或 refs action。",
|
||||
"openIwooos": "開啟 IwoooS",
|
||||
"metrics": {
|
||||
"totalContracts": "總 contracts",
|
||||
"totalContractsDetail": "security mirror 目前彙整 36 個主要 contract。",
|
||||
"readyForMirror": "Ready for mirror",
|
||||
"readyForMirrorDetail": "33 個 ready、2 個 partial、1 個 contract-only、0 blocked。",
|
||||
"partialReady": "Partial",
|
||||
"partialReadyDetail": "缺口仍集中在 owner response、payload ingestion 與 source-control owner evidence。",
|
||||
"activeRuntimeGates": "Active runtime gates",
|
||||
"activeRuntimeGatesDetail": "仍為 0;合約可見性不等於 runtime enforcement。"
|
||||
},
|
||||
"contractRefs": {
|
||||
"statusRollup": "AwoooP / Security Session 的共同狀態入口,只彙整進度與安全 gate。",
|
||||
"postureProjection": "IwoooS 前端態勢、主機覆蓋、owner response focus 與禁止動作的投影契約。",
|
||||
"ownerValidation": "S4.9-S4.12 owner response received / accepted 分離與 reviewer 檢查口徑。",
|
||||
"rolloutPolicy": "低摩擦、observe-first、owner review before blocking 的 rollout policy。"
|
||||
}
|
||||
}
|
||||
},
|
||||
"approvals": {
|
||||
"securityOwnerResponseGate": {
|
||||
"title": "IwoooS Owner Response 只讀審查焦點",
|
||||
|
||||
@@ -6,12 +6,16 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import {
|
||||
ArrowRight,
|
||||
FileText,
|
||||
RefreshCw,
|
||||
AlertCircle,
|
||||
Filter,
|
||||
ChevronDown,
|
||||
ShieldCheck,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@@ -136,6 +140,112 @@ function ContractRow({ contract }: { contract: Contract }) {
|
||||
);
|
||||
}
|
||||
|
||||
function SecurityContractCandidatePanel() {
|
||||
const t = useTranslations("awooop.contracts.securityContractCandidate");
|
||||
const metrics = [
|
||||
{
|
||||
label: t("metrics.totalContracts"),
|
||||
value: "36",
|
||||
detail: t("metrics.totalContractsDetail"),
|
||||
},
|
||||
{
|
||||
label: t("metrics.readyForMirror"),
|
||||
value: "33",
|
||||
detail: t("metrics.readyForMirrorDetail"),
|
||||
},
|
||||
{
|
||||
label: t("metrics.partialReady"),
|
||||
value: "2",
|
||||
detail: t("metrics.partialReadyDetail"),
|
||||
},
|
||||
{
|
||||
label: t("metrics.activeRuntimeGates"),
|
||||
value: "0",
|
||||
detail: t("metrics.activeRuntimeGatesDetail"),
|
||||
},
|
||||
];
|
||||
const contracts = [
|
||||
{
|
||||
name: "security_mirror_status_rollup_v1",
|
||||
detail: t("contractRefs.statusRollup"),
|
||||
},
|
||||
{
|
||||
name: "iwooos_posture_projection_v1",
|
||||
detail: t("contractRefs.postureProjection"),
|
||||
},
|
||||
{
|
||||
name: "source_control_owner_response_validation_rollup_v1",
|
||||
detail: t("contractRefs.ownerValidation"),
|
||||
},
|
||||
{
|
||||
name: "security_rollout_policy_v1",
|
||||
detail: t("contractRefs.rolloutPolicy"),
|
||||
},
|
||||
];
|
||||
|
||||
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 items-start gap-2">
|
||||
<ShieldCheck className="mt-0.5 h-4 w-4 text-[#d97757]" aria-hidden="true" />
|
||||
<div>
|
||||
<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>
|
||||
<span className="inline-flex border border-[#9bb6d9] bg-[#eef5ff] px-2 py-0.5 text-xs font-semibold text-[#1f5b9b]">
|
||||
{t("badge")}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-px bg-[#e0ddd4] md:grid-cols-2 xl:grid-cols-4">
|
||||
{metrics.map((item) => (
|
||||
<div key={item.label} className="bg-white px-4 py-3">
|
||||
<p className="text-xs font-semibold text-[#77736a]">{item.label}</p>
|
||||
<p className="mt-2 font-mono text-2xl font-semibold text-[#141413]">{item.value}</p>
|
||||
<p className="mt-2 text-xs leading-5 text-[#5f5b52]">{item.detail}</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("contractRefsTitle")}
|
||||
</div>
|
||||
<div className="divide-y divide-[#eee9dd]">
|
||||
{contracts.map((item) => (
|
||||
<div key={item.name} className="px-4 py-3">
|
||||
<p className="break-all font-mono text-xs font-semibold text-[#141413]">{item.name}</p>
|
||||
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">{item.detail}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="min-w-0 border border-[#e0ddd4] bg-[#faf9f3] px-4 py-3">
|
||||
<p className="text-xs font-semibold text-[#77736a]">{t("boundaryLabel")}</p>
|
||||
<p className="mt-2 text-sm font-semibold text-[#141413]">{t("boundaryTitle")}</p>
|
||||
<p className="mt-2 text-xs leading-5 text-[#5f5b52]">{t("boundaryDetail")}</p>
|
||||
<div className="mt-4 grid gap-2 font-mono text-xs text-[#141413]">
|
||||
<span>contract_publish_authorized=false</span>
|
||||
<span>contract_mutation_authorized=false</span>
|
||||
<span>runtime_execution_authorized=false</span>
|
||||
<span>action_buttons_allowed=false</span>
|
||||
</div>
|
||||
<Link
|
||||
href="/iwooos"
|
||||
className="mt-4 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>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Main Component
|
||||
// =============================================================================
|
||||
@@ -206,6 +316,8 @@ export default function ContractsPage() {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<SecurityContractCandidatePanel />
|
||||
|
||||
{/* Filters */}
|
||||
<div className="flex items-center gap-3 border border-[#e0ddd4] bg-white p-4">
|
||||
<Filter className="w-4 h-4 text-muted-foreground flex-shrink-0" aria-hidden="true" />
|
||||
|
||||
Reference in New Issue
Block a user