Skip to content

Commit 4ddadf7

Browse files
committed
Initial release: v1.0.0
NIS2 supply-chain questionnaire as a typed Zod schema. ~56 fields across 6 sections (profile, security_practices, saas_technical, on_prem_technical, pro_services, managed_services), each anchored to a specific source — NIS2 Art. 21(2), CIR 2024/2690, ENISA TIG, BSI IT-Grundschutz, or GDPR Art. 28. - src/schema.ts: Zod schema as source of truth. SECTION and FIELD_TYPE enums exported as named const objects. visibleWhen mechanism gates technical sections by service-type flags (isSaas, isOnPrem, etc.). - src/data.ts: validated, typed export with groupBySection() + visibleFields(). - examples/render-form.ts: render the multi-page form given a partial response. - examples/drizzle-storage-reference.ts: suggested response-storage layer for Drizzle-based applications. - .github/workflows/validate.yml: CI runs the Zod parse on every push. Dual-licensed: MIT for code, CC BY 4.0 for content.
0 parents  commit 4ddadf7

12 files changed

Lines changed: 1208 additions & 0 deletions

File tree

.github/workflows/validate.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: validate
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
schema-validates-data:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
- uses: oven-sh/setup-bun@v2
15+
with:
16+
bun-version: latest
17+
- run: bun install --no-save
18+
- name: Typecheck
19+
run: bun run typecheck
20+
- name: Schema validates bundled JSON
21+
run: bun run validate

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
node_modules/
2+
dist/
3+
*.log
4+
.DS_Store
5+
.env
6+
.env.local
7+
bun.lockb
8+
bun.lock

LICENSE

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
This repository carries a dual licence:
2+
3+
------------------------------------------------------------------------------
4+
1. CONTENT — questionnaire fields, descriptions, legal citations
5+
------------------------------------------------------------------------------
6+
7+
The compliance content (everything in `data/`, all bilingual labels and
8+
descriptions, and the substantive content of the README) is licensed under
9+
10+
Creative Commons Attribution 4.0 International (CC BY 4.0)
11+
https://creativecommons.org/licenses/by/4.0/legalcode
12+
13+
You are free to share, adapt, and use the content commercially, provided you
14+
give appropriate credit. Suggested attribution:
15+
16+
"Based on the NIS2 Supplier Questionnaire by Kardashev Catalyst UG /
17+
nisd2.eu, licensed under CC BY 4.0.
18+
https://github.com/NISD2/nis2-supplier-questionnaire"
19+
20+
------------------------------------------------------------------------------
21+
2. CODE — Zod schema, TypeScript types, helpers, examples
22+
------------------------------------------------------------------------------
23+
24+
All source code (everything in `src/` and `examples/`, plus build configuration
25+
files such as `tsconfig.json` and `package.json`) is licensed under
26+
27+
MIT License
28+
29+
Copyright (c) 2026 Kardashev Catalyst UG (haftungsbeschränkt)
30+
31+
Permission is hereby granted, free of charge, to any person obtaining a
32+
copy of this software and associated documentation files (the "Software"),
33+
to deal in the Software without restriction, including without limitation
34+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
35+
and/or sell copies of the Software, and to permit persons to whom the
36+
Software is furnished to do so, subject to the following conditions:
37+
38+
The above copyright notice and this permission notice shall be included in
39+
all copies or substantial portions of the Software.
40+
41+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
46+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
47+
DEALINGS IN THE SOFTWARE.
48+
49+
------------------------------------------------------------------------------
50+
3. NO WARRANTY ON COMPLIANCE OUTCOMES
51+
------------------------------------------------------------------------------
52+
53+
This is structured guidance based on our reading of the NIS2 Directive, CIR
54+
2024/2690, ENISA TIG, and BSI IT-Grundschutz. It is not legal advice and
55+
confers no guarantee that any user of this material will pass an audit, secure
56+
a procurement contract, or avoid regulatory penalties. Consult qualified
57+
counsel for your situation.

