feat(iwooos): expose Wazuh owner evidence preflight
This commit is contained in:
@@ -40,6 +40,8 @@ import {
|
||||
type IwoooSSecurityControlCoverageResponse,
|
||||
type IwoooSWazuhLiveMetadataGateItem,
|
||||
type IwoooSWazuhLiveMetadataGateResponse,
|
||||
type IwoooSWazuhOwnerEvidencePreflightItem,
|
||||
type IwoooSWazuhOwnerEvidencePreflightResponse,
|
||||
} from '@/lib/api-client'
|
||||
|
||||
type PostureMetric = {
|
||||
@@ -2365,14 +2367,6 @@ const wazuhLiveMetadataEnvGateBoundaries = [
|
||||
'not_authorization=true',
|
||||
] as const
|
||||
|
||||
const wazuhOwnerEvidencePreflightSummary = [
|
||||
{ key: 'fields', value: '23', icon: ClipboardCheck, tone: 'steady' },
|
||||
{ key: 'aliases', value: '6', icon: Server, tone: 'warn' },
|
||||
{ key: 'checks', value: '10', icon: ListChecks, tone: 'steady' },
|
||||
{ key: 'received', value: '0', icon: FileWarning, tone: 'locked' },
|
||||
{ key: 'accepted', value: '0', icon: Lock, tone: 'locked' },
|
||||
] as const
|
||||
|
||||
const wazuhOwnerEvidencePreflightItems: WazuhOwnerEvidencePreflightItem[] = [
|
||||
{ key: 'scopeAliases', check: 'EV-0', state: '6 個別名', icon: Server, tone: 'warn' },
|
||||
{ key: 'registryCounts', check: 'EV-1', state: '待脫敏計數', icon: Server, tone: 'warn' },
|
||||
@@ -2384,14 +2378,25 @@ const wazuhOwnerEvidencePreflightItems: WazuhOwnerEvidencePreflightItem[] = [
|
||||
{ key: 'runtimeBoundary', check: 'EV-7', state: '不開執行', icon: Lock, tone: 'locked' },
|
||||
] as const
|
||||
|
||||
const wazuhOwnerEvidencePreflightItemKeyById: Record<IwoooSWazuhOwnerEvidencePreflightItem['item_id'], WazuhOwnerEvidencePreflightItem['key']> = {
|
||||
scope_aliases: 'scopeAliases',
|
||||
registry_counts: 'registryCounts',
|
||||
per_host_matrix: 'perHostMatrix',
|
||||
time_window: 'timeWindow',
|
||||
health_refs: 'healthRefs',
|
||||
redaction: 'redaction',
|
||||
owner_decision: 'ownerDecision',
|
||||
runtime_boundary: 'runtimeBoundary',
|
||||
}
|
||||
|
||||
const wazuhOwnerEvidencePreflightBoundaries = [
|
||||
'wazuh_agent_visibility_owner_evidence_preflight_visible=true',
|
||||
'wazuh_agent_visibility_owner_evidence_required_field_count=23',
|
||||
'wazuh_agent_visibility_owner_evidence_reviewer_check_count=10',
|
||||
'wazuh_agent_visibility_owner_evidence_required_field_count=28',
|
||||
'wazuh_agent_visibility_owner_evidence_reviewer_check_count=15',
|
||||
'wazuh_agent_visibility_owner_evidence_expected_scope_alias_count=6',
|
||||
'wazuh_agent_visibility_owner_evidence_per_host_required_field_count=9',
|
||||
'wazuh_agent_visibility_owner_evidence_outcome_lane_count=5',
|
||||
'wazuh_agent_visibility_owner_evidence_forbidden_payload_count=18',
|
||||
'wazuh_agent_visibility_owner_evidence_outcome_lane_count=8',
|
||||
'wazuh_agent_visibility_owner_evidence_forbidden_payload_count=22',
|
||||
'wazuh_agent_visibility_owner_evidence_registry_export_received_count=0',
|
||||
'wazuh_agent_visibility_owner_evidence_registry_export_accepted_count=0',
|
||||
'wazuh_agent_visibility_owner_evidence_received_count=0',
|
||||
@@ -9115,6 +9120,92 @@ function IwoooSWazuhLiveMetadataEnvGateBoard() {
|
||||
function IwoooSWazuhOwnerEvidencePreflightBoard() {
|
||||
const t = useTranslations('iwooos.wazuhOwnerEvidencePreflight')
|
||||
const textWrap = { overflowWrap: 'anywhere' as const, wordBreak: 'break-word' as const }
|
||||
const [data, setData] = useState<IwoooSWazuhOwnerEvidencePreflightResponse | null>(null)
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [failed, setFailed] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
let mounted = true
|
||||
|
||||
async function loadPreflight() {
|
||||
setLoading(true)
|
||||
setFailed(false)
|
||||
try {
|
||||
const payload = await apiClient.getIwoooSWazuhOwnerEvidencePreflight()
|
||||
if (mounted) {
|
||||
setData(payload)
|
||||
}
|
||||
} catch {
|
||||
if (mounted) {
|
||||
setData(null)
|
||||
setFailed(true)
|
||||
}
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadPreflight()
|
||||
return () => {
|
||||
mounted = false
|
||||
}
|
||||
}, [])
|
||||
|
||||
const summary = data?.summary
|
||||
const summaryItems = [
|
||||
{
|
||||
key: 'fields',
|
||||
value: summary ? String(summary.required_field_count) : loading ? '...' : '28',
|
||||
icon: ClipboardCheck,
|
||||
tone: 'steady',
|
||||
},
|
||||
{
|
||||
key: 'aliases',
|
||||
value: summary ? String(summary.expected_scope_alias_count) : loading ? '...' : '6',
|
||||
icon: Server,
|
||||
tone: 'warn',
|
||||
},
|
||||
{
|
||||
key: 'checks',
|
||||
value: summary ? String(summary.reviewer_check_count) : loading ? '...' : '15',
|
||||
icon: ListChecks,
|
||||
tone: 'steady',
|
||||
},
|
||||
{
|
||||
key: 'received',
|
||||
value: summary ? String(summary.owner_evidence_received_count) : loading ? '...' : '0',
|
||||
icon: FileWarning,
|
||||
tone: 'locked',
|
||||
},
|
||||
{
|
||||
key: 'accepted',
|
||||
value: summary ? String(summary.owner_evidence_accepted_count) : loading ? '...' : '0',
|
||||
icon: Lock,
|
||||
tone: 'locked',
|
||||
},
|
||||
] as const
|
||||
const preflightItems = data?.items?.length
|
||||
? data.items.map(item => {
|
||||
const key = wazuhOwnerEvidencePreflightItemKeyById[item.item_id]
|
||||
const fallback = wazuhOwnerEvidencePreflightItems.find(candidate => candidate.key === key)
|
||||
return {
|
||||
key,
|
||||
check: item.check,
|
||||
state: t(`states.${item.state_key}` as never),
|
||||
icon: fallback?.icon ?? FileWarning,
|
||||
tone: item.tone,
|
||||
}
|
||||
})
|
||||
: wazuhOwnerEvidencePreflightItems
|
||||
const boundaryMarkers = data?.boundary_markers?.length
|
||||
? data.boundary_markers
|
||||
: loading
|
||||
? [t('loadingBoundary')]
|
||||
: wazuhOwnerEvidencePreflightBoundaries
|
||||
const statusText = loading ? t('status.loading') : failed ? t('status.failed') : t('status.ready')
|
||||
const statusTone: 'steady' | 'warn' | 'locked' = loading || failed ? 'warn' : 'locked'
|
||||
|
||||
return (
|
||||
<section
|
||||
@@ -9132,10 +9223,14 @@ function IwoooSWazuhOwnerEvidencePreflightBoard() {
|
||||
<p style={{ fontSize: 12, color: '#315a74', margin: '6px 0 0', lineHeight: 1.55, ...textWrap }}>
|
||||
{t('subtitle')}
|
||||
</p>
|
||||
<div style={{ marginTop: 8, display: 'inline-flex', alignItems: 'center', gap: 8, color: toneColors[statusTone], fontSize: 12, fontWeight: 700, ...textWrap }}>
|
||||
<ToneDot tone={statusTone} />
|
||||
{statusText}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(126px, 1fr))', gap: 8 }}>
|
||||
{wazuhOwnerEvidencePreflightSummary.map(item => {
|
||||
{summaryItems.map(item => {
|
||||
const Icon = item.icon
|
||||
return (
|
||||
<div key={item.key} style={{ border: '0.5px solid #c8dbea', borderRadius: 8, padding: 12, background: '#fff' }}>
|
||||
@@ -9163,7 +9258,7 @@ function IwoooSWazuhOwnerEvidencePreflightBoard() {
|
||||
gap: 10,
|
||||
}}
|
||||
>
|
||||
{wazuhOwnerEvidencePreflightItems.map(item => {
|
||||
{preflightItems.map(item => {
|
||||
const Icon = item.icon
|
||||
return (
|
||||
<div
|
||||
@@ -9219,7 +9314,7 @@ function IwoooSWazuhOwnerEvidencePreflightBoard() {
|
||||
{t('boundaryIntro')}
|
||||
</p>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(230px, 1fr))', gap: 6 }}>
|
||||
{wazuhOwnerEvidencePreflightBoundaries.map(item => (
|
||||
{boundaryMarkers.map(item => (
|
||||
<code
|
||||
key={item}
|
||||
style={{
|
||||
|
||||
Reference in New Issue
Block a user