Skip to content

Commit

Permalink
add compact ISA report
Browse files Browse the repository at this point in the history
verinice-veo#3177
  • Loading branch information
jochenkemnade committed Oct 2, 2024
1 parent edabdb7 commit 31e0e3a
Show file tree
Hide file tree
Showing 6 changed files with 376 additions and 5 deletions.
23 changes: 20 additions & 3 deletions src/main/java/org/veo/reporting/Demo.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ static void runDemo(ConfigurableApplicationContext ctx) throws IOException {
var requestId = ctx.getEnvironment().getProperty("veo.demorequestid");
var scopeIdItgs = ctx.getEnvironment().getProperty("veo.demoscopeiditbp");
var scopeIdNIS2 = ctx.getEnvironment().getProperty("veo.demoscopeidnis2");
var isaId = ctx.getEnvironment().getProperty("veo.demoisaid");
var veoClient = ctx.getBean(VeoClient.class);
var authHeader = "Bearer " + token;
Map<Locale, Map<String, Object>> entriesForLanguage = new HashMap<>();
Expand All @@ -81,6 +82,7 @@ static void runDemo(ConfigurableApplicationContext ctx) throws IOException {
boolean createRequestReports = requestId != null;
boolean createItgsReports = scopeIdItgs != null;
boolean createNIS2Reports = scopeIdNIS2 != null;
boolean createISAReports = isaId != null;

DataProvider dataProvider =
dataSpec -> {
Expand All @@ -105,6 +107,8 @@ static void runDemo(ConfigurableApplicationContext ctx) throws IOException {
url = url.replace(TARGET_ID_PLACEHOLDER, scopeIdItgs);
} else if ("organization".equals(key)) {
url = url.replace(TARGET_ID_PLACEHOLDER, scopeIdNIS2);
} else if ("isa".equals(key)) {
url = url.replace(TARGET_ID_PLACEHOLDER, isaId);
} else if (url.contains("targetId")) {
throw new IllegalArgumentException("Unhandled url: " + url);
}
Expand Down Expand Up @@ -133,7 +137,8 @@ static void runDemo(ConfigurableApplicationContext ctx) throws IOException {
createDPIncidentReports,
createRequestReports,
createItgsReports,
createNIS2Reports);
createNIS2Reports,
createISAReports);
Path template = Paths.get("src/main/resources/templates");
try (WatchService watchService = FileSystems.getDefault().newWatchService()) {

Expand Down Expand Up @@ -161,7 +166,8 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
createDPIncidentReports,
createRequestReports,
createItgsReports,
createNIS2Reports);
createNIS2Reports,
createISAReports);
}
key.reset();
}
Expand All @@ -181,7 +187,8 @@ static void createReports(
boolean createDPIncidentReports,
boolean createRequestReports,
boolean createItgsReports,
boolean createNIS2Reports)
boolean createNIS2Reports,
boolean createISAReports)
throws IOException {

ReportCreationParameters parametersGermany =
Expand Down Expand Up @@ -381,6 +388,16 @@ static void createReports(
parametersUS,
entriesForLanguage.get(Locale.US));
}
if (createISAReports) {
createReport(
reportEngine,
"tisax-compact",
"/tmp/tisax-compact.pdf",
dataProvider,
MediaType.APPLICATION_PDF_VALUE,
parametersGermany,
entriesForLanguage.get(Locale.GERMANY));
}
} catch (IOException | TemplateException e) {
logger.error("Error creating reports", e);
}
Expand Down
25 changes: 25 additions & 0 deletions src/main/resources/reports/tisax-compact.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": {
"de": "ISA: Information Security Assessment 6"
},
"domainName": "TISAX",
"description": {
"de": "ISA: Information Security Assessment 6"
},
"templateFile": "tisax-compact.md",
"templateType": "text/markdown",
"outputTypes": [
"application/pdf"
],
"targetTypes": [
{
"modelType": "scope",
"subTypes": [
"SCP_InformationSecurityAssessment"
]
}
],
"data": {
"isa": "/scopes/${targetId}"
}
}
279 changes: 279 additions & 0 deletions src/main/resources/templates/tisax-compact.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
<#import "/libs/commons.md" as com>

<#assign table = com.table
def = com.def
multiline = com.multiline
heading = com.heading />

<style>
<#include "styles/default.css">
h1, h2, h3, h4, h5, h6 {
page-break-after: avoid;
}

td {
vertical-align: top;
}

.main_page {
page-break-after: always;
}

