Files
msolarczekandClaude Opus 4.8 522508aaf3 GAP WP2.1: Inline-VA-Verweise + Verify-Fix (F17)
Umsetzung aus dem GAP-Report Runde 2 (Umsetzungsanleitung), Etappe 1.

- WP2.1 (F3–F9, F19, N4, N7, N9): In 14 IMPL-Blöcken den zuständigen VA-Verweis
  inline ergänzt ({{LINK:VA-xx}}) — R02 1.3.1/1.3.2→VA-08, R03 1.4.1→VA-09,
  R04 1.6.1/1.6.2→VA-01 & 1.6.3→VA-02, R05 2.1.3→VA-12, R08 4.1.1/4.1.3/4.2.1→VA-03,
  R09 5.1.2→VA-07, R10 5.2.1→VA-04 & 5.2.6→VA-06, R13 6.1.2/6.1.3→VA-10.
  Damit verweisen alle 23 Controls mit zuständiger VA inline (zuvor 8).
- WP2.3/F17: _verify.py lief nicht (KeyError 'implementation' — Feld existiert nicht
  in mapping.json). Gefixt via .get(): Umsetzungstext wird zur Laufzeit über
  impl_anchor aus der .md aufgelöst (Variante 2 der Anleitung).

Verifiziert: _verify.py Render-Probleme 0, Mapping beidseitig sauber, keine neuen
Befunde (einzig vorbestehendes IMPL 3.1.3 = WP1.3/E2, ISB-Scope). Nicht-destruktiver
Re-Import in den Demo-Mandanten (8 Dokumente aktualisiert, Status/Anforderungen
erhalten); Browser: R02 rendert „(siehe VA-08)" als klickbaren Deep-Link.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 20:19:05 +02:00

54 lines
2.5 KiB
Python

# -*- coding: utf-8 -*-
# Korrekter rekursiver {{#if}}-Renderer (wie echtes Handlebars) zur Verifikation.
import re, glob, json, os
BASE=os.path.dirname(__file__)
schema=json.load(open(os.path.join(BASE,"variables.schema.json")))
allvars=set(schema["properties"].keys())
def make_ctx(inc, extra=None):
c={k:(True if k.startswith("FLAG_") else k) for k in allvars}
for k in ["FLAG_OT_USED","FLAG_DEV_INHOUSE","FLAG_CRYPTO_PKI","FLAG_CUSTOMER_SYSTEMS"]: c[k]=False
c["FLAG_INCLUDE_SHOULD"]=inc
c["ORG_NAME"]="Muster GmbH"; c["TOOL_NAME"]="ISMS-Portal"; c["REVIEW_CYCLE"]="jährlich"
if extra: c.update(extra)
return c
def render_if(t,c):
# rekursiv innerste Bloecke zuerst
pat=re.compile(r"\{\{#if (\w+)\}\}((?:(?!\{\{#if )(?!\{\{/if\}\}).)*?)\{\{/if\}\}",re.S)
prev=None
while prev!=t:
prev=t
t=pat.sub(lambda m:(m.group(2) if c.get(m.group(1)) else ""),t)
return t
def render(t,c):
t=render_if(t,c)
t=re.sub(r"\{\{LINK:[^}]+\}\}","[LINK]",t)
t=re.sub(r"\{\{(\w+)\}\}",lambda m:str(c[m.group(1)]) if m.group(1) in c else "«MISS:%s»"%m.group(1),t)
return t
files=sorted(glob.glob(os.path.join(BASE,"richtlinien/*.md")))+[os.path.join(BASE,"Nachweisregister_zentral.md"),os.path.join(BASE,"ISA-Mapping-Matrix.md")]
problems=0
for inc in [True,False]:
c=make_ctx(inc)
for fp in files:
r=render(open(fp,encoding="utf-8").read(),c)
bad=re.findall(r"\{\{.*?\}\}",r); miss=sorted(set(re.findall(r"«MISS:\w+»",r)))
if bad or miss:
problems+=1; print("!",os.path.basename(fp),"inc=%s"%inc,"open:",bad[:4],"miss:",miss[:4])
d=json.load(open(os.path.join(BASE,"mapping.json")))
fa=set()
for fp in glob.glob(os.path.join(BASE,"richtlinien/*.md")):
for m in re.findall(r"<!-- (REQ|IMPL) ([0-9.\-A-Za-z]+) -->",open(fp,encoding="utf-8").read()): fa.add(m[0]+" "+m[1])
ma=set()
for a in d["anforderungen"]: ma.add(a["req_anchor"]); ma.add(a["impl_anchor"])
# F17: mapping.json enthaelt kein 'implementation'-Feld; der Umsetzungstext wird zur
# Laufzeit ueber impl_anchor (Control-IMPL-Block) aus der jeweiligen .md aufgeloest.
leftover_hb=any("{{" in a["requirement"] or "{{" in a.get("implementation","") for a in d["anforderungen"])
print("Render-Probleme:",problems)
print("mapping-Anker ohne Datei:",sorted(ma-fa))
print("Datei-Anker ohne mapping:",sorted(fa-ma))
print("Handlebars-Reste in mapping-Text:",leftover_hb)
print("OK" if problems==0 and not (ma-fa) and not (fa-ma) and not leftover_hb else "PRUEFEN")