Unveränderter Stand von certvia/dev (a48c5fb) plus Craftvia-Spezifikation und Brandbook unter docs/craftvia/. ISMS-Module werden im Folgecommit entfernt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
63 lines
3.0 KiB
Python
63 lines
3.0 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"
|
|
c["FLAG_FW_TISAX"]=True; c["FLAG_FW_ISO27001"]=False # dieses Skript prueft die TISAX-Sicht
|
|
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])
|
|
# Zwei Framework-Mappings teilen sich diese Bibliothek: die Anker des ISO-Mappings
|
|
# werden hier ausgeblendet und von _verify_iso.py geprueft.
|
|
iso_anchors=set()
|
|
_iso=os.path.join(BASE,"mapping-iso.json")
|
|
if os.path.exists(_iso):
|
|
for a in json.load(open(_iso,encoding="utf-8"))["anforderungen"]:
|
|
iso_anchors.add(a["req_anchor"]); iso_anchors.add(a["impl_anchor"])
|
|
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"])
|
|
fa-=(iso_anchors-ma) # nur ISO-exklusive Anker ausblenden; gemeinsam genutzte bleiben geprueft
|
|
# 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")
|