admin / Strike
publicWeb-Based UK Cyber Compliance Tool with Reporting
Strike / strikexi-v2 / docs / build_user_guide.py
8294 B · main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | """Generate the StrikeXi User Guide PDF (reportlab).""" from reportlab.lib.pagesizes import A4 from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import cm from reportlab.lib import colors from reportlab.platypus import ( SimpleDocTemplate, Paragraph, Spacer, ListFlowable, ListItem, HRFlowable, Table, TableStyle ) import os NAVY = colors.HexColor("#16324f") BLUE = colors.HexColor("#2e86de") styles = getSampleStyleSheet() styles.add(ParagraphStyle("Brand", fontName="Helvetica-Bold", fontSize=28, textColor=NAVY, spaceAfter=2)) styles.add(ParagraphStyle("Sub", fontName="Helvetica", fontSize=13, textColor=colors.HexColor("#5b6b7b"), spaceAfter=18)) styles.add(ParagraphStyle("H1", fontName="Helvetica-Bold", fontSize=15, textColor=NAVY, spaceBefore=16, spaceAfter=6)) styles.add(ParagraphStyle("Body2", fontName="Helvetica", fontSize=10.5, leading=15, spaceAfter=6)) styles.add(ParagraphStyle("BulletX", fontName="Helvetica", fontSize=10.5, leading=15)) styles.add(ParagraphStyle("CodeX", fontName="Courier", fontSize=9.5, leading=13, backColor=colors.HexColor("#f1f4f8"), borderPadding=6, textColor=colors.HexColor("#1f2d3d"))) def h1(t): return Paragraph(t, styles["H1"]) def p(t): return Paragraph(t, styles["Body2"]) def code(t): return Paragraph(t.replace(" ", " ").replace("\n", "<br/>"), styles["CodeX"]) def bullets(items): return ListFlowable([ListItem(Paragraph(i, styles["BulletX"]), leftIndent=10) for i in items], bulletType="bullet", start="•", leftIndent=14) def build(path): doc = SimpleDocTemplate(path, pagesize=A4, topMargin=1.6*cm, bottomMargin=1.6*cm, leftMargin=1.8*cm, rightMargin=1.8*cm, title="StrikeXi User Guide") e = [] e.append(Paragraph('Strike<font color="#2e86de">Xi</font>', styles["Brand"])) e.append(Paragraph("User Guide - NCSC CAF Cyber Maturity Assessment Platform", styles["Sub"])) e.append(HRFlowable(width="100%", color=BLUE, thickness=2)) e.append(Spacer(1, 10)) e.append(p("StrikeXi is a containerised web application for running Cyber Maturity Assessments " "against the NCSC Cyber Assessment Framework (CAF). It scores responses, generates an " "actionable remediation roadmap, and exports a professional PDF report.")) e.append(h1("1. Getting Started (Administrator)")) e.append(p("Prerequisites: Docker and Docker Compose installed on the host.")) e.append(code("cd strikexi\ncp .env.example .env # edit secrets before first run\ndocker compose up -d --build")) e.append(p("The first launch initialises the PostgreSQL database, applies the schema and seed data, " "and creates the default administrator account.")) e.append(bullets([ "Frontend (web UI): <b>http://localhost:8080</b>", "Backend API docs (Swagger): <b>http://localhost:8000/docs</b>", "Default login: username <b>admin</b> / password as set in <b>.env</b> (ADMIN_PASSWORD).", ])) e.append(p('<b>Important:</b> change <font face="Courier">SECRET_KEY</font>, ' '<font face="Courier">POSTGRES_PASSWORD</font> and ' '<font face="Courier">ADMIN_PASSWORD</font> in <font face="Courier">.env</font> before production use.')) e.append(h1("2. Logging In")) e.append(bullets([ "Open the web UI and enter your username and password.", "Sessions are secured with a signed JWT token that expires automatically.", "Every login - successful or failed - is recorded in the Audit Log.", ])) e.append(h1("3. The Dashboard")) e.append(p("After login you land on the Dashboard, which lists all your assessments with their " "organisation, date, score and status. From here you can:")) e.append(bullets([ "<b>Resume</b> an in-progress assessment.", "<b>Review</b> a completed assessment and its results/roadmap.", "Start a new assessment via the sidebar.", ])) e.append(h1("4. Running an Assessment")) e.append(bullets([ "Click <b>New Assessment</b>, enter the organisation name and assessment date, then <b>Create & begin</b>.", "Questions cover all four CAF Objectives (A-D) and all fourteen Principles " "(A1-A4, B1-B6, C1-C2, D1-D2), grouped by objective and principle.", "For each question, select an answer (Achieved / Partially achieved / Not achieved). " "Each option carries a weighted score.", "Use <b>Save & pause</b> at any time - your answers are stored and you can resume later.", "Click <b>Complete & score</b> to calculate maturity and generate the roadmap.", ])) e.append(h1("5. Understanding Your Scores")) e.append(p("Scoring is weighted: each question's contribution is its option score multiplied by its " "weight. Principle scores roll up into Objective scores, and the four objectives average " "into an overall maturity score out of 100.")) band = Table([ ["Score", "Maturity band"], ["80-100", "Strong"], ["60-79", "Established"], ["40-59", "Developing"], ["0-39", "Initial"], ], colWidths=[4*cm, 8*cm]) band.setStyle(TableStyle([ ("BACKGROUND", (0,0), (-1,0), NAVY), ("TEXTCOLOR", (0,0), (-1,0), colors.white), ("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"), ("FONTSIZE", (0,0), (-1,-1), 10), ("GRID", (0,0), (-1,-1), 0.5, colors.HexColor("#d4dde7")), ("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.white, colors.HexColor("#f6f9fc")]), ("TOPPADDING", (0,0), (-1,-1), 5), ("BOTTOMPADDING", (0,0), (-1,-1), 5), ])) e.append(band) e.append(Spacer(1, 8)) e.append(h1("6. The Maturity Roadmap")) e.append(p("When a principle scores below its maturity threshold, StrikeXi automatically queues the " "mapped remediation action. Each roadmap step references the specific CAF Objective and " "Principle it addresses and provides detailed mitigation guidance. Steps are ordered by " "priority so you know exactly what to tackle first to raise maturity.")) e.append(h1("7. Exporting the PDF Report")) e.append(bullets([ "From the results screen, click <b>Export PDF report</b>.", "Confirm or edit the <b>Organisation Assessed</b> and <b>Date of Assessment</b>.", "Click <b>Generate PDF</b> - the report downloads automatically.", "The report includes the overall score, per-objective scores, a breakdown, and the full roadmap.", ])) e.append(h1("8. Audit Log")) e.append(p("The Audit Log (sidebar) records key actions with timestamps and source IP: logins, " "failed logins, assessments started/completed, and PDF exports - supporting accountability " "and compliance evidence.")) e.append(h1("9. Future Integrations (ITSM)")) e.append(p("Roadmap items are structured so they can be pushed to ITSM tools such as Jira or " "ServiceNow via the backend's pluggable adapter layer. A stub endpoint " "(<font face=\"Courier\">POST /api/assessments/{id}/push-itsm</font>) is included for future use.")) e.append(h1("10. Maintenance")) e.append(bullets([ "Data persists in Docker named volumes (<font face=\"Courier\">strikexi_pgdata</font>, " "<font face=\"Courier\">strikexi_reports</font>) and survives reboots.", "Stop: <font face=\"Courier\">docker compose down</font> (add <font face=\"Courier\">-v</font> only if you intend to wipe data).", "View logs: <font face=\"Courier\">docker compose logs -f backend</font>.", ])) e.append(Spacer(1, 14)) e.append(HRFlowable(width="100%", color=colors.HexColor("#d4dde7"))) e.append(Paragraph("StrikeXi - Confidential. For authorised assessor use only.", ParagraphStyle("foot", fontName="Helvetica", fontSize=8.5, textColor=colors.HexColor("#8a97a6")))) doc.build(e) print("Wrote", path) if __name__ == "__main__": out = os.path.join(os.path.dirname(__file__), "StrikeXi_User_Guide.pdf") build(out) |