// evaluation-hitrust-engine.jsx — Verigo Global: HITRUST CSF readiness evaluation engine
// The assessment type chosen in scope (e1 / i1 / r2) decides which CSF categories are assessed.
// Exposes window.EVAL_HITRUST
const { V: GV, MAXW: GMW, FONT: GFT } = window;
/* ── QUESTION BANK — per CSF category, tagged with assessment scope ─── */
// Each question is [control reference, statement] so every answer maps to a specific CSF control.
const HQUESTIONS = [
{ code: '01', name: 'Access Control', icon: 'lock', e1: true, controls: 25,
docs: ['Access Control Policy', 'Access Provisioning & Deprovisioning Procedure'],
q: [
['01.b', 'User access is registered and authorized before being granted.'],
['01.q', 'Users are uniquely identified and authenticated, with MFA for remote/privileged access.'],
['01.e', 'User access rights are reviewed and recertified on a defined cadence.'],
] },
{ code: '02', name: 'Human Resources Security', icon: 'users', e1: true, controls: 9,
docs: ['Human Resources Security Policy', 'Security Awareness & Training Procedure'],
q: [
['02.b', 'Personnel are screened before employment and bound by confidentiality terms.'],
['02.e', 'All workforce members complete tracked security awareness training.'],
['02.i', 'Access rights are removed promptly on termination or role change.'],
] },
{ code: '03', name: 'Risk Management', icon: 'target', e1: true, controls: 4,
docs: ['Risk Management Policy', 'Risk Assessment Procedure'],
q: [
['03.b', 'Risk assessments are performed on a defined cadence and kept current.'],
['03.c', 'Risks are mitigated through a tracked treatment plan.'],
] },
{ code: '04', name: 'Security Policy', icon: 'file', e1: false, controls: 2,
docs: ['Information Security Policy'],
q: [
['04.a', 'An approved information security policy document is published.'],
['04.b', 'The security policy is reviewed at planned intervals.'],
] },
{ code: '05', name: 'Organization of Information Security', icon: 'briefcase', e1: false, controls: 11,
docs: ['Organization of Information Security Policy', 'Third-Party & Supplier Security Policy'],
q: [
['05.c', 'Information security responsibilities are clearly allocated.'],
['05.k', 'Security requirements are addressed in third-party agreements.'],
] },
{ code: '06', name: 'Compliance', icon: 'scale', e1: false, controls: 10,
docs: ['Compliance Policy', 'Privacy Policy'],
q: [
['06.a', 'Applicable legislation and regulations (incl. HIPAA) are identified.'],
['06.d', 'Covered information is protected in line with data-protection requirements.'],
['06.h', 'Technical compliance is checked on a defined cadence.'],
] },
{ code: '07', name: 'Asset Management', icon: 'layers', e1: false, controls: 5,
docs: ['Asset Management Policy', 'Data Classification & Handling Procedure'],
q: [
['07.a', 'An inventory of assets is maintained with assigned owners.'],
['07.d', 'Information is classified and labeled by sensitivity.'],
] },
{ code: '08', name: 'Physical and Environmental Security', icon: 'building', e1: false, controls: 13,
docs: ['Physical & Environmental Security Policy'],
q: [
['08.b', 'Physical entry controls protect facilities and equipment.'],
['08.l', 'Equipment and media are securely disposed of or sanitized.'],
] },
{ code: '09', name: 'Communications and Operations Management', icon: 'network', e1: true, controls: 32,
docs: ['Communications & Operations Management Policy', 'Backup Policy', 'Malware Protection Policy'],
q: [
['09.j', 'Controls against malicious code are deployed and updated.'],
['09.l', 'Backups are performed, encrypted, and restoration is tested.'],
['09.aa', 'Audit logging captures and protects security-relevant events.'],
] },
{ code: '10', name: 'Systems Acquisition, Development & Maintenance', icon: 'cpu', e1: true, controls: 13,
docs: ['Secure Development Policy', 'Vulnerability & Patch Management Procedure'],
q: [
['10.m', 'Technical vulnerabilities are identified and remediated on a cadence.'],
['10.f', 'Cryptographic controls protect covered information in transit and at rest.'],
['10.k', 'Changes follow a controlled change-management process.'],
] },
{ code: '11', name: 'Information Security Incident Management', icon: 'zap', e1: true, controls: 5,
docs: ['Incident Management Policy', 'Incident Response Procedure'],
q: [
['11.a', 'Security events are reported through a defined channel.'],
['11.c', 'Incident response responsibilities and procedures are documented and exercised.'],
] },
{ code: '12', name: 'Business Continuity Management', icon: 'refresh', e1: false, controls: 5,
docs: ['Business Continuity Policy', 'Business Continuity & DR Testing Procedure'],
q: [
['12.c', 'Continuity plans including information security are developed.'],
['12.e', 'Continuity plans are tested, maintained, and re-assessed.'],
] },
{ code: '13', name: 'Privacy Practices', icon: 'heart', e1: false, controls: 12,
docs: ['Privacy Policy', 'Privacy Rights & Consent Procedure'],
q: [
['13.a', 'A privacy notice describes how covered information is handled.'],
['13.d', 'Choice and consent are captured before collection.'],
['13.g', 'Covered information is retained and disposed of per policy.'],
] },
];
const HASSESS_LABEL = { e1: 'e1 · Essentials', i1: 'i1 · Implemented', r2: 'r2 · Risk-based' };
const HASSESS_REQS = { e1: 44, i1: 182, r2: '200+' };
// Build the in-scope sections for the chosen assessment type.
function hSectionsForType(type) {
const t = (type === 'e1' || type === 'i1' || type === 'r2') ? type : 'i1';
const grp = HASSESS_LABEL[t];
const list = t === 'e1' ? HQUESTIONS.filter((c) => c.e1) : HQUESTIONS;
return list.map((c) => ({ code: c.code, theme: c.code + ' · ' + c.name, group: grp, icon: c.icon, docs: c.docs, controls: c.controls, q: c.q }));
}
const HOPTIONS = [
['Not started', 0],
['Partial', 1],
['Largely', 2],
['Fully', 3],
];
const HBANDS = [
[0, 'Initial', GV.orange, 'Foundations are largely missing — start with the core policy and risk set.'],
[40, 'Developing', GV.orange, 'Key controls exist, but real gaps remain before an assessment is viable.'],
[60, 'Established', GV.purple, 'A working CSF program is in place — focus on closing the weaker categories.'],
[80, 'Optimized', GV.purple, 'Strong posture — finalize maturity evidence and keep it continuous.'],
];
const hBandFor = (pct) => { let b = HBANDS[0]; HBANDS.forEach((x) => { if (pct >= x[0]) b = x; }); return b; };
function hCompute(answers, sections, type) {
const secs = sections || hSectionsForType('i1');
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);
const reqs = HASSESS_REQS[type] || HASSESS_REQS.i1;
return { themes, overall, gaps, totalControls, reqs, level: (secs[0] && secs[0].group) || HASSESS_LABEL.i1, band: hBandFor(overall) };
}
/* ── SEGMENTED MATURITY CONTROL ──────────────────────────── */
const HSegmented = ({ value, onChange }) => (
{HOPTIONS.map(([label, val]) => {
const on = value === val;
return (
onChange(val)}
style={{ fontFamily: GFT, fontSize: 13, fontWeight: 700, padding: '10px 6px', cursor: 'pointer', textAlign: 'center', background: on ? GV.purple : '#fff', color: on ? '#fff' : GV.g600, border: `1.5px solid ${on ? GV.purple : GV.g200}`, transition: 'all 120ms' }}>
{label}
);
})}
);
/* ── QUIZ ────────────────────────────────────────────────── */
const EvalQuizHITRUST = ({ onComplete, onExit, assessment, initialAnswers, initialStep, onProgress }) => {
const sections = React.useMemo(() => hSectionsForType(assessment), [assessment]);
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(hCompute(answers, sections, assessment)); } };
const back = () => { if (step > 0) { const ns = step - 1; setStep(ns); report(answers, ns); window.scrollTo({ top: 0 }); } else { onExit(); } };
return (
Category {step + 1} of {total}
{progress}% complete
For each statement, choose how completely it reflects your organization today. Each maps to a specific HITRUST CSF control reference.
{cur.q.map(([code, text], qi) => (
))}
{step === 0 ? 'Exit' : 'Back'}
{step === total - 1 ? 'See my results' : 'Next category'}
{!stepDone &&
Answer all {cur.q.length} statements to continue.
}
Your progress is saved automatically — you can leave and resume this evaluation later.
);
};
/* ── RESULTS ─────────────────────────────────────────────── */
const HDonut = ({ pct, color }) => (
);
const EvalResultsHITRUST = ({ results, user, onNav, onRetake }) => {
const { themes, overall, gaps, band, totalControls, level, reqs } = 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_HITRUST.QUOTE_MODULES;
const isR2 = /r2/.test(level || '');
const reco = new Set(['tailor', 'gap']);
if (isR2) reco.add('assessor');
if (overall < 80) reco.add('guidance');
if (overall < 60) reco.add('impl');
themes.forEach((t) => { if (t.pct < 60 && (t.code === '01' || t.code === '09' || t.code === '10')) reco.add('impl'); });
const recoIds = [...reco];
const recoModules = MODULES.filter((m) => reco.has(m.id));
const goBuild = () => { try { localStorage.setItem('verigo_reco_hitrust', JSON.stringify(recoIds)); } catch (e) {} onNav('checkout'); };
return (
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} control references need attention across your {reqs}-requirement {level.split(' · ')[0]} scope.
{user && user.company ? ` Prepared for ${user.company}.` : ''}
{themes.map((t, i) => {
const c = t.pct < 60 ? GV.orange : GV.purple;
return (
{t.theme}
{t.pct}%
~{t.gaps} of {t.controls} references need attention
);
})}
{focus.length === 0 && (
Every category scored 80%+ — you\u2019re in strong shape. A practitioner can validate maturity evidence and prepare your MyCSF submission.
)}
{focus.map((t, i) => (
{i + 1}
{t.theme}
{t.pct}%
{t.docs.map((d, di) => (
{d}
))}
onNav('toolkit:hitrust')} style={{ whiteSpace: 'nowrap' }}>Open toolkit
))}
window.EVAL_HITRUST.generateEvalPDF(results, user)}> Download my results (PDF)
Retake the evaluation
{recoModules.map((m, i) => (
))}
Build my custom package
Pick your options, see the price, then download a custom quote.
);
};
/* ── RESULTS PDF ─────────────────────────────────────────── */
function genEvalPDFHITRUST(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('HITRUST CSF', W - M - 20, 35, { align: 'right' });
doc.setTextColor(...INK); doc.setFont('helvetica', 'bold'); doc.setFontSize(21);
doc.text('HITRUST CSF 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 || 147) + ' control references need attention. ' + 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 control category', M, y); y += 6;
doc.setDrawColor(...PURPLE); doc.setLineWidth(0.8); doc.line(M, y, W - M, y); y += 20;
const barX = M + 250, barW = W - M - barX;
themes.forEach((t) => {
if (y > H - 70) { doc.addPage(); y = 60; }
doc.setFont('helvetica', 'bold'); doc.setFontSize(9); doc.setTextColor(...INK);
doc.splitTextToSize(t.theme, 230).forEach((ln, i) => doc.text(ln, M, y + 3 + i * 10));
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 += 24;
});
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 validated HITRUST assessment', M, H - 24);
doc.text(i + ' / ' + total, W - M, H - 24, { align: 'right' });
}
doc.save('Verigo-HITRUST-Readiness-Report.pdf');
}
window.EVAL_HITRUST = { QUESTIONS: HQUESTIONS, OPTIONS: HOPTIONS, BANDS: HBANDS, sectionsForType: hSectionsForType, computeResults: hCompute, EvalQuiz: EvalQuizHITRUST, EvalResults: EvalResultsHITRUST, generateEvalPDF: genEvalPDFHITRUST };
Object.assign(window, { EvalQuizHITRUST, EvalResultsHITRUST });