<!-- markdownlint-disable MD013 -->
<!--
SPDX-License-Identifier: Apache-2.0
SPDX-FileCopyrightText: 2026 ndaal Gesellschaft für Sicherheit in der Informationstechnik mbH & Co KG, Cologne
-->
<!-- markdownlint-enable MD013 -->
# BSI Grundschutz++ OSCAL Viewer
> This file is the English original. Deutsche Fassung:
> [LIESMICH.md](LIESMICH.md) · Version française :
> [LISEZMOI.md](LISEZMOI.md) · Versión española: [LEEME.md](LEEME.md) ·
> Versione italiana: [LEGGIMI.md](LEGGIMI.md)
A safe, single-binary, offline viewer for the official **BSI
Grundschutz++** catalog, written in Rust. The complete OSCAL catalog
from the BSI [Stand-der-Technik-Bibliothek](https://github.com/BSI-Bund/Stand-der-Technik-Bibliothek)
is embedded in the executable at compile time: **copying the binary to
any machine is a full installation** — no install step, no database, no
network access required.
The web UI design and the Info menu are carried over from the ndaal
`vulnerability-lookup-rs` project (hyper + Askama + Bootstrap 5 + HTMX,
all assets embedded — no CDN).
## Features
- **Single binary, fully offline** — the complete Anwenderkatalog
Grundschutz++ (OSCAL 1.1.3, 1000 controls, 20 practices) plus all UI
assets (Bootstrap, Bootstrap Icons, HTMX, Roboto fonts) ship inside
the executable.
- **Filters** — practice (domain), requirement level
(MUSS / SOLLTE / KANN), security level (`normal-SdT` / `erhöht`),
effort level (0–5), tag and free text; filters combine and survive
pagination.
- **Full-text search** — a built-in engine works out of the box and is the
default. A [Meilisearch](https://www.meilisearch.com/) instance is
**opt-in** for typo-tolerant ranked search: enable it by passing a URL
(`--meili-url http://localhost:7700` or `MEILI_URL=…`). When enabled the
index is populated automatically at startup, with automatic fallback to
the built-in engine whenever Meilisearch is unset or unreachable. The
Meilisearch client is rustls-protected (HTTPS for any non-loopback host,
TLS 1.3 only).
- **Export** — the navbar **Export** menu writes the whole catalog, a
single practice or a single control as **JSON, Markdown, ODT or PDF — or a
ZIP bundle** of those formats
(Markdown/ODT via the pure-Rust `lo_writer`; PDF rendered directly with an
embedded TrueType font so German umlauts are faithful; the ZIP built with the
zero-dependency `lo_zip`), each with
selectable checksum **sidecars** (`.sha-256`, `.sha-512`, `.sha3-512`,
`.blake3-512`, `.shake256-512`). Files land in `--export-dir` (default
`grundschutz-oscal-viewer/export` under your home directory — `$HOME` on
Linux/macOS, `%USERPROFILE%` on Windows) via a capability-scoped,
non-overwriting writer.
- **Annotations** *(opt-in)* — the navbar **Annotations** workspace adds
Markdown notes to the **catalog, any practice or any control**, with a
Source ⇄ Rendered preview, a `MUSS`/`SOLLTE`/`KANN` modal (defaulting from
the control), a **CMMI Maturity Level** picker (0 Incomplete … 5 Innovating,
default 1 Performed), a draft/release toggle, **append-only ISO-8601
versioning**,
and PNG/SVG image attachments (served only as downloads). Markdown rendering
is XSS-safe (`markdown` crate) and uploads pass a strict MIME + structural
validator. Enable with `--db <FILE>` / `GSV_DB`; the notes live in a local
SQLite file (statically-linked vendored SQLite — still a single binary).
Without `--db` the viewer stays entirely read-only. To explore the workspace
with ready-made data, add `--seed-demo` (opt-in, non-destructive): it seeds a
demonstration annotation — a fifteen-version Draft → Release history plus
generated demo images — for the whole catalog, every practice and every
control. The ≤ 15 patch-management controls (`DET.5.10`, `KONF.8.1.1`,
`DEV.5.1`, … selected by Grundschutz++ catalog title) additionally carry a
**CISA BOD 26-04** remediation walk (V16–V24): the trilingual *Prioritizing
Security Updates Based on Risk* playbook and its colour decision-tree
graphic, so those controls show 24 versions. The playbook ships as
importable templates in
`templates/CISA_BOD_26-04_Remediation_Timelines_template_{EN,DE,FR}.md`.
- **Catalog change tracking** — when the embedded catalog is refreshed to
a newer BSI edition, every control whose requirement content changed
(title, statement, guidance, modal verb, security/effort level, tags or
parameters) is flagged **Updated** and shows its previous content for
comparison; brand-new controls are flagged **New**.
- **Every JSON byte visible** — each control page renders statement
(with OSCAL parameter substitution), guidance, props with namespaces,
parameters, tags and nested sub-controls **plus** the raw OSCAL JSON;
`/catalog.json` serves the embedded catalog byte-for-byte and
`/control/<id>/raw.json` each control.
- **Cross-framework mappings** — each control page shows, per framework,
the corresponding control in that framework (reference id + name), with
a similarity score and an "auto-generated — verify before use" caveat.
The navbar **Settings** menu lists ~150 frameworks (with flags) in a
searchable, scrollable panel with All / None / Reset; a default subset
(ISO 27001, NIS2, PCI DSS, GDPR, DORA, CRA, BSI Kompendium / C5 /
Mindeststandard Cloud, NIS2 IR, OWASP ASVS 5, EU AI Act, ISO 42001,
IEC 62443) is on, the rest off. **All** mapping data — the generated
Grundschutz++ ↔ framework crosswalk (~181k rows across 139 frameworks)
plus the hand-curated crosswalks (GitHub Security Controls, TISAX ISA
2027) — is **embedded in the binary** (Apache-2.0, ndaal's own work), so
every control shows its cross-framework mappings out of the box, with no
flag and no external pack. You can *optionally* load extra or custom CSVs
at runtime with `--mappings-dir`, merged on top of the embedded set (see
[framework mappings pack](documentation/framework_mappings_pack.md)).
- **Statistics** — catalog-wide distributions for modal verbs, security
levels, effort levels and practices.
- **Info menu** — About, System Information, Privacy, Security, License,
Imprint, Changelog, README and the Administrator, User, Developer and
Troubleshooting Guides, in the order of the ndaal design (§ 8.1).
- **HTTPS only** — TLS 1.3 via [rustls](https://github.com/rustls/rustls)
(aws-lc-rs provider with `prefer-post-quantum`, so the
X25519MLKEM768 post-quantum hybrid key-exchange group is offered
first). A self-signed certificate for localhost is generated at every
start-up (45-day validity); there is no plaintext-HTTP fallback.
- **Safe by construction** — `#![forbid(unsafe_code)]`, panicking
shortcuts denied by lint policy, capability-based filesystem access
(cap-std) for the only two write paths (`--export` and the Export
menu), localhost binding by default, defence-in-depth security headers
on every response.
- **Multiplatform** — pure-Rust dependency tree (no OpenSSL, no C TLS
stack — rustls all the way); builds on Linux, macOS and Windows,
x86_64 and aarch64.
- **49-language interface** — English, Deutsch, Français, Español and
Italiano lead the switcher; the other 44 (every EU official language
plus Albanian, Armenian, Azerbaijani, Belarusian, Bosnian, Georgian,
Icelandic, Latin, Lule and Southern Sámi, Macedonian, Montenegrin,
Norwegian Bokmål and Nynorsk, Romansh, Russian, Serbian, Turkish,
Ukrainian, and — beyond Europe — Chinese, Hindi and Urdu, the last
written right-to-left) follow alphabetically by English name. The UI chrome
(navigation, settings, headings, table headers, labels and buttons) is
translated. A **language switcher** in the navbar pins the choice in a
`gsv_lang` cookie; without it the browser's `Accept-Language` header is
honoured, with English as the fallback. The embedded BSI catalog content
and the terms of art (`MUSS` / `SOLLTE` / `KANN`, `erhöht`,
`normal-SdT`) intentionally stay in their source language, as does the
German legal Impressum.
- **Encryption at rest** *(opt-in)* — `--encryption-key-file <FILE>`
(`GSV_ENCRYPTION_KEY_FILE`) seals annotation bodies and image assets with
**XChaCha20-Poly1305** (AEAD) before they reach SQLite, so a stolen `.db`
file — or any `.db` / `.sql` / `.sql.gz` dump of it — yields ciphertext.
The key is 32 raw bytes or 64 hex characters. Plaintext and encrypted rows
coexist via a self-describing marker, so the key can be added to an existing
database with **no migration**; a configured-but-unreadable key is a hard
start-up error rather than a silent plaintext fallback. The key can be
**rotated without downtime**: pass the previous key as
`--retired-encryption-key-file` and it stays available for reading while new
writes use the new key (no re-encryption pass, no change to stored data).
Pure-Rust RustCrypto, so it cross-compiles to every target.
- **Database dumps + restore** — the **Export** menu also writes a consistent
SQLite snapshot (`VACUUM INTO`) and a portable SQL text dump (optionally
gzipped to `.sql.gz`) of the annotation database, each with checksum
sidecars, into `--dump-dir` (a chosen sub-path is confined under that
root). A management list **downloads** or **deletes** existing dumps.
`--restore-dump <FILE>` rebuilds a database from a `.db` snapshot or a
`.sql` / `.sql.gz` text dump — offline and non-destructive (the target
must not already exist).
- **Searchable annotations** — with `--db` enabled, `/search` surfaces a
*Matching annotations* section alongside the catalog hits; the search
decrypts in memory, so it keeps working under encryption-at-rest.
- **Operations-ready** — health probes `GET /healthz` (liveness) and
`/readyz` (readiness, `200` once the catalog is loaded and, with
`--db`, the store answers `SELECT 1`) for load balancers and
orchestrators; `--tls-cert` / `--tls-key` present a CA-issued certificate
instead of the ephemeral self-signed one; every request's `Host` is pinned
to the bind address (anti-DNS-rebinding), so `--allowed-host` /
`GSV_ALLOWED_HOSTS` is needed only behind a real hostname or reverse proxy;
`--log-format json` emits structured, newline-delimited logs for aggregation.
- **Self-update** *(explicit, checksum-verified)* — `--check-update` reports
whether a newer release exists on
`gitlab.com/vPierre/ndaal_public_bsi_grundschutz_oscal_viewer` (read-only, an
unreachable host is never fatal), and `--self-update` downloads the matching
target-triple binary, **verifies its SHA-256 against the committed
`release/SHA256SUMS`** at the tag, and atomically replaces the running
executable over TLS 1.3 (the same aws-lc-rs stack as the server — no second
crypto provider, no TLS 1.2). It pins the exact release it checksummed, never
downgrades, and never installs on a checksum mismatch. Opt out with
`--no-self-update` / `GSV_NO_SELF_UPDATE` for package-managed or locked-down
installs.
- **Accessibility** — a *Skip to main content* link is the first focusable
element (jumping past the navbar to a focusable `<main>` landmark), and the
HTMX live-search results are an `aria-live` region announced by screen
readers.
## Framework mappings
All 156 frameworks selectable from the navbar **Settings** menu — same
order, same icons the app shows. ✅ marks the 14 that are **on by
default**; the rest are off until you enable them (individually, or with the
**All** button). A toggle reveals rows on a control page whenever that
framework has mapping data — and all of it is **embedded in the binary**:
the generated Grundschutz++ ↔ framework crosswalk (~181k rows across 139
frameworks) plus the hand-curated crosswalks (GitHub Security Controls,
TISAX ISA 2027). No external pack is needed; `--mappings-dir` only *adds*
optional extra CSVs on top (see
[framework mappings pack](documentation/framework_mappings_pack.md)).
<!-- markdownlint-disable MD013 -->
| # | Framework (as shown in Settings) | Toggle slug | Default |
| --: | --- | --- | :-: |
| 1 | ISO 27001:2013 & 27001:2022 🌐 | `iso27001` | ✅ |
| 2 | NIST Cyber Security Framework (CSF) v1.1 🇺🇸 | `nist-cyber-security-framework-csf-v1` | — |
| 3 | NIST Cyber Security Framework (CSF) v2.0 🇺🇸 | `nist-cyber-security-framework-csf-v2` | — |
| 4 | NIS2 🇪🇺 | `nis2` | ✅ |
| 5 | SOC2 🇺🇸 | `soc2` | — |
| 6 | PCI DSS 4.0.1 💳 | `pci-dss-4` | ✅ |
| 7 | CMMC v2 🇺🇸 | `cmmc-v2` | — |
| 8 | PSPF 🇦🇺 | `pspf` | — |
| 9 | General Data Protection Regulation (GDPR): Full text and checklist from GDPR.EU 🇪🇺 | `gdpr` | ✅ |
| 10 | Essential Eight 🇦🇺 | `essential-eight` | — |
| 11 | NYDFS 500 with 2023-11 amendments 🇺🇸 | `nydfs-500-with-2023-11-amendments` | — |
| 12 | DORA (Act, RTS, ITS and GL) 🇪🇺 | `dora` | ✅ |
| 13 | NIST AI Risk Management Framework 🇺🇸🤖 | `nist-ai-risk-management-framework` | — |
| 14 | NIST SP 800-53 rev5 🇺🇸 | `nist-sp-800-53-rev5` | — |
| 15 | Règles OIV - Secteur « Activités civiles de l'Etat » (2019) 🇫🇷 | `r-gles-oiv-secteur-activit-s` | — |
| 16 | CCB CyberFundamentals Framework 🇧🇪 | `ccb-cyberfundamentals-framework` | — |
| 17 | NIST SP-800-66 (HIPAA) 🏥 | `nist-sp-800-66-hipaa` | — |
| 18 | HDS/HDH 🇫🇷 | `hds-hdh` | — |
| 19 | OWASP Application Security Verification Standard (ASVS) 4 🐝🖥️ | `owasp-application-security-verification` | — |
| 20 | RGS v2.0 🇫🇷 | `rgs-v2-0` | — |
| 21 | AirCyber ✈️🌐 | `aircyber` | — |
| 22 | Cyber Resilience Act (CRA) 🇪🇺 | `cra` | ✅ |
| 23 | TIBER-EU 🇪🇺 | `tiber-eu` | — |
| 24 | NIST Privacy Framework 🇺🇸 | `nist-privacy-framework` | — |
| 25 | TISAX (VDA ISA) v5.1 and v6.0 🚘 | `tisax-vda-isa-v5-1-and` | — |
| 26 | TISAX (VDA ISA) 2027 🚘 | `tisax-vda-isa-2027` | — |
| 27 | ANSSI hygiene guide 🇫🇷 | `anssi-hygiene-guide` | — |
| 28 | Essential Cybersecurity Controls (ECC) 🇸🇦 | `essential-cybersecurity-controls-ecc` | — |
| 29 | CIS Controls v8* 🌐 | `cis-controls-v8` | — |
| 30 | CSA CCM (Cloud Controls Matrix)* ☁️ | `csa-ccm-cloud-controls-matrix` | — |
| 31 | FADP (Federal Act on Data Protection) 🇨🇭 | `fadp-federal-act-on-data-protection` | — |
| 32 | NIST SP 800-171 rev2 (2021) 🇺🇸 | `nist-sp-800-171-rev2-2021` | — |
| 33 | ANSSI : recommandations de sécurité pour un système d'IA générative 🇫🇷🤖 | `anssi-recommandations-de-s-curit-pour` | — |
| 34 | NIST SP 800-218: Secure Software Development Framework (SSDF) 🖥️ | `nist-sp-800-218-secure-software` | — |
| 35 | GSA FedRAMP rev5 ☁️🇺🇸 | `gsa-fedramp-rev5` | — |
| 36 | Cadre Conformité Cyber France (3CF) v1 (2021) ✈️🇫🇷 | `cadre-conformit-cyber-france-3cf-v1` | — |
| 37 | ANSSI : SecNumCloud ☁️🇫🇷 | `anssi-secnumcloud` | — |
| 38 | Cadre Conformité Cyber France (3CF) v2 (2024) ✈️🇫🇷 | `cadre-conformit-cyber-france-3cf-v2` | — |
| 39 | ANSSI : outil d'autoévaluation de gestion de crise cyber 💥🇫🇷 | `anssi-outil-d-auto-valuation-de` | — |
| 40 | BSI: IT-Grundschutz-Kompendium 🇩🇪 | `bsi-kompendium` | ✅ |
| 41 | NIST SP 800-171 rev3 (2024) 🇺🇸 | `nist-sp-800-171-rev3-2024` | — |
| 42 | ENISA: 5G Security Controls Matrix 🇪🇺 | `enisa-5g-security-controls-matrix` | — |
| 43 | OWASP Mobile Application Security Verification Standard (MASVS) 🐝📱 | `owasp-mobile-application-security` | — |
| 44 | Agile Security Framework (ASF) - baseline - by intuitem 🤗 | `agile-security-framework-asf-baseline-by` | — |
| 45 | ISO 27001:2013 🌐 (For legacy and migration) | `iso-27001-2013-for-legacy-and` | — |
| 46 | EU AI Act 🇪🇺🤖 | `eu-ai-act` | ✅ |
| 47 | FBI CJIS 🇺🇸👮 | `fbi-cjis` | — |
| 48 | Operational Technology Cybersecurity Controls (OTCC) 🇸🇦 | `operational-technology-cybersecurity` | — |
| 49 | Secure Controls Framework (SCF) 🇺🇸🌐 | `secure-controls-framework-scf` | — |
| 50 | NCSC - Cyber Assessment Framework (CAF) v3.2 🇬🇧 | `ncsc-cyber-assessment-framework-caf-v3` | — |
| 51 | California Consumer Privacy Act (CCPA) 🇺🇸 | `california-consumer-privacy-act-ccpa` | — |
| 52 | California Consumer Privacy Act Regulations 🇺🇸 | `california-consumer-privacy-act` | — |
| 53 | NCSC Cyber Essentials 🇬🇧 | `ncsc-cyber-essentials` | — |
| 54 | Directive Nationale de la Sécurité des Systèmes d'Information (DNSSI) Maroc 🇲🇦 | `directive-nationale-de-la-s-curit` | — |
| 55 | Part-IS ✈️🇪🇺 | `part-is` | — |
| 56 | ENS Esquema Nacional de seguridad 🇪🇸 | `ens-esquema-nacional-de-seguridad` | — |
| 57 | Korea ISA ISMS-P 🇰🇷 | `korea-isa-isms-p` | — |
| 58 | Swiss ICT minimum standard 🇨🇭 | `swiss-ict-minimum-standard` | — |
| 59 | Adobe Common Controls Framework (CCF) v5 🌐 | `adobe-common-controls-framework-ccf-v5` | — |
| 60 | BSI Cloud Computing Compliance Criteria Catalogue (C5) 🇩🇪 | `bsi-c5` | ✅ |
| 61 | Référentiel d'Audit de la Sécurité des Systèmes d'Information, ANCS Tunisie 🇹🇳 | `r-f-rentiel-d-audit-de` | — |
| 62 | ECB Cyber resilience oversight expectations for financial market infrastructures 🇪🇺 | `ecb-cyber-resilience-oversight` | — |
| 63 | Mindeststandard-des-BSI-zur-Nutzung-externer-Cloud-Dienste (Version 2.1) 🇩🇪 | `bsi-ms-cloud` | ✅ |
| 64 | Formulaire d'évaluation de la maturité - niveau fondamental (DGA) 🇫🇷 | `formulaire-d-valuation-de-la-maturit` | — |
| 65 | NIS2 technical and methodological requirements 2024/2690 🇪🇺 | `nis2-ir` | ✅ |
| 66 | Saudi Arabian Monetary Authority (SAMA) Cybersecurity Framework 🇸🇦 | `saudi-arabian-monetary-authority-sama` | — |
| 67 | Guide de sécurité des données (CNIL) 🇫🇷 | `guide-de-s-curit-des-donn` | — |
| 68 | International Traffic in Arms Regulations (ITAR) 🇺🇸 | `international-traffic-in-arms` | — |
| 69 | Federal Trade Commission (FTC) Standards for Safeguarding Customer Information 🇺🇸 | `federal-trade-commission-ftc-standards` | — |
| 70 | OWASP's checklist for LLM governance and security 🌐 | `owasp-s-checklist-for-llm-governance` | — |
| 71 | Recommandations pour les architectures des systèmes d'information sensibles ou à diffusion restreinte (ANSSI) 🇫🇷 | `recommandations-pour-les-architectures` | — |
| 72 | CIS benchmark for Kubernetes v1.10 🌐 | `cis-benchmark-for-kubernetes-v1-10` | — |
| 73 | De tekniske minimumskrav for statslige myndigheder 🇩🇰 | `de-tekniske-minimumskrav-for-statslige` | — |
| 74 | Google SAIF framework 🤖 | `google-saif-framework` | — |
| 75 | Recommandations relatives à l'administration sécurisée des SI (ANSSI) 🇫🇷 | `recommandations-relatives-l` | — |
| 76 | Prudential Standard CPS 230 - Operational Risk Management (APRA) 🇦🇺 | `prudential-standard-cps-230-operational` | — |
| 77 | Prudential Standard CPS 234 - Information Security (APRA) 🇦🇺 | `prudential-standard-cps-234-information` | — |
| 78 | Vehicle Cyber Security Audit (VCSA) v1.1 🚘 | `vehicle-cyber-security-audit-vcsa-v1` | — |
| 79 | Cisco Cloud Controls Framework (CCF) v3.0 ☁️🌐 | `cisco-cloud-controls-framework-ccf-v3` | — |
| 80 | FINMA - Circular 2023/01 - Operational risks and resilience - Banks 🇨🇭 | `finma-circular-2023-01-operational-risks` | — |
| 81 | Post-Quantum Cryptography (PQC) Migration Roadmap (May 2025) 🔐 | `post-quantum-cryptography-pqc-migration` | — |
| 82 | Cloud Sovereignty Framework - 1.2.1 - Oct 2025 🇪🇺 | `cloud-sovereignty-framework-1-2-1` | — |
| 83 | ISO 22301:2019 outline - Business continuity management systems 🌐 | `iso-22301-2019-outline-business` | — |
| 84 | CCB CyberFundamentals Framework 2025 🇧🇪 | `ccb-cyberfundamentals-framework-2025` | — |
| 85 | Prestataires de détection des incidents de sécurité (PDIS) - Référentiel d'exigences 🇫🇷 | `prestataires-de-d-tection-des-incidents` | — |
| 86 | Vendor Due Diligence - simple baseline - intuitem 🌐 | `vendor-due-diligence-simple-baseline` | — |
| 87 | Points de contrôle Active Directory (AD) - ANSSI 🇫🇷 | `points-de-contr-le-active-directory` | — |
| 88 | ISO 42001:2023 outline - Artificial Intelligence Management System, including Annex A 🤖🌐 | `iso-42001-2023-outline-artificial` | ✅ |
| 89 | India's Digital Personal Data Protection Act (DPDPA) - 2023 🇮🇳 | `india-s-digital-personal-data-protection` | — |
| 90 | E-ITS (Estonia's national cyber security standard) - 2024 🇪🇪 | `e-its-estonia-s-national-cyber` | — |
| 91 | Microsoft cloud security benchmark v1 - ☁️🌐 | `microsoft-cloud-security-benchmark-v1` | — |
| 92 | Baseline informatiebeveiliging Overheid 2 (BIO2) 🇳🇱 | `baseline-informatiebeveiliging-overheid` | — |
| 93 | ANSSI : Questionnaire MonAideCyber 🇫🇷 | `anssi-questionnaire-monaidecyber` | — |
| 94 | ITSP.10.171 - Protecting specified information in non-Government of Canada systems and organizations 🇨🇦 | `itsp-10-171-protecting-specified` | — |
| 95 | CISA Vendor Supply Chain Risk Management (SCRM) Template 🇺🇸 | `cisa-vendor-supply-chain-risk-management` | — |
| 96 | European Sustainability Reporting Standards (ESRS) 🇪🇺 | `european-sustainability-reporting` | — |
| 97 | ITIL 4 Management Practices 🌐 | `itil-4-management-practices` | — |
| 98 | NOREA - DORA in Control Framework v3.0 🇪🇺 | `norea-dora-in-control-framework-v3` | — |
| 99 | NIS-1 transposition FR 🇫🇷 | `nis-1-transposition-fr` | — |
| 100 | PSSI État 🇫🇷 | `pssi-tat` | — |
| 101 | Checklist de dossier d'homologation 🇫🇷 | `checklist-de-dossier-d-homologation` | — |
| 102 | Cahier des charges Label EBIOS RM v3.1 🇫🇷 | `cahier-des-charges-label-ebios-rm` | — |
| 103 | SecNumCloud v3.2 Annexe 2 : recommandations aux commanditaires ☁️🇫🇷 | `secnumcloud-v3-2-annexe-2` | — |
| 104 | CCB CyberFundamentals Small - Self assessment 🇧🇪 | `ccb-cyberfundamentals-small-self` | — |
| 105 | Mitre ATT&CK v18.1 - Threat catalog 🌐 | `mitre-att-ck-v18-1-threat` | — |
| 106 | Mitre D3FEND - Reference controls 🌐 | `mitre-d3fend-reference-controls` | — |
| 107 | OWASP Top 10 Web - Threat catalog 🐝🌐 | `owasp-top-10-web-threat-catalog` | — |
| 108 | OWASP MAS Threat Modelling Guide - Threat catalog 🐝📱 | `owasp-mas-threat-modelling-guide-threat` | — |
| 109 | CISA Cybersecurity Performance Goals (CPG) v2.0 🇺🇸 | `cisa-cybersecurity-performance-goals-cpg` | — |
| 110 | ANSSI : Référentiel Cyber France pour la réglementation NIS2 (ReCyF) 🇫🇷 | `anssi-r-f-rentiel-cyber-france` | — |
| 111 | Cadre Conformité Cyber France (3CF) v3.1 (2026) ✈️🇫🇷 | `cadre-conformit-cyber-france-3cf-v3` | — |
| 112 | Règles OIV - Secteur « Transport aérien » (2016) ✈️🇫🇷 | `r-gles-oiv-secteur-transport-a` | — |
| 113 | IEC 62443 series — parts 2-1, 2-4, 3-2, 3-3, 4-1, 4-2 🏭🌐 | `iec-62443-series-parts-2-1` | ✅ |
| 114 | CER Directive (Critical Entities Resilience) 🇪🇺 | `cer-directive-critical-entities` | — |
| 115 | EUDI ARF — EU Digital Identity Wallet High-Level Requirements (Annex 2.02) 🇪🇺 | `eudi-arf-eu-digital-identity-wallet` | — |
| 116 | UK Defence Standard 05-138 Issue 4 🇬🇧 | `uk-defence-standard-05-138-issue` | — |
| 117 | Référentiel HAS - Certification des établissements de santé pour la qualité des soins 🇫🇷🏥 | `r-f-rentiel-has-certification-des` | — |
| 118 | Personal Data Protection Law (PDPL) 🇸🇦 | `personal-data-protection-law-pdpl` | — |
| 119 | NCSC - Cyber Assessment Framework (CAF) v4.0 🇬🇧 | `ncsc-cyber-assessment-framework-caf-v4` | — |
| 120 | Algemene Beveiligingseisen voor Rijksoverheidsopdrachten (ABRO) 2026 🇳🇱 | `algemene-beveiligingseisen-voor` | — |
| 121 | PGSSI-S (Politique Générale de Sécurité des Systèmes d'Information de Santé) 🇫🇷 | `pgssi-s-politique-g-n-rale` | — |
| 122 | ANSSI : Recommandations de configuration d'un système GNU/Linux 🇫🇷 | `anssi-recommandations-de-configuration-d` | — |
| 123 | PSSI-MCAS (Politique de sécurité des systèmes d'information pour les ministères chargés des affaires sociales) 🇫🇷 | `pssi-mcas-politique-de-s-curit` | — |
| 124 | ANSSI : Recommandations pour la protection des systèmes d'information essentiels 🇫🇷 | `anssi-recommandations-pour-la-protection` | — |
| 125 | ANSSI : Recommandations de sécurité pour l'architecture d'un système de journalisation 🇫🇷 | `anssi-recommandations-de-s-curit-pour-2` | — |
| 126 | ANSSI : Recommandations de sécurité relatives à TLS 🇫🇷 | `anssi-recommandations-de-s-curit` | — |
| 127 | New Zealand Information Security Manual (NZISM) 🇳🇿 | `new-zealand-information-security-manual` | — |
| 128 | Clausier de sécurité numérique du Club RSSI Santé 🇫🇷 | `clausier-de-s-curit-num-rique` | — |
| 129 | Référentiel National de Sécurité de l'Information (RNSI), MPT Algérie 🇩🇿 | `r-f-rentiel-national-de-s` | — |
| 130 | Misure minime di sicurezza ICT per le pubbliche amministrazioni, AGID Italia 🇮🇹 | `misure-minime-di-sicurezza-ict-per` | — |
| 131 | Framework Nazionale CyberSecurity v2, FNCS Italia 🇮🇹 | `framework-nazionale-cybersecurity-v2` | — |
| 132 | Framework Nazionale per la Cybersecurity e la Data Protection, ACN Italia 🇮🇹 | `framework-nazionale-per-la-cybersecurity` | — |
| 133 | PSSIE du Bénin, ANSSI Bénin 🇧🇯 | `pssie-du-b-nin-anssi-b` | — |
| 134 | IGI 1300 / II 901 - Liste des exigences pour la mise en oeuvre d'un SI classifié (ANSSI) 🇫🇷 | `igi-1300-ii-901-liste-des` | — |
| 135 | Référentiel Général de Sécurité 2.0 - Annexe B2 🇫🇷 | `r-f-rentiel-g-n-ral` | — |
| 136 | Recommandations sur la sécurisation des systèmes de contrôle d'accès physique et de vidéoprotection 🇫🇷 | `recommandations-sur-la-s-curisation-des` | — |
| 137 | Recommandations pour un usage sécurisé d'(Open)SSH 🇫🇷 | `recommandations-pour-un-usage-s-curis` | — |
| 138 | Recommandations de sécurité relatives à IPsec pour la protection des flux réseau 🇫🇷 | `recommandations-de-s-curit-relatives` | — |
| 139 | Recommandations relatives à l'interconnexion d'un système d'information à internet 🇫🇷 | `recommandations-relatives-l-2` | — |
| 140 | Guides des mécanismes cryptographiques 🇫🇷 | `guides-des-m-canismes-cryptographiques` | — |
| 141 | Swift Customer Security Controls Framework (CSCF) v2025 🏦🌐 | `swift-customer-security-controls` | — |
| 142 | OWASP Application Security Verification Standard (ASVS) 5 🐝🖥️ | `owasp-asvs5` | ✅ |
| 143 | NIST 800-82 (OT) - appendix 🏭🤖 | `nist-800-82-ot-appendix` | — |
| 144 | RBI Master Direction 2023 - india 🏦🇮🇳 | `rbi-master-direction-2023-india` | — |
| 145 | Loi 05-20 relative à la cybersécurité (Maroc) 🇲🇦 | `loi-05-20-relative-la-cybers` | — |
| 146 | Lithuanian NIS2 Cybersecurity Law (Kibernetinio saugumo įstatymas) 🇱🇹 | `lithuanian-nis2-cybersecurity-law` | — |
| 147 | Prestataire d'audit de sécurité des systèmes d'information (PASSI) 🇫🇷 | `prestataire-d-audit-de-s-curit` | — |
| 148 | ANS Programme CaRE - Domaine 2 (Continuité et reprise d'activité, sauvegarde) 🇫🇷🏥 | `ans-programme-care-domaine-2-continuit` | — |
| 149 | ANS HospiConnect HOP'EN2 (Sécurisation de l'accès au SIH) 🇫🇷🏥 | `ans-hospiconnect-hop-en2-s-curisation` | — |
| 150 | Loi n° 09-08 relative à la protection des personnes physiques 🇲🇦 | `loi-n-09-08-relative-la` | — |
| 151 | Checklist des exigences de la Loi n° 09-08 🇲🇦 | `checklist-des-exigences-de-la-loi` | — |
| 152 | Référentiel des exigences de qualification des prestataires de services cloud ☁️🇲🇦 | `r-f-rentiel-des-exigences-de` | — |
| 153 | AI Defense Matrix 🤖🌐 | `ai-defense-matrix` | — |
| 154 | Zero Trust for Operational Technology (ZT OT) 🇺🇸🏭 | `zero-trust-for-operational-technology-zt` | — |
| 155 | T.C. CBDDO Bilgi ve İletişim Güvenliği Rehberi (BİGR) 🇹🇷 | `t-c-cbddo-bilgi-ve-leti` | — |
| 156 | GitHub Security Controls 🐙 | `github-security-controls` | — |
<!-- markdownlint-enable MD013 -->
## Installation
You do **not** have to be a developer to run the viewer — it is a single,
self-contained file. Pick the easiest option for you.
### Option A — `cargo binstall` or `cargo install` (if you have Rust)
If [Rust](https://www.rust-lang.org/tools/install) 1.93 or newer is installed,
the fastest path is [`cargo binstall`](https://github.com/cargo-bins/cargo-binstall),
which downloads the prebuilt binary instead of compiling it:
```sh
cargo binstall grundschutz-oscal-viewer # downloads the prebuilt binary, no build
```
Or build it from source with plain `cargo install` (compiles locally):
```sh
cargo install grundschutz-oscal-viewer
grundschutz-oscal-viewer # then open https://127.0.0.1:8228
```
Either way the binary lands in `~/.cargo/bin` (already on your `PATH`). The
difference is just how it gets there: `binstall` fetches the prebuilt binary,
while `install` compiles it from source.
### Option B — download the ready-made binary (no Rust needed)
Every release ships prebuilt binaries on the
[**Releases** page](https://gitlab.com/vPierre/ndaal_public_bsi_grundschutz_oscal_viewer/-/releases).
Download the **one file** that matches your system:
| Your system | File to download |
| --- | --- |
| **Windows** 10/11 (most PCs) | `…-x86_64-pc-windows-gnu.exe` |
| **Windows** on ARM | `…-aarch64-pc-windows-gnullvm.exe` |
| **Linux** (most PCs/servers) | `…-x86_64-unknown-linux-musl` |
| **Linux** on ARM (e.g. Raspberry Pi 64-bit) | `…-aarch64-unknown-linux-musl` |
| **macOS** Intel | `…-x86_64-apple-darwin` |
| **macOS** Apple Silicon (M1/M2/M3/M4) | `…-aarch64-apple-darwin` |
Not sure? On Windows take the first row; on a Mac from 2020 or later take Apple
Silicon; on a normal Linux PC take the first Linux row. (Optionally verify the
download against the release's `SHA256SUMS`.)
#### Windows
1. Download `…-x86_64-pc-windows-gnu.exe` (rename it to
`grundschutz-oscal-viewer.exe` if you like).
2. Double-click it. If SmartScreen says *"Windows protected your PC"*, click
**More info → Run anyway** — the binary is just unsigned.
3. A console window opens and stays open while the viewer runs.
#### Linux
```sh
chmod +x grundschutz-oscal-viewer-*-unknown-linux-musl # make it runnable (once)
./grundschutz-oscal-viewer-*-unknown-linux-musl # run it
```
#### macOS
```sh
chmod +x grundschutz-oscal-viewer-*-apple-darwin # once
xattr -d com.apple.quarantine grundschutz-oscal-viewer-*-apple-darwin # clear the download flag
./grundschutz-oscal-viewer-*-apple-darwin # run it
```
If macOS still says the developer cannot be verified, open **System Settings →
Privacy & Security**, scroll down, and click **Open Anyway**.
### Open it in your browser
However you started it, the viewer prints `listening on https://127.0.0.1:8228`
and keeps running. Now:
1. Open a web browser (Chrome, Firefox, Edge, Safari…).
2. Go to **<https://127.0.0.1:8228>**.
3. It is HTTPS with a self-signed certificate regenerated at every start, so the
browser warns **once** — click **Advanced → Proceed / Continue to
127.0.0.1**. This is expected and safe: the connection never leaves your
computer.
4. You should see the home page:

To **stop** the viewer, press `Ctrl-C` in its window (or just close it). Nothing
is written to disk and no data leaves your machine.
> Port 8228 already in use? Start with another one:
> `grundschutz-oscal-viewer --port 9000` → then open `https://127.0.0.1:9000`.
## Build
Requires Rust 1.93 or newer.
```sh
cargo build --release
# binary: target/release/grundschutz-oscal-viewer (~8 MB, self-contained)
```
### Cross-platform release builds
With [cargo-zigbuild](https://github.com/rust-cross/cargo-zigbuild) and
Zig installed, one command builds all six supported platforms and
writes the binaries plus a `SHA256SUMS` file into `dist/`:
```sh
just build-all # or: bash release/build_release_targets.sh
```
| Target | Artifact |
| --- | --- |
| Linux x86_64 (static, musl) | `grundschutz-oscal-viewer-<v>-x86_64-unknown-linux-musl` |
| Linux aarch64 (static, musl) | `grundschutz-oscal-viewer-<v>-aarch64-unknown-linux-musl` |
| Windows x86_64 | `grundschutz-oscal-viewer-<v>-x86_64-pc-windows-gnu.exe` |
| Windows aarch64 | `grundschutz-oscal-viewer-<v>-aarch64-pc-windows-gnullvm.exe` |
| macOS x86_64 | `grundschutz-oscal-viewer-<v>-x86_64-apple-darwin` |
| macOS aarch64 (Apple Silicon) | `grundschutz-oscal-viewer-<v>-aarch64-apple-darwin` |
## Usage
```sh
grundschutz-oscal-viewer # serve https://127.0.0.1:8228 (TLS 1.3)
grundschutz-oscal-viewer --port 9000 # custom port (env: GSV_PORT)
grundschutz-oscal-viewer --bind 0.0.0.0 # non-localhost bind (env: GSV_BIND) — your decision
grundschutz-oscal-viewer --export DIR # write the embedded catalog JSON into DIR, then exit
grundschutz-oscal-viewer --export-dir DIR # target dir for the Export menu (env: GSV_EXPORT_DIR)
grundschutz-oscal-viewer --meili-url "" # disable the default-on Meilisearch client
grundschutz-oscal-viewer --db notes.db --encryption-key-file key.bin # encrypt annotations at rest (env: GSV_ENCRYPTION_KEY_FILE)
grundschutz-oscal-viewer --encryption-key-file new.bin --retired-encryption-key-file old.bin # rotate the key; old values stay readable
grundschutz-oscal-viewer --db notes.db --clamav-db-dir /srv/clamav-db # offline ClamAV signature DB for clamscan (env: GSV_CLAMAV_DB_DIR)
grundschutz-oscal-viewer --tls-cert cert.pem --tls-key key.pem # present a CA certificate (env: GSV_TLS_CERT / GSV_TLS_KEY)
grundschutz-oscal-viewer --log-format json # structured JSON logs (env: GSV_LOG_FORMAT)
grundschutz-oscal-viewer --restore-dump dump.sql.gz --db new.db # rebuild a database from a dump, then exit
grundschutz-oscal-viewer --check-update # is a newer GitLab release available? (read-only)
grundschutz-oscal-viewer --self-update # download + SHA-256-verify + replace this binary, then exit
grundschutz-oscal-viewer --version
grundschutz-oscal-viewer --help
```
`--self-update` fetches the latest release for the running target triple from
`gitlab.com/vPierre/ndaal_public_bsi_grundschutz_oscal_viewer` over TLS 1.3
(the same aws-lc-rs stack as the server), verifies the download against the
committed `release/SHA256SUMS`, and atomically replaces the executable. It
never downgrades and never installs on a checksum mismatch; `--check-update`
only reports and treats an unreachable host as "up to date, could not check",
never an error. Set `--no-self-update` (or `GSV_NO_SELF_UPDATE=1`) to forbid
`--self-update` entirely — for package-managed or locked-down installs.
`--export` (one-shot) and the **Export** menu both open their target
directory as a capability (`cap-std`) and create files with `create_new`
semantics: existing files are never overwritten and no path outside the
directory can be reached. The Export menu additionally offers Markdown,
ODT and PDF (via the pure-Rust `lo_writer`), a ZIP bundle of the selected
formats (via `lo_zip`), plus checksum sidecars, scoped to the whole catalog,
one practice or one control.
The viewer serves **HTTPS only** (TLS 1.3, rustls). The self-signed
certificate is regenerated at every start-up, so a browser shows a
one-time "not trusted" warning on first connect — expected for a
self-signed localhost cert. Use `curl -k` for scripted access.
### Meilisearch (opt-in)
```sh
# Meilisearch is disabled by default; pass a URL to enable it:
grundschutz-oscal-viewer --meili-url http://localhost:7700 # enable a local instance
grundschutz-oscal-viewer --meili-url http://localhost:7700 --meili-key <key> # add an API key if it needs one
grundschutz-oscal-viewer --meili-url https://host:7700 # remote instance over TLS
# without --meili-url / MEILI_URL the built-in search is used
# or via environment: MEILI_URL / MEILI_MASTER_KEY
```
At startup the viewer pushes all controls into the `grundschutz` index
and switches `/search` to Meilisearch once indexing succeeded. If the
instance is unreachable, the built-in search stays active — the binary
never depends on it. The Meilisearch client is **rustls-protected**: it
uses HTTPS for any non-loopback host and negotiates **TLS 1.3 only**;
plain `http://` is accepted exclusively for loopback addresses
(`localhost` / `127.0.0.1` / `::1`). The viewer's own listener serves
TLS 1.3 via rustls.
## Routes
| Route | Content |
| --- | --- |
| `/healthz`, `/readyz` | Liveness / readiness probes (plain text, un-gated) |
| `/lang/{code}` | UI language switcher (`en` / `de` / `fr`) — sets the `gsv_lang` cookie, returns to the referring page |
| `/` | Hero search, stat cards, practice overview |
| `/controls` | Filterable, paginated control list |
| `/control/{id}` | Every field of one control + raw OSCAL JSON |
| `/control/{id}/raw.json` | Raw control JSON |
| `/practices`, `/practice/{id}` | Practice (domain) pages |
| `/search`, `/search/partial` | Full-text search (page / HTMX partial) |
| `/stats` | Catalog-wide distributions |
| `/metadata` | OSCAL metadata + back-matter, raw |
| `/export`, `/export/run`, `/export/download` | Export menu (JSON / Markdown / ODT / PDF / ZIP bundle + sidecars); *run* writes server-side, *download* streams to the browser |
| `/export/dumps/download`, `/export/dumps/delete` | Database-dump management (download / same-origin delete), confined to the dump root |
| `/catalog.json` | The embedded catalog, byte-for-byte |
| `/about`, `/system-info`, `/privacy`, `/security`, `/license`, `/imprint`, `/changelog`, `/readme`, `/administrator`, `/user`, `/developer`, `/troubleshooting` | Info menu |
| `/annotations`, `/annotations/...` | Annotations workspace (save / preview / upload / asset / template) — only with `--db` |
| `/readme`, `/administrator`, `/user` | Embedded README + guides |
| `/static/{path}` | Embedded UI assets (Bootstrap, icons, HTMX, fonts, logo) |
## Documentation
| Document | What it covers |
| --- | --- |
| [Tutorials](documentation/tutorials/README.md) | Task-oriented how-tos: cut a release, bump the version, write a CSAF advisory, run the quality gates, author a bash gate, back up/restore the database, verify TLS 1.3 / PQC, run the security scans |
| [User Guide](documentation/user_guide.md) | Day-to-day use of the viewer (also served at `/user`) |
| [Administrator Guide](documentation/administrator_guide.md) | Deployment, CLI flags, secrets, backup/restore (also at `/administrator`) |
| [Developer Guide](documentation/developer_guide.md) | Architecture, conventions, QA toolchain, testing, contribution checklist (also at `/developer`) |
| [Troubleshooting Guide](documentation/troubleshooting_guide.md) | Root-cause method and fixes, organised by symptom (also at `/troubleshooting`) |
| [Architecture (arc42)](documentation/arc42/README.md) | The 12-section arc42 architecture view |
| [Threat model (STRIDE)](documentation/threat-model/stride.md) | Per-boundary STRIDE analysis, data classification and encryption-at-rest policy, residual-risk register; ships a Microsoft Threat Modeling Tool companion (`.tm7`) |
| [Security decisions](documentation/security/cryptographic-inventory.md) | The OWASP ASVS registry documents: [cryptographic inventory](documentation/security/cryptographic-inventory.md) and [validation architecture](documentation/security/validation-architecture.md) |
| [Codebase wiki](documentation/wiki/en/overview.md) | Navigable code map for contributors and AI agents: [overview](documentation/wiki/en/overview.md), [codemap](documentation/wiki/en/codemap.md), and per-module entity/concept/pattern pages |
| [Framework mappings pack](documentation/framework_mappings_pack.md) | How the mappings are embedded and built (with `--mappings-dir` as an optional extra) |
| [Test sequences](documentation/test_sequences.md) | The layered test suite (Rust, Bruno, Playwright, fuzz, live scans) |
| [Changelog](CHANGELOG.md) | Release history (also served at `/changelog`) |
## Development
```sh
just test # unit + integration tests
just clippy # warnings denied (pedantic)
just qa # all quality gates: fmt, clippy, tests, doc, audit,
# deny, machete, rust-doctor, htmlhint, oxlint
just fuzz-smoke # 10 s per fuzz target (nightly + cargo-fuzz)
just fuzz fuzz_query_parse # one target, 60 s
```
Quality gates are configured at the repository root: `clippy.toml`,
`rustfmt.toml`, `audit.toml`, `deny.toml`, `rust-doctor.toml`,
`.oxlintrc.json` — plus `src/templates/.htmlhintrc` for the template
lint.
### Test coverage
Line coverage is **90.17%** (4 732 / 5 248 lines, `cargo-tarpaulin` 0.37.0),
measured across the workspace with `vendor/` excluded so third-party sources
do not count either way. A blocking `--fail-under 80` gate guards it:
```sh
bash tests/scripts/test_cargo_tarpaulin.sh # writes documentation/rust/cargo_tarpaulin/
```
Excluding `src/main.rs` the library sits at **97.48%** (4 675 / 4 796).
`main.rs` is 57/452 on its own and accounts for 395 of the 516 uncovered
lines — socket binding, TLS listener setup and `process::exit` paths that no
hermetic unit test can reach without a real listener.
The run caps `PROPTEST_CASES`/`QUICKCHECK_TESTS` at 2, because tarpaulin's
instrumentation is 10-50x slower than native and the default 256 cases across
90 properties does not terminate in reasonable time. Line coverage is
identical at 2 cases or 256; the full 256-case run still happens in the
normal `test` and proptest gates.
Beyond the unit/integration suite, several dimensions are layered on:
- **Property-based invariants** (`tests/proptest_invariants.rs`) mirror the
`cargo fuzz` targets, so every untrusted-input parser's invariant is
checked on each `cargo test` run — not only under a dedicated fuzz session.
- **Fuzzing** — `cargo fuzz` targets under `fuzz/fuzz_targets/` cover every
byte-input surface (`just fuzz-smoke`).
- **Model checking** — `kani-harness/` proves 3 harnesses exhaustively over
the whole input space, where proptest only samples: `paginate` is total and
returns a well-formed window for any `(len, page)` in `usize × usize`, the
empty-catalog corner is pinned exactly, and `parse_args` on empty input
yields all defaults. It is a **standalone workspace** that `#[path]`-includes
only the rusqlite-free pure modules — `cargo kani` on the main crate cannot
work, because `libsqlite3-sys`'s build script uses the unstable `cfg_select`
feature that Kani's pinned nightly rejects. Run it from that directory, or
via the opt-in gate:
```sh
QG_RUN_KANI=1 bash tests/scripts/test_cargo_kani.sh # nightly-only, slow
```
String-processing functions are deliberately left to proptest and libFuzzer:
symbolic `&str` forces CBMC to model heap allocation plus full UTF-8 decode,
a state space that exhausts memory rather than terminating.
- **Known-answer & policy tests** — each of the five checksum hash families
(`src/sidecar.rs`) carries a fixed NIST / FIPS-202 / BLAKE3 known-answer
vector; annotation Markdown is checked against an XSS-protocol battery
(`javascript:` / `vbscript:` / `data:` stripped from links and images); and
the start-up TLS certificate is parsed back to enforce the Elliptic-curve
(no-RSA) signature policy and its `localhost` / `127.0.0.1` / `::1` SANs.
- **API / HATEOAS contract** — `tests/scripts/test_hateoas_compliance_grundschutz.sh`
drives the running server (`:8228`) and checks the hypermedia navigation
(in-band nav links, live control -> detail -> `raw.json`, htmx fragments)
and the JSON contract (`/catalog.json`, `/control/{id}/raw.json`); it
self-skips when no server is listening.
### Browser-driven E2E tests
`test/playwright/` runs the whole app through a real Chromium, Firefox,
and WebKit — HTMX live search, framework-toggle persistence, the
language switcher, and the annotation editor's create/preview/save
flow — against a throwaway `--seed-demo` instance it manages itself:
```sh
test/playwright/run.sh # self-skips if no system Chrome is found
```
See `documentation/test_sequences.md` §7 for the full spec-file
breakdown and the config's documented deviations (self-signed dev TLS,
serialized execution over the shared database).
### Framework mappings generator
`scripts/generate_ciso_mappings/` builds the generated crosswalk that is
committed under `data/mappings/` and embedded in the binary (see
[framework mappings pack](documentation/framework_mappings_pack.md)
§4): it reads the public framework requirement catalogues (via the CISO
Assistant community library) as **input**, matches `data/frameworks.csv`
slugs to library files, and embeds both sides with a multilingual
sentence-transformer to produce one similarity-scored CSV per framework.
```sh
cd scripts/generate_ciso_mappings
python3 -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt
python3 download_libraries.py --cache-dir .cache
python3 generate_pack.py --repo-root ../.. --cache-dir .cache --output-dir /path/to/pack
```
The output is a **similarity analysis** — ndaal's own **Apache-2.0** work
product (the requirement catalogues are only read as input to compute the
scores; no third-party source code is reused). The generated CSVs are
committed under `data/mappings/` and embedded in the binary. See the
script's own README for the platform note on pinning `torch==2.2.2`
(the last release with macOS x86_64/Intel wheels) and how to run its
unit tests offline.
## Data source and licenses
- **Code:** Apache-2.0 (see `LICENSE`).
- **Embedded catalog:** Anwenderkatalog Grundschutz++ from the BSI
[Stand-der-Technik-Bibliothek](https://github.com/BSI-Bund/Stand-der-Technik-Bibliothek),
© Bundesamt für Sicherheit in der Informationstechnik, licensed
**CC-BY-SA-4.0** (see `data/grundschutz-plus-plus-catalog.json.license`).
- **Embedded UI assets** (REUSE `.license` sidecars next to each file,
full license texts in `LICENSES/`):
- Bootstrap 5.3.3 and Bootstrap Icons 1.11.3 — MIT,
© The Bootstrap Authors
- htmx 2.0.4 — 0BSD, © Big Sky Software
- Roboto — Apache-2.0, © Google LLC
- Roboto Mono — OFL-1.1, © The Roboto Mono Project Authors
To refresh the embedded catalog, run `scripts/update_catalog.sh` (or
download the current file manually) and rebuild:
```sh
scripts/update_catalog.sh
cargo build --release
```
## Author
Pierre Gronau, ndaal Gesellschaft für Sicherheit in der
Informationstechnik mbH & Co KG, Cologne — <Pierre.Gronau@ndaal.eu>