README.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# NIS2 Supplier Questionnaire
2+
3+
[![License: MIT + CC BY 4.0](https://img.shields.io/badge/license-MIT%20%2B%20CC%20BY%204.0-blue.svg)](./LICENSE)
4+
5+
**The questions a NIS2-regulated customer needs to ask their suppliers — as a typed Zod schema.** ~55 fields across 6 sections, each anchored to a specific source (NIS2 Art. 21(2), CIR 2024/2690, ENISA TIG, BSI IT-Grundschutz, GDPR Art. 28).
6+
7+
Maintained by [Kardashev Catalyst UG](https://nisd2.eu) — operator of [nisd2.eu](https://nisd2.eu) — and the same questionnaire that powers the supplier portal at nisd2.eu.
8+
9+
The Zod schema is the source of truth. The bundled JSON snapshot is a derived, schema-validated artefact.
10+
11+
---
12+
13+
## Why this exists
14+
15+
NIS2 Art. 21(2)(d) requires every regulated entity to assess its suppliers' cybersecurity practices. CIR 2024/2690 §5.1.2–§5.1.4 spells out what that assessment must include. ENISA TIG adds operational obligations on top.
16+
17+
In practice, every Mittelstand procurement team is currently:
18+
- Inventing their own supplier questionnaire from scratch
19+
- Sending suppliers 5 different questionnaires from 5 different customers
20+
- Each one re-asking the same NIS2/CIR/ENISA-anchored questions in slightly different words
21+
22+
A single shared, openly maintained, legally-anchored questionnaire is more valuable than 1,000 vendor forks. So we're publishing ours.
23+
24+
---
25+
26+
## Why a schema, not just a JSON file
27+
28+
A JSON-only release is a dead artefact: nobody can validate it without re-deriving the rules, and forks drift silently. A Zod schema is alive:
29+
30+
- **TypeScript consumers** import the schema directly and get full type safety.
31+
- **Non-TS consumers** generate JSON Schema via [`zod-to-json-schema`](https://github.com/StefanTerdell/zod-to-json-schema) and use it from Python, Go, Rust, Excel, anywhere.
32+
- **Drizzle / Prisma / Kysely consumers** use `examples/drizzle-storage-reference.ts` for a suggested response-storage layer keyed to our field IDs.
33+
- **Forks stay honest** — every change must validate against the schema or CI fails.
34+
35+
---
36+
37+
## Install
38+
39+
```bash
40+
npm install @nisd2/nis2-supplier-questionnaire
41+
# or
42+
bun add @nisd2/nis2-supplier-questionnaire
43+
```
44+
45+
Or pin to a specific commit / tag without npm:
46+
47+
```bash
48+
npm install github:NISD2/nis2-supplier-questionnaire#v1.0.0
49+
```
50+
51+
---
52+
53+
## Usage
54+
55+
### Render a multi-page form
56+
57+
```ts
58+
import {
59+
supplierQuestionnaire,
60+
groupBySection,
61+
visibleFields,
62+
} from "@nisd2/nis2-supplier-questionnaire";
63+
64+
const sections = groupBySection(supplierQuestionnaire);
65+
// → Map { "profile" => [...], "security_practices" => [...], ... }
66+
67+
// Given the supplier's answers so far, what should we show next?
68+
const response = { isSaas: true, isOnPrem: false };
69+
const visible = visibleFields(supplierQuestionnaire, response);
70+
// → only fields whose visibleWhen is satisfied (e.g. saas* fields shown, onPrem* hidden)
71+
```
72+
73+
### Validate a supplier's response
74+
75+
```ts
76+
import { supplierResponseSchema } from "@nisd2/nis2-supplier-questionnaire";
77+
78+
const response = JSON.parse(rawSubmission);
79+
const validated = supplierResponseSchema.parse(response);
80+
// throws on shape errors. Per-field type validation is up to your application:
81+
// look up `field.type` in the questionnaire and validate accordingly.
82+
```
83+
84+
### Generate JSON Schema for non-TS consumers
85+
86+
```ts
87+
import { zodToJsonSchema } from "zod-to-json-schema";
88+
import { supplierQuestionnaireSchema } from "@nisd2/nis2-supplier-questionnaire";
89+
90+
const jsonSchema = zodToJsonSchema(supplierQuestionnaireSchema, "SupplierQuestionnaire");
91+
fs.writeFileSync("./schema.json", JSON.stringify(jsonSchema, null, 2));
92+
```
93+
94+
---
95+
96+
## Sections
97+
98+
| Section | Fields | Anchored to |
99+
|------------------------|-------:|-------------|
100+
| `profile` | 17 | CIR §5.2(a), ENISA TIG §5.1.4(d), §5.2(b) |
101+
| `security_practices` | 24 | NIS2 Art. 21(2), CIR §5.1.x, ENISA TIG §5.1.4 TIPS |
102+
| `saas_technical` | 5 | BSI IT-Grundschutz OPS.2.2, ORP.4, DER.4 |
103+
| `on_prem_technical` | 4 | CRA, BSI IT-Grundschutz CON.8, CON.10 |
104+
| `pro_services` | 3 | BSI IT-Grundschutz ORP.2, ORP.3 |
105+
| `managed_services` | 3 | BSI IT-Grundschutz ORP.4, OPS.1.2.5, DER.2.1 |
106+
107+
`saas_technical`, `on_prem_technical`, `pro_services`, and `managed_services` are gated by the corresponding service-type flag in the profile section (`isSaas`, `isOnPrem`, `isProfessionalServices`, `isManagedService`). Use `visibleFields()` to render only the relevant ones.
108+
109+
---
110+
111+
## Field shape
112+
113+
```ts
114+
{
115+
id: "mfaEnforcedInternal" // stable camelCase key
116+
section: "security_practices"
117+
type: "boolean" // string | text | email | phone | url | country | boolean | enum | integer
118+
label: { en, de }
119+
description: { en, de } // why this field exists, with legal context
120+
legalBasis: "NIS2 Art. 21(2)(j)" // canonical citation
121+
required: true
122+
visibleWhen: { field: "isSaas", equals: true } // optional — gates section visibility
123+
options?: [{ value, label: { en, de } }] // type=enum only
124+
}
125+
```
126+
127+
The full Zod schema is in [`src/schema.ts`](./src/schema.ts).
128+
129+
---
130+
131+
## What this is NOT
132+
133+
- **Not legal advice.** Structured guidance based on our reading of NIS2, CIR 2024/2690, ENISA TIG, and BSI IT-Grundschutz. Consult qualified counsel.
134+
- **Not a certification scheme.** Answering "yes" to every question does not make a supplier compliant — it makes them claim compliance. Verification is the customer's responsibility.
135+
- **Not exhaustive.** Sector-specific obligations (KRITIS, energy, telecommunications, healthcare) may add fields. Pull requests welcome.
136+
137+
---
138+
139+
## Contributing
140+
141+
PRs welcome. We are particularly interested in:
142+
143+
- **Corrections to `legalBasis`** — if you read a directive article differently, open a PR with a primary-source citation. Press articles alone are not sufficient.
144+
- **Additional translations** — French, Italian, Spanish, etc. Extend `localisedString` to `{ en, de, fr, it, es }` (breaking change, target a `2.0.0` release).
145+
- **Sector extensions** — KRITIS-specific fields, healthcare patient-data fields, energy SCADA fields. Deliver as separate sections that compose with the base 6.
146+
- **Type refinements** — currently most "yes/no/details" fields are split into `boolean` + a separate `text` field gated on the boolean. If you have a cleaner pattern, propose it.
147+
148+
For substantial changes please open an issue first.
149+
150+
---
151+
152+
## Versioning
153+
154+
`supplier-questionnaire.json#version` follows semver:
155+
156+
- **Major** — breaking schema change (field added/removed/renamed, enum values changed, type changes)
157+
- **Minor** — fields or sections added; existing items unchanged
158+
- **Patch** — wording fixes, clarifications, legal-basis corrections
159+
160+
Older versions remain reachable via git tags.
161+
162+
---
163+
164+
## Related
165+
166+
- **Companion repo:** [NISD2/nis2-gap-assessment](https://github.com/NISD2/nis2-gap-assessment) — open NIS2 gap assessment under the same Zod-first model.
167+
- **Live tool:** [nisd2.eu](https://nisd2.eu) — supplier portal, gap assessment, NIS2 timeline, registration portals tracker.
168+
- **Source legislation:**
169+
- [Directive (EU) 2022/2555 (NIS2)](https://eur-lex.europa.eu/eli/dir/2022/2555/oj)
170+
- [Commission Implementing Regulation (EU) 2024/2690](https://eur-lex.europa.eu/eli/reg_impl/2024/2690/oj)
171+
- [ENISA Technical Implementation Guidance](https://www.enisa.europa.eu/publications/nis2-technical-implementation-guidance)
172+
- [BSI IT-Grundschutz](https://www.bsi.bund.de/DE/Themen/Unternehmen-und-Organisationen/Standards-und-Zertifizierung/IT-Grundschutz/it-grundschutz_node.html)
173+
174+
---
175+
176+
## Licence
177+
178+
Dual: **MIT** for code, **CC BY 4.0** for content. See [LICENSE](./LICENSE).
179+
180+
Substantive issues / partnership questions: [contact@nisd2.eu](mailto:contact@nisd2.eu).

0 commit comments

Comments
 (0)