// evaluation-cmmc-engine.jsx — Verigo Global: CMMC 2.0 readiness evaluation engine // The CMMC Level chosen in scope decides which domains/questions are assessed. // Exposes window.EVAL_CMMC const { V: GV, MAXW: GMW, FONT: GFT } = window; /* ── QUESTION BANK — per domain, with Level 1 and Level 2 question sets ─── */ // Each question is [practice id, statement] so every answer maps to a specific 800-171 practice. const CQUESTIONS = [ { code: 'AC', domain: 'Access Control', icon: 'lock', l1: 4, l2: 22, docs: ['Access Control Policy', 'Account Management Procedure'], qL1: [ ['3.1.1', 'System access is limited to authorized users, processes, and devices.'], ['3.1.2', 'Access is limited to the transactions and functions users are permitted.'], ['3.1.22', 'Information posted on publicly accessible systems is controlled.'], ], qL2: [ ['3.1.1', 'System access is limited to authorized users, processes, and devices.'], ['3.1.5', 'Least privilege and separation of duties are enforced for accounts.'], ['3.1.12', 'Remote access sessions are authorized, monitored, and encrypted.'], ] }, { code: 'AT', domain: 'Awareness & Training', icon: 'users', l1: 0, l2: 3, docs: ['Awareness & Training Policy', 'Security Awareness & Training Procedure'], qL1: [], qL2: [ ['3.2.1', 'Personnel receive security awareness training on risks and policies.'], ['3.2.2', 'Staff are trained for their assigned information-security duties.'], ['3.2.3', 'Insider-threat awareness is included in training.'], ] }, { code: 'AU', domain: 'Audit & Accountability', icon: 'clipboard', l1: 0, l2: 9, docs: ['Audit & Accountability Policy', 'Audit Log Review Procedure'], qL1: [], qL2: [ ['3.3.1', 'Audit logs are created and retained to support monitoring and investigation.'], ['3.3.2', 'Actions are traceable to individual users for accountability.'], ['3.3.5', 'Audit records are reviewed, analyzed, and correlated for issues.'], ] }, { code: 'CM', domain: 'Configuration Management', icon: 'cpu', l1: 0, l2: 9, docs: ['Configuration Management Policy', 'Configuration Baseline & Change Procedure'], qL1: [], qL2: [ ['3.4.1', 'Baseline configurations of systems are established and maintained.'], ['3.4.2', 'Security configuration settings are enforced on system components.'], ['3.4.3', 'Changes are tracked, reviewed, approved, and analyzed for impact.'], ] }, { code: 'IA', domain: 'Identification & Authentication', icon: 'shield', l1: 2, l2: 11, docs: ['Identification & Authentication Policy', 'FIPS-Validated Cryptography Procedure'], qL1: [ ['3.5.1', 'Users and devices are identified before access is granted.'], ['3.5.2', 'The identity of users and devices is authenticated.'], ], qL2: [ ['3.5.1', 'Users, processes, and devices are uniquely identified.'], ['3.5.3', 'Multifactor authentication is used for network and privileged access.'], ['3.5.10', 'Passwords are cryptographically protected in storage and transit.'], ] }, { code: 'IR', domain: 'Incident Response', icon: 'zap', l1: 0, l2: 3, docs: ['Incident Response Policy', 'Incident Response Procedure'], qL1: [], qL2: [ ['3.6.1', 'An incident-handling capability covering prep, detection, and recovery exists.'], ['3.6.2', 'Incidents are tracked, documented, and reported to authorities.'], ['3.6.3', 'The incident response capability is tested.'], ] }, { code: 'MA', domain: 'Maintenance', icon: 'refresh', l1: 0, l2: 6, docs: ['Maintenance Policy', 'Maintenance Logging Procedure'], qL1: [], qL2: [ ['3.7.1', 'System maintenance is performed and controlled.'], ['3.7.4', 'Media used for maintenance is checked for malicious code.'], ['3.7.5', 'Nonlocal maintenance sessions require multifactor authentication.'], ] }, { code: 'MP', domain: 'Media Protection', icon: 'file', l1: 1, l2: 9, docs: ['Media Protection Policy', 'Media Sanitization & Disposal Procedure'], qL1: [ ['3.8.3', 'Media containing FCI is sanitized or destroyed before disposal or reuse.'], ['3.8.1', 'Media containing FCI is physically controlled and protected.'], ], qL2: [ ['3.8.1', 'System media containing CUI is protected and access-controlled.'], ['3.8.3', 'Media is sanitized or destroyed before disposal or reuse.'], ['3.8.6', 'CUI on transported media is cryptographically protected.'], ] }, { code: 'PS', domain: 'Personnel Security', icon: 'briefcase', l1: 0, l2: 2, docs: ['Personnel Security Policy', 'Access Provisioning & Deprovisioning Procedure'], qL1: [], qL2: [ ['3.9.1', 'Individuals are screened before being granted access to CUI.'], ['3.9.2', 'CUI is protected during personnel actions such as termination and transfer.'], ] }, { code: 'PE', domain: 'Physical Protection', icon: 'building', l1: 4, l2: 6, docs: ['Physical Protection Policy', 'Maintenance Logging Procedure'], qL1: [ ['3.10.1', 'Physical access to systems and equipment is limited to authorized staff.'], ['3.10.3', 'Visitors are escorted and monitored.'], ['3.10.5', 'Physical access devices (keys, badges) are controlled and managed.'], ], qL2: [ ['3.10.1', 'Physical access to systems and equipment is limited to authorized individuals.'], ['3.10.3', 'Visitors are escorted and their activity is monitored.'], ['3.10.4', 'Audit logs of physical access are maintained.'], ] }, { code: 'RA', domain: 'Risk Assessment', icon: 'target', l1: 0, l2: 3, docs: ['Risk Assessment Policy', 'Vulnerability Scanning & Remediation Procedure'], qL1: [], qL2: [ ['3.11.1', 'Risk to operations and CUI is assessed periodically.'], ['3.11.2', 'Systems are scanned for vulnerabilities on a defined cadence.'], ['3.11.3', 'Vulnerabilities are remediated in line with risk assessments.'], ] }, { code: 'CA', domain: 'Security Assessment', icon: 'search', l1: 0, l2: 4, docs: ['Security Assessment Policy', 'System Security Plan (SSP) Procedure', 'POA&M Management Procedure'], qL1: [], qL2: [ ['3.12.1', 'Security controls are assessed periodically for effectiveness.'], ['3.12.2', 'A Plan of Action & Milestones (POA&M) tracks remediation.'], ['3.12.4', 'A System Security Plan (SSP) is developed, maintained, and current.'], ] }, { code: 'SC', domain: 'System & Communications Protection', icon: 'network', l1: 2, l2: 16, docs: ['System & Communications Protection Policy', 'FIPS-Validated Cryptography Procedure'], qL1: [ ['3.13.1', 'Communications are monitored and controlled at external boundaries.'], ['3.13.5', 'Publicly accessible system components are separated on subnetworks.'], ], qL2: [ ['3.13.1', 'Communications are monitored and controlled at system boundaries.'], ['3.13.8', 'Cryptographic mechanisms protect CUI in transit.'], ['3.13.11', 'FIPS-validated cryptography is employed to protect CUI.'], ] }, { code: 'SI', domain: 'System & Information Integrity', icon: 'activity', l1: 4, l2: 7, docs: ['System & Information Integrity Policy', 'Vulnerability Scanning & Remediation Procedure'], qL1: [ ['3.14.1', 'System flaws are identified and corrected in a timely manner.'], ['3.14.2', 'Protection from malicious code is provided.'], ['3.14.5', 'Periodic and real-time scans are performed.'], ], qL2: [ ['3.14.1', 'System flaws are identified, reported, and corrected in a timely manner.'], ['3.14.2', 'Malicious-code protection is deployed at appropriate locations.'], ['3.14.5', 'Periodic and real-time scans of the system are performed.'], ] }, ]; // Level 3 adds a subset of enhanced NIST SP 800-172 requirements. const C_ENHANCED = { code: 'EN', domain: 'Enhanced Protection (NIST SP 800-172)', icon: 'shield', controls: 24, docs: ['Risk Assessment Policy', 'System & Communications Protection Policy'], q: [ ['3.x', 'Advanced threat-hunting and detection operate continuously across the environment.'], ['3.x', 'Dual authorization and enhanced access controls protect high-value CUI.'], ['3.x', 'Supply-chain risk and component authenticity controls are applied to critical assets.'], ] }; const CLEVEL_LABEL = { 1: 'Level 1 · Foundational', 2: 'Level 2 · Advanced', 3: 'Level 3 · Expert' }; // Build the in-scope sections for the chosen level. function cSectionsForLevel(level) { const lv = Number(level) || 2; const grp = CLEVEL_LABEL[lv] || CLEVEL_LABEL[2]; if (lv === 1) { return CQUESTIONS.filter((d) => d.qL1 && d.qL1.length).map((d) => ({ code: d.code, theme: d.code + ' · ' + d.domain, group: grp, icon: d.icon, docs: d.docs, controls: d.l1, q: d.qL1 })); } const base = CQUESTIONS.map((d) => ({ code: d.code, theme: d.code + ' · ' + d.domain, group: grp, icon: d.icon, docs: d.docs, controls: d.l2, q: d.qL2 })); if (lv === 3) base.push({ code: C_ENHANCED.code, theme: C_ENHANCED.code + ' · ' + C_ENHANCED.domain, group: grp, icon: C_ENHANCED.icon, docs: C_ENHANCED.docs, controls: C_ENHANCED.controls, q: C_ENHANCED.q }); return base; } const COPTIONS = [ ['Not started', 0], ['Partial', 1], ['Largely', 2], ['Fully', 3], ]; const CBANDS = [ [0, 'Initial', GV.orange, 'Foundations are largely missing — start with the core policy and SSP set.'], [40, 'Developing', GV.orange, 'Key practices exist, but real gaps remain before an assessment is viable.'], [60, 'Established', GV.purple, 'A working control environment is in place — focus on closing the weaker domains.'], [80, 'Optimized', GV.purple, 'Strong posture — finalize evidence and the SSP, and keep it continuous.'], ]; const cBandFor = (pct) => { let b = CBANDS[0]; CBANDS.forEach((x) => { if (pct >= x[0]) b = x; }); return b; }; function cCompute(answers, sections) { const secs = sections || cSectionsForLevel(2); 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 { theme: t.theme, code: t.code, group: t.group, icon: t.icon, docs: t.docs, controls: t.controls, pct, gaps: Math.round((1 - pct / 100) * t.controls) }; }); const totSum = themes.reduce((a, t) => a + (t.pct), 0); const overall = themes.length ? Math.round(totSum / themes.length) : 0; const gaps = themes.reduce((a, t) => a + t.gaps, 0); const totalControls = secs.reduce((a, t) => a + t.controls, 0); return { themes, overall, gaps, totalControls, level: (secs[0] && secs[0].group) || CLEVEL_LABEL[2], band: cBandFor(overall) }; } /* ── SEGMENTED MATURITY CONTROL ──────────────────────────── */ const CSegmented = ({ value, onChange }) => (
{COPTIONS.map(([label, val]) => { const on = value === val; return ( ); })}
); /* ── QUIZ ────────────────────────────────────────────────── */ const EvalQuizCMMC = ({ onComplete, onExit, level, initialAnswers, initialStep, onProgress }) => { const sections = React.useMemo(() => cSectionsForLevel(level), [level]); const [step, setStep] = React.useState(() => Math.min(Math.max(initialStep || 0, 0), sections.length - 1)); const [answers, setAnswers] = React.useState(() => initialAnswers || {}); const total = sections.length; const cur = sections[step]; const report = (a, s) => { if (onProgress) onProgress(a, s); }; const set = (qi, v) => setAnswers((a) => { const na = { ...a, [step + '-' + qi]: v }; report(na, step); return na; }); const stepDone = cur.q.every((_, qi) => answers[step + '-' + qi] !== undefined); const answeredCount = Object.keys(answers).length; const totalQ = sections.reduce((a, t) => a + t.q.length, 0); const progress = Math.round((answeredCount / totalQ) * 100); const next = () => { if (step < total - 1) { const ns = step + 1; setStep(ns); report(answers, ns); window.scrollTo({ top: 0 }); } else { onComplete(cCompute(answers, sections)); } }; const back = () => { if (step > 0) { const ns = step - 1; setStep(ns); report(answers, ns); window.scrollTo({ top: 0 }); } else { onExit(); } }; return (
Domain {step + 1} of {total} {progress}% complete
{cur.group}

{cur.theme}

For each statement, choose how completely it reflects your organization today. Each maps to a specific NIST SP 800-171 practice.

{cur.q.map(([code, text], qi) => (
{code}

{text}

set(qi, v)} />
))}
{step === 0 ? 'Exit' : 'Back'} {step === total - 1 ? 'See my results' : 'Next domain'}
{!stepDone &&

Answer all {cur.q.length} statements to continue.

}
Your progress is saved automatically — you can leave and resume this evaluation later.
); }; /* ── RESULTS ─────────────────────────────────────────────── */ const CDonut = ({ pct, color }) => (
{pct} / 100
); const EvalResultsCMMC = ({ results, user, onNav, onRetake }) => { const { themes, overall, gaps, band, totalControls, level } = results; const [, label, bandColor, bandDesc] = band; const sorted = [...themes].sort((a, b) => a.pct - b.pct); const focus = sorted.filter((t) => t.pct < 80); const MODULES = window.TK_CMMC.QUOTE_MODULES; const isL2plus = /Level 2|Level 3/.test(level || ''); const reco = new Set(['tailor', 'ssp']); if (isL2plus) reco.add('c3pao'); if (overall < 80) reco.add('guidance'); if (overall < 60) reco.add('impl'); themes.forEach((t) => { if (t.pct < 60) { if (t.code === 'SC' || t.code === 'AC' || t.code === 'IA') reco.add('impl'); if (t.code === 'CA') reco.add('scoping'); } }); const recoIds = [...reco]; const recoModules = MODULES.filter((m) => reco.has(m.id)); const goBuild = () => { try { localStorage.setItem('verigo_reco_cmmc', JSON.stringify(recoIds)); } catch (e) {} onNav('checkout'); }; return (
{/* SCORE HEADER */}
Your readiness report · {level}
Overall maturity · {label}

{overall >= 80 ? 'You\u2019re close to assessment-ready.' : overall >= 60 ? 'A solid base, with clear gaps to close.' : 'There\u2019s real groundwork to do first.'}

{bandDesc} We estimate ~{gaps} of {totalControls} practices need attention before your assessment. {user && user.company ? ` Prepared for ${user.company}.` : ''}

{/* DOMAIN BREAKDOWN */}
{themes.map((t, i) => { const c = t.pct < 60 ? GV.orange : GV.purple; return (
{t.theme} {t.pct}%
~{t.gaps} of {t.controls} practices need attention
); })}
{/* ACTION PLAN */}
{focus.length === 0 && (
Every domain scored 80%+ — you\u2019re in strong shape. A practitioner can help validate evidence, finalize the SSP, and prepare for assessment.
)} {focus.map((t, i) => (
{i + 1}

{t.theme}

{t.pct}%
{t.docs.map((d, di) => ( {d} ))}
onNav('toolkit:cmmc')} style={{ whiteSpace: 'nowrap' }}>Open toolkit
))}
window.EVAL_CMMC.generateEvalPDF(results, user)}> Download my results (PDF) Retake the evaluation
{/* CUSTOM PACKAGE CTA */}
{recoModules.map((m, i) => (
{m.name}
{m.desc}
))}
Build my custom package Pick your options, see the price, then download a custom quote.
); }; /* ── RESULTS PDF ─────────────────────────────────────────── */ function genEvalPDFCMMC(results, user) { const lib = window.jspdf; if (!lib || !lib.jsPDF) { alert('PDF engine is still loading — please try again in a moment.'); return; } const { themes, overall, gaps, band, totalControls, level } = results; const doc = new lib.jsPDF({ unit: 'pt', format: 'a4' }); const W = doc.internal.pageSize.getWidth(); const H = doc.internal.pageSize.getHeight(); const M = 50; const PURPLE = [91, 46, 145], ORANGE = [232, 98, 42], INK = [30, 30, 46], GREY = [120, 120, 134]; let y = 100; doc.setFillColor(...PURPLE); doc.rect(0, 0, W, 70, 'F'); doc.setFillColor(...ORANGE); doc.rect(W - M - 11, 28, 11, 11, 'F'); doc.setTextColor(255, 255, 255); doc.setFont('helvetica', 'bold'); doc.setFontSize(15); doc.text('VERIGO GLOBAL', M, 33); doc.setFont('helvetica', 'normal'); doc.setFontSize(8.5); doc.setTextColor(214, 204, 232); doc.text('Compliance by Design', M, 49); doc.setTextColor(255, 255, 255); doc.setFontSize(8.5); doc.text('CMMC 2.0 · NIST SP 800-171', W - M - 20, 35, { align: 'right' }); doc.setTextColor(...INK); doc.setFont('helvetica', 'bold'); doc.setFontSize(21); doc.text('CMMC 2.0 Readiness Report', M, y); y += 12; doc.setDrawColor(...ORANGE); doc.setLineWidth(2.5); doc.line(M, y, M + 54, y); y += 16; doc.setFont('helvetica', 'normal'); doc.setFontSize(10); doc.setTextColor(...GREY); doc.text(String(level || ''), M, y); y += 18; doc.setFont('helvetica', 'bold'); doc.setFontSize(40); doc.setTextColor(...PURPLE); doc.text(String(overall), M, y + 14); doc.setFontSize(11); doc.setTextColor(...GREY); doc.setFont('helvetica', 'normal'); doc.text('/ 100', M + 58, y + 14); doc.setFont('helvetica', 'bold'); doc.setFontSize(13); doc.setTextColor(...INK); doc.text('Overall maturity: ' + band[1], M + 130, y - 2); doc.setFont('helvetica', 'normal'); doc.setFontSize(10); doc.setTextColor(...GREY); doc.splitTextToSize('~' + gaps + ' of ' + (totalControls || 110) + ' practices need attention before your assessment. ' + band[3], W - M - (M + 130)).forEach((ln, i) => doc.text(ln, M + 130, y + 14 + i * 13)); y += 56; if (user && (user.company || user.name)) { doc.setDrawColor(224, 224, 232); doc.setLineWidth(0.5); doc.line(M, y, W - M, y); y += 16; doc.setFontSize(9); doc.setTextColor(...PURPLE); doc.setFont('helvetica', 'bold'); doc.text('Prepared for ' + (user.company || user.name), M, y); doc.setFont('helvetica', 'normal'); doc.setTextColor(...GREY); doc.text(new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }), W - M, y, { align: 'right' }); y += 22; } doc.setFont('helvetica', 'bold'); doc.setFontSize(12.5); doc.setTextColor(...PURPLE); doc.text('Maturity by domain', M, y); y += 6; doc.setDrawColor(...PURPLE); doc.setLineWidth(0.8); doc.line(M, y, W - M, y); y += 20; const barX = M + 230, barW = W - M - barX; themes.forEach((t) => { if (y > H - 70) { doc.addPage(); y = 60; } doc.setFont('helvetica', 'bold'); doc.setFontSize(9.5); doc.setTextColor(...INK); doc.splitTextToSize(t.theme, 210).forEach((ln, i) => doc.text(ln, M, y + 3 + i * 11)); doc.setFillColor(237, 237, 245); doc.rect(barX, y - 7, barW, 10, 'F'); const col = t.pct < 60 ? ORANGE : PURPLE; doc.setFillColor(...col); doc.rect(barX, y - 7, barW * (t.pct / 100), 10, 'F'); doc.setFont('helvetica', 'bold'); doc.setFontSize(10); doc.setTextColor(...col); doc.text(t.pct + '%', W - M, y + 3, { align: 'right' }); y += 26; }); y += 6; const focus = [...themes].sort((a, b) => a.pct - b.pct).filter((t) => t.pct < 80); if (focus.length) { if (y > H - 90) { doc.addPage(); y = 60; } doc.setFont('helvetica', 'bold'); doc.setFontSize(12.5); doc.setTextColor(...PURPLE); doc.text('Recommended next steps', M, y); y += 6; doc.setDrawColor(...PURPLE); doc.setLineWidth(0.8); doc.line(M, y, W - M, y); y += 18; focus.forEach((t, i) => { if (y > H - 90) { doc.addPage(); y = 60; } doc.setFont('helvetica', 'bold'); doc.setFontSize(10.5); doc.setTextColor(...INK); doc.text((i + 1) + '. ' + t.theme + ' (' + t.pct + '%)', M, y); y += 14; doc.setFont('helvetica', 'normal'); doc.setFontSize(9.5); doc.setTextColor(...GREY); doc.splitTextToSize('Toolkit documents: ' + t.docs.join(', '), W - 2 * M - 14).forEach((ln) => { doc.text(ln, M + 14, y); y += 12; }); y += 8; }); } const total = doc.internal.getNumberOfPages(); for (let i = 1; i <= total; i++) { doc.setPage(i); doc.setDrawColor(224, 224, 232); doc.setLineWidth(0.5); doc.line(M, H - 38, W - M, H - 38); doc.setFont('helvetica', 'normal'); doc.setFontSize(8); doc.setTextColor(150, 150, 160); doc.text('© 2026 Verigo Global · Readiness self-assessment — indicative, not a formal C3PAO assessment', M, H - 24); doc.text(i + ' / ' + total, W - M, H - 24, { align: 'right' }); } doc.save('Verigo-CMMC-Readiness-Report.pdf'); } window.EVAL_CMMC = { QUESTIONS: CQUESTIONS, OPTIONS: COPTIONS, BANDS: CBANDS, sectionsForLevel: cSectionsForLevel, computeResults: cCompute, EvalQuiz: EvalQuizCMMC, EvalResults: EvalResultsCMMC, generateEvalPDF: genEvalPDFCMMC }; Object.assign(window, { EvalQuizCMMC, EvalResultsCMMC });