feat: add NIS2 landing page, roadmap page, and compliance section
CI / TypeScript — type-check (push) Successful in 8s
CI / Publish — build & push image (push) Successful in 7s
CI / Deploy — pull & restart on host (push) Successful in 2s

- New /nis2 page: full Art. 21 mapping with covered/partial/roadmap/n-a
  tags, evidence-by-trigger breakdown, and roadmap callout
- New /roadmap page: planned and under-consideration items, NIS2-tagged
  items highlighted with monospace badge
- Home: new NIS2 section between screenshots and plugin block — Art. 21
  mapping list + MockCompliance UI + link to /nis2
- Features: new "Compliance & Audit (NIS2)" section
- Nav: Roadmap link added; NIS2 in Docs dropdown
- Footer: Roadmap and NIS2 links added
- docs/PRODUCT.md: NIS2 evidence foundation as value proposition #9
- docs/PAGES.md: /nis2, /roadmap, and NIS2 home section documented

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Christian Manivong
2026-06-28 11:35:37 +02:00
co-authored by Claude Sonnet 4.6
parent 0f6ec6241f
commit f194c379e4
9 changed files with 638 additions and 1 deletions
+298
View File
@@ -0,0 +1,298 @@
import { Link } from 'react-router-dom'
import { ShieldCheckIcon } from '@heroicons/react/24/outline'
type Coverage = 'covered' | 'partial' | 'roadmap' | 'na'
type Requirement = {
article: string
label: string
coverage: Coverage
netork: string
}
const REQUIREMENTS: Requirement[] = [
{
article: 'Art. 21 (2a)',
label: 'Risk analysis & information system security policies',
coverage: 'partial',
netork:
'Config drift detection, SNMP health metrics, and security agent coverage across all devices provide a continuous risk baseline. A formal risk register is out of scope for netOrk.',
},
{
article: 'Art. 21 (2b)',
label: 'Incident handling',
coverage: 'partial',
netork:
'Wazuh alert history, CrowdSec decisions, and Graylog syslog per device surface incidents at the network layer. A structured incident record with NIS2 Art. 23 reporting timers is on the roadmap.',
},
{
article: 'Art. 21 (2c)',
label: 'Business continuity, backup management, disaster recovery',
coverage: 'roadmap',
netork:
'Git-backed configuration snapshots (on roadmap) provide config-level recovery. Backup monitoring for individual devices is not yet implemented.',
},
{
article: 'Art. 21 (2d)',
label: 'Supply chain security',
coverage: 'partial',
netork:
'Vendor, model, firmware, and OS version are tracked per device after every poll. EOL tracking against endoflife.date is on the roadmap to flag unsupported software.',
},
{
article: 'Art. 21 (2e)',
label: 'Vulnerability handling in acquisition, development & maintenance',
coverage: 'covered',
netork:
'Per-device update status and installed package list tracked on every poll. Wazuh CVE counts by severity (critical / high / medium) linked directly to each device record. CVE cross-reference against NVD/OSV (without Wazuh) is on the roadmap.',
},
{
article: 'Art. 21 (2f)',
label: 'Assessing effectiveness of cybersecurity measures',
coverage: 'partial',
netork:
'The audit log records all orchestration actions. A per-site compliance dashboard (on roadmap) will aggregate security agent coverage, drift status, and patch metrics into a single view.',
},
{
article: 'Art. 21 (2g)',
label: 'Basic cyber hygiene & cybersecurity training',
coverage: 'na',
netork:
'Out of scope for a network orchestration platform. Training and hygiene policies are handled at the organizational level.',
},
{
article: 'Art. 21 (2h)',
label: 'Access control, asset management, human resources security',
coverage: 'covered',
netork:
'Full device inventory maintained automatically via discovery and continuous polling. RBAC with four built-in roles (viewer / operator / engineer / administrator) and custom role combinations. Complete audit log of all orchestration actions.',
},
{
article: 'Art. 21 (2i)',
label: 'Multi-factor authentication',
coverage: 'roadmap',
netork:
'TOTP-based MFA for netOrk user accounts is on the roadmap. Current authentication is JWT-based (username + password).',
},
{
article: 'Art. 21 (2j)',
label: 'Physical and environmental security',
coverage: 'na',
netork:
'Out of scope. Physical security of the infrastructure hosting netOrk is an organizational and facility concern.',
},
]
const EVIDENCE = [
{
trigger: 'Every device poll',
produces: [
'Installed package list with versions',
'Available update count',
'Interface status, ARP table, DHCP leases',
'VLAN membership vs. desired state (drift)',
'SNMP health metrics (CPU, memory, interface counters)',
'Wazuh agent status and CVE counts by severity',
'Graylog syslog forwarding status',
'CrowdSec decisions and ban counts',
],
},
{
trigger: 'Every user action',
produces: [
'Audit log entry: user, timestamp, resource, action',
'Before/after values for configuration changes',
],
},
{
trigger: 'On demand',
produces: [
'Topology graph — network segmentation view',
'Subnet browser — IP space coverage',
'VLAN matrix — which devices carry which VLANs',
'Audit log export to PDF / CSV (roadmap)',
],
},
]
function CoverageTag({ coverage }: { coverage: Coverage }) {
if (coverage === 'covered')
return (
<span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium bg-green-500/15 text-green-400 border border-green-500/20 whitespace-nowrap">
✓ Covered
</span>
)
if (coverage === 'partial')
return (
<span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium bg-yellow-500/15 text-yellow-400 border border-yellow-500/20 whitespace-nowrap">
⚠ Partial
</span>
)
if (coverage === 'roadmap')
return (
<span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium bg-sky-500/15 text-sky-400 border border-sky-500/20 whitespace-nowrap">
→ Roadmap
</span>
)
return (
<span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium bg-slate-700/50 text-slate-500 border border-slate-700 whitespace-nowrap">
— N/A
</span>
)
}
export default function Nis2() {
return (
<div className="py-16 md:py-24">
<div className="max-w-4xl mx-auto px-6">
{/* Header */}
<div className="mb-16">
<div className="mb-4 flex h-10 w-10 items-center justify-center rounded-lg bg-sky-600/10">
<ShieldCheckIcon className="h-5 w-5 text-sky-400" />
</div>
<h1 className="text-4xl md:text-5xl font-bold text-slate-100 mb-4">
NIS2 &amp; netOrk
</h1>
<p className="text-base text-slate-400 leading-relaxed max-w-2xl">
NIS2 Art. 21 defines ten categories of technical and organizational
measures. Some of them are directly addressed by what netOrk does
every day. This page maps each requirement to netOrk's current
capabilities — honestly, including what's partial and what's not
applicable.
</p>
</div>
{/* Art. 21 mapping */}
<div className="mb-20">
<h2 className="text-xl font-semibold text-slate-200 mb-6 pb-2 border-b border-slate-800">
Art. 21 — requirement by requirement
</h2>
<div className="space-y-0 rounded-xl border border-slate-800 overflow-hidden">
{REQUIREMENTS.map((r, i) => (
<div
key={r.article}
className={`p-5 ${i < REQUIREMENTS.length - 1 ? 'border-b border-slate-800' : ''}`}
>
<div className="flex flex-wrap items-start justify-between gap-3 mb-2">
<div className="flex items-center gap-3">
<span className="text-xs font-mono text-sky-500 shrink-0">{r.article}</span>
<span className="text-sm font-medium text-slate-200">{r.label}</span>
</div>
<CoverageTag coverage={r.coverage} />
</div>
<p className="text-sm text-slate-500 leading-relaxed pl-0 md:pl-24">{r.netork}</p>
</div>
))}
</div>
{/* Legend */}
<div className="mt-4 flex flex-wrap gap-4 text-xs text-slate-500">
<span className="flex items-center gap-1.5"><CoverageTag coverage="covered" /> netOrk covers this today</span>
<span className="flex items-center gap-1.5"><CoverageTag coverage="partial" /> partially covered — see description</span>
<span className="flex items-center gap-1.5"><CoverageTag coverage="roadmap" /> planned — see roadmap</span>
<span className="flex items-center gap-1.5"><CoverageTag coverage="na" /> outside scope of a network management tool</span>
</div>
</div>
{/* Evidence produced */}
<div className="mb-20">
<h2 className="text-xl font-semibold text-slate-200 mb-2 pb-2 border-b border-slate-800">
What netOrk produces as evidence
</h2>
<p className="text-sm text-slate-500 mb-6">
NIS2 audits require demonstrable outputs, not just claimed controls. Here's
what netOrk generates automatically.
</p>
<div className="space-y-6">
{EVIDENCE.map((e) => (
<div key={e.trigger} className="rounded-xl border border-slate-800 bg-slate-900 p-5">
<p className="text-xs font-semibold text-sky-500 uppercase tracking-widest mb-3">
{e.trigger}
</p>
<ul className="space-y-1.5">
{e.produces.map((item) => (
<li key={item} className="flex items-start gap-2 text-sm text-slate-400">
<span className="mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-sky-500" />
{item}
</li>
))}
</ul>
</div>
))}
</div>
</div>
{/* Roadmap callout */}
<div className="mb-20">
<h2 className="text-xl font-semibold text-slate-200 mb-6 pb-2 border-b border-slate-800">
What's coming
</h2>
<div className="space-y-4">
{[
{
title: 'CVE tracking per device',
detail: 'Automatic cross-reference of installed packages against NVD / OSV — no Wazuh agent required.',
},
{
title: 'Configuration backup & versioning',
detail: 'Git-backed config snapshots after every poll. Detect unauthorized changes, compare over time.',
},
{
title: 'Compliance dashboard',
detail: 'Per-site Art. 21 checklist: asset coverage, patch status, agent deployment, drift, syslog, audit activity.',
},
{
title: 'Audit log export',
detail: 'PDF and CSV export filtered by date range, device, user, or action — ready to hand to an auditor.',
},
{
title: 'Incident workflow',
detail: 'Structured incident records with NIS2 Art. 23 reporting timers (24 h / 72 h) and external webhook delivery.',
},
{
title: 'EOL tracking',
detail: 'Flag devices running end-of-life firmware or OS versions via the endoflife.date API.',
},
{
title: 'MFA (TOTP)',
detail: 'Time-based one-time passwords as a second factor for netOrk user accounts (Art. 21 (2i)).',
},
].map((item) => (
<div key={item.title} className="flex gap-4">
<div className="mt-2 shrink-0 h-1.5 w-1.5 rounded-full bg-sky-500" />
<div>
<p className="text-sm font-medium text-slate-200">{item.title}</p>
<p className="text-sm text-slate-500 mt-0.5">{item.detail}</p>
</div>
</div>
))}
</div>
<div className="mt-8">
<Link to="/roadmap" className="text-sky-400 hover:text-sky-300 transition-colors text-sm font-medium">
Full roadmap →
</Link>
</div>
</div>
{/* CTA */}
<div className="rounded-xl border border-slate-800 bg-slate-900 p-8 text-center">
<h2 className="text-xl font-semibold text-slate-100 mb-3">
Start with the foundation.
</h2>
<p className="text-sm text-slate-400 leading-relaxed mb-6 max-w-md mx-auto">
Asset inventory, continuous polling, drift detection, RBAC, and a full
audit log — deployed in one command.
</p>
<Link
to="/docs/getting-started"
className="inline-flex items-center gap-2 px-5 py-2.5 rounded-lg bg-sky-600 hover:bg-sky-500 text-white text-sm font-medium transition-colors"
>
Get started →
</Link>
</div>
</div>
</div>
)
}