// evaluation-nist-engine.jsx — Verigo Global: NIST CSF v2.0 readiness evaluation engine
// All six functions are assessed regardless of tier; tier shapes recommendations.
// Exposes window.EVAL_NIST
const { V: GV, MAXW: GMW, FONT: GFT } = window;
// Compute subcategory counts per function from NIST_FUNCS global (loaded first by data file)
const N_FN_COUNTS = {};
(function(){ NIST_FUNCS.forEach(f=>{ N_FN_COUNTS[f.fn]=f.cats.reduce((a,c)=>a+c.items.length,0); }); })();
/* ── QUESTION BANK — 6 functions × 3 questions, tagged with CSF subcategory IDs ── */
const NIST_Q = [
{ fn:'GV', name:'Govern', icon:'briefcase', docs:['Cybersecurity Policy','Organizational Risk Management Policy','Cybersecurity Roles & Responsibilities Policy'], q:[
['GV.OC-01','The organizational mission is understood and informs how cybersecurity risk is prioritized.'],
['GV.RM-02','Cybersecurity risk appetite and risk tolerance statements are established, communicated, and maintained.'],
['GV.SC-05','Requirements to address cybersecurity risks in supply chains are established and integrated into contracts.'],
]},
{ fn:'ID', name:'Identify', icon:'search', docs:['Asset Management Policy','Vulnerability Management Policy'], q:[
['ID.AM-01','Inventories of hardware and software managed by the organization are established and maintained.'],
['ID.RA-01','Vulnerabilities in assets are identified, validated, and recorded.'],
['ID.IM-01','Improvements are identified from security evaluations, tests, and exercises.'],
]},
{ fn:'PR', name:'Protect', icon:'shield', docs:['Identity & Access Management Policy','Data Security Policy','Platform & Infrastructure Security Policy','Security Awareness & Training Policy'], q:[
['PR.AA-01','Identities and credentials for authorized users, services, and hardware are managed.'],
['PR.DS-01','The confidentiality, integrity, and availability of data at rest are protected.'],
['PR.PS-01','Configuration management practices are established and applied across systems.'],
]},
{ fn:'DE', name:'Detect', icon:'activity', docs:['Continuous Monitoring Policy','Security Monitoring & Alerting Procedure'], q:[
['DE.CM-01','Networks and network services are monitored to find potentially adverse events.'],
['DE.AE-03','Information from multiple sources is correlated to understand the scope of adverse events.'],
['DE.AE-08','Incidents are declared when adverse events meet the defined incident criteria.'],
]},
{ fn:'RS', name:'Respond', icon:'zap', docs:['Incident Response Policy','Incident Response Procedure'], q:[
['RS.MA-01','The incident response plan is executed in coordination with relevant third parties.'],
['RS.AN-03','Analysis is performed to establish what occurred and the root cause of the incident.'],
['RS.MI-01','Incidents are contained to limit their impact on operations.'],
]},
{ fn:'RC', name:'Recover', icon:'refresh', docs:['Business Continuity & Recovery Policy','Business Continuity & Recovery Testing Procedure'], q:[
['RC.RP-01','The recovery portion of the incident response plan is executed once initiated.'],
['RC.RP-05','The integrity of restored assets is verified and normal operating status is confirmed.'],
['RC.CO-03','Recovery activities and progress are communicated to designated internal and external stakeholders.'],
]},
];
const NIST_TIER_LABELS = { tier1:'Tier 1 · Partial', tier2:'Tier 2 · Risk Informed', tier3:'Tier 3 · Repeatable', tier4:'Tier 4 · Adaptive' };
function nSectionsForTier(tier) {
// All 6 functions are always assessed; tier shapes reco but not sections.
const lv = (tier==='tier1'||tier==='tier2'||tier==='tier3'||tier==='tier4') ? tier : 'tier3';
const grp = NIST_TIER_LABELS[lv];
return NIST_Q.map(f=>({ fn:f.fn, theme:f.fn+' · '+f.name, group:grp, icon:f.icon, docs:f.docs, controls:N_FN_COUNTS[f.fn]||10, q:f.q }));
}
const NOPTIONS = [['Not started',0],['Partial',1],['Largely',2],['Fully',3]];
const NBANDS = [
[0,'Initial',GV.orange,'Foundational cybersecurity practices are largely absent — start with Govern and Identify.'],
[40,'Developing',GV.orange,'Some practices exist but the program is not consistently applied across the organization.'],
[60,'Repeatable',GV.purple,'Formal, approved practices are in place — focus on closing the weaker functions.'],
[80,'Adaptive',GV.purple,'Strong posture — refine evidence, expand monitoring, and optimize continuously.'],
];
const nBandFor = pct=>{ let b=NBANDS[0]; NBANDS.forEach(x=>{ if(pct>=x[0]) b=x; }); return b; };
function nCompute(answers, sections, tier) {
const secs=sections||nSectionsForTier('tier3');
const themes=secs.map((t,ti)=>{ const max=t.q.length*3; let sum=0; t.q.forEach((_,qi)=>{ sum+=(answers[ti+'-'+qi]||0); }); const pct=Math.round((sum/max)*100); return {fn:t.fn,theme:t.theme,group:t.group,icon:t.icon,docs:t.docs,controls:t.controls,pct,gaps:Math.round((1-pct/100)*t.controls)}; });
const overall=themes.length?Math.round(themes.reduce((a,t)=>a+t.pct,0)/themes.length):0;
const totalControls=secs.reduce((a,t)=>a+t.controls,0);
const gaps=themes.reduce((a,t)=>a+t.gaps,0);
return { themes, overall, gaps, totalControls, tier:(secs[0]&&secs[0].group)||NIST_TIER_LABELS.tier3, band:nBandFor(overall) };
}
/* ── SEGMENTED ────────────────────────────────────────────── */
const NSegmented = ({ value, onChange }) => (
{overall>=80?"You're approaching your target tier.":overall>=60?"A solid base, with clear gaps to close.":"There's real groundwork to do first."}
{bandDesc} We estimate ~{gaps} of {totalControls} subcategories need attention across your profile.{user&&user.company?' Prepared for '+user.company:''}