.main_page table th:first-child, .main_page table td:first-child {
width: 8cm;
padding-left:0;
}

.fullwidth {
width: 100%;
}

.nobreak {
page-break-inside: avoid;
}

.maturityred {
color: #f00;
}

.maturityorange {
color: #f90;
}

.maturitygreen {
color: #396;
}

table.maturitytable > tbody > tr > td:nth-child(3),
table.maturitytable > tbody > tr > td:nth-child(4) {
text-align: center;
}

.paginated {
-fs-table-paginate: paginate;
}
</style>

<#assign domain=domains?filter(it->it.name == 'TISAX')?filter(it->isa.domains?keys?seq_contains(it.id))?sort_by("createdAt")?last />

<#assign scope = scopes?filter(it->it.domains[domain.id].subType == 'SCP_Organization')?filter(it->it.members?map(it->it._self)?seq_contains(isa._self))?first! />

<#assign usedControls = isa.getMembersWithType('control')>


<div class="footer-left">
<table>
<tr>
<td>Scope: </td>
<td>${scope.name!}</td>
</tr>
<tr>
<td>${bundle.creation_date}: </td>
<td>${.now?date}</td>
</tr>
</table>
</div>

<div class="cover">
<h1><@multiline bundle.title/></h1>
<p>powered by verinice</p>
</div>


# ${bundle.main_page} {#main_page}

<h2>Information Security Assessment<br/>${isa.name}<br/>kompakt</h2>
<div class="main_page">

<#if scope?has_content>

<@table bundle.scope_SCP_Organization_singular,
scope,
[{'name' : 'abbreviation name'},
'scope_address_address1',
'scope_address_address2',
{'scope_address_postcode, scope_address_city' : 'scope_address_postcode scope_address_city'},
{'scope_address_country, scope_address_state' : 'scope_address_country scope_address_state'},
'scope_identification_duns'
],
domain/>

</#if>


<@table bundle.scope_SCP_InformationSecurityAssessment_singular,
isa,
['scope_tisax_scopeID',
{'isa_scope' : 'description'},
'scope_tisax_assessmentDate'
],
domain/>

<#assign tisaxContact = isa.findFirstLinked('scope_tisaxContact') !>

<#if tisaxContact?has_content>

<@table 'Ansprechpartner',
tisaxContact,
[
{'name' : 'person_generalInformation_givenName person_generalInformation_familyName'},
'person_contactInformation_office / person_contactInformation_mobile',
'person_contactInformation_email'
],
domain/>

</#if>

<#assign tisaxCreator = isa.findFirstLinked('scope_tisaxCreator') !>

<#if tisaxCreator?has_content>

<@table 'Ersteller',
tisaxCreator,
[
{'name' : 'person_generalInformation_givenName person_generalInformation_familyName'}
],
domain/>

</#if>


<div style="margin-top:1cm; margin-bottom:2cm">
Unterschrift:
</div>

Version 6.0.2

</div>

<#function averageMaturity controls cutback=-1>
<#local maturities = controls?map(it->it.control_isaMaturity_assessment!)?filter(it->it?has_content)?map(it->it?keep_after_last('_')?number) />
<#if (maturities?size == 0)>
<#return 0>
</#if>
<#local sum = 0>
<#list maturities as it>
<#if (cutback>0)>
<#local sum = sum + [it, cutback]?min>
<#else>
<#local sum = sum + it>
</#if>>
</#list>
<#return sum / maturities?size>
</#function>


| ISA Ergebnisse | | | |
|:---|:---|:---|:---|
| Ergebnis mit Kürzung auf Zielreifegrad | ${averageMaturity(usedControls, 3)?string["0.00"]} | Höchstes erreichbares Ergebnis:| ${3.00?string["0.00"]} |
{.table .fullwidth .paginated}

<#function unique_items seq>
<#local result = []>
<#list seq as item>
<#if ! result?seq_contains(item)>
<#local result = result + [item] />
</#if>
</#list>
<#return result>
</#function>


<#assign chapters=unique_items(usedControls?filter(it->it.domains[domain.id].subType != 'CTL_ISAControlDataProtection')?map(c->c.abbreviation?keep_before(".")))?sort>

<object type="jfreechart/veo-spiderweb" style="margin-bottom: 2cm;width:17cm;height:15cm;margin:auto;" title="Ergebnis je Kapitel (ohne Kürzung)" alt="Diagramm: Ergebnis je Kapitel (ohne Kürzung)" interiorGap="0.4">
<#list chapters as chapter>
<data row="Zielreifegrad" column="${chapter} ${bundle["chapter_label_"+chapter]}" value="3"/>
<#assign controls_chapter = usedControls?filter(c->c.abbreviation?starts_with(chapter))>
<data row="Ergebnis" column="${chapter} ${bundle["chapter_label_"+chapter]}" value="${averageMaturity(controls_chapter)?c}"/>
</#list>
</object>

<div class="pagebreak" />

<#assign subchapters=unique_items(usedControls?filter(it->it.domains[domain.id].subType != 'CTL_ISAControlDataProtection')?map(c->c.abbreviation?keep_before_last(".")))?sort>

<object type="jfreechart/veo-spiderweb" style="margin-bottom: 2cm;width:17cm;height:15cm;margin:auto;" title="Ergebnis je Unterkapitel (ohne Kürzung)" alt="Diagramm: Ergebnis je Unterkapitel (ohne Kürzung)" interiorGap="0.6">
<#list subchapters as subchapter>
<data row="Zielreifegrad" column="${subchapter} ${bundle["chapter_label_"+subchapter]}" value="3"/>
<#assign controls_subchapters = usedControls?filter(c->c.abbreviation?starts_with(subchapter))>
<data row="Ergebnis" column="${subchapter} ${bundle["chapter_label_"+subchapter]}" value="${averageMaturity(controls_subchapters)?c}"/>
</#list>
</object>

<div class="pagebreak" />

<#macro maturitydisplay control>
<#local targetLevel = 3>
<#local val = control.control_isaMaturity_assessment!>
<#if val?has_content>
<#local level=val?keep_after_last('_') />
<#local diff = targetLevel - level?number>
<#local class="maturitygreen"/>
<#if (diff >= 2)>
<#local class="maturityred"/>
<#elseif (diff >= 1) >
<#local class="maturityorange"/>
</#if>
<span class="${class}">${level}</span>
</#if>
</#macro>

<#assign isacontrols = usedControls?filter(it->it.domains[domain.id].subType == 'CTL_ISAControlInformationSecurity')?sort_by('abbreviation')>
<#assign prototypecontrols = usedControls?filter(it->it.domains[domain.id].subType == 'CTL_ISAControlPrototypeProtection')?sort_by('abbreviation')>
<#assign dataprotectioncontrols = usedControls?filter(it->it.domains[domain.id].subType == 'CTL_ISAControlDataProtection')?sort_by('abbreviation')>

# Information Security Assessment <br/> Ergebnisse - Informationssicherheit

|:---|:---|:---|:---|
| Ergebnis mit Kürzung auf Zielreifegrad | ${averageMaturity(isacontrols, 3)?string["0.00"]} | Höchstes erreichbares Ergebnis:| ${3.00?string["0.00"]}|
{.table .fullwidth}


## Details

| Nr. | Thema | Ziel-Reifegrad | Ergebnis |
|:---|:---|:---:|:---:|
<#list isacontrols as control>
| ${control.abbreviation} | ${control.name} | 3 | <@maturitydisplay control /> |
</#list>
{.table .fullwidth .maturitytable .paginated}

<#if prototypecontrols?has_content>

<div class="pagebreak" />


# Information Security Assessment <br/> Ergebnisse - Prototypenschutz

|:---|:---|:---|:---|
| Ergebnis mit Kürzung auf Zielreifegrad | ${averageMaturity(prototypecontrols, 3)?string["0.00"]} | Höchstes erreichbares Ergebnis:| ${3.00?string["0.00"]} |
{.table .fullwidth}


## Details

| Nr. | Thema | Ziel-Reifegrad | Ergebnis |
|:---|:---|:---:|:---:|
<#list prototypecontrols as control>
| ${control.abbreviation} | ${control.name} | 3 | <@maturitydisplay control /> |
</#list>
{.table .fullwidth .maturitytable .paginated}
</#if>

<#if prototypecontrols?has_content>

<div class="pagebreak" />


# Information Security Assessment <br/> Ergebnisse - Zusätzliche Anforderungen an den Datenschutz

## Details

| Nr. | Thema | Bewertung |
|:---|:---|:---|
<#list dataprotectioncontrols as control>
| ${control.abbreviation} | ${control.name} | ${(bundle[control.control_isaDataProtection_assessment])!} |
</#list>
{.table .fullwidth}
</#if>
Loading

0 comments on commit 31e0e3a

Please sign in to comment.