diff --git a/writehat/components/FindingsStatusList.py b/writehat/components/FindingsStatusList.py new file mode 100644 index 0000000..3902d60 --- /dev/null +++ b/writehat/components/FindingsStatusList.py @@ -0,0 +1,11 @@ +import logging +from .base import * + +log = logging.getLogger(__name__) + +class Component(BaseComponent): + + default_name = 'Summary of Findings Status' + htmlTemplate = 'componentTemplates/FindingsStatusList.html' + iconType = 'fas fa-th-list' + iconColor = 'var(--orange)' \ No newline at end of file diff --git a/writehat/lib/finding.py b/writehat/lib/finding.py index 719ff68..74c0e5a 100644 --- a/writehat/lib/finding.py +++ b/writehat/lib/finding.py @@ -27,6 +27,17 @@ class BaseDatabaseFinding(WriteHatBaseModel): background = MarkdownField(max_length=30000, null=True, blank=True) remediation = MarkdownField(max_length=30000, null=True, blank=True) references = MarkdownField(max_length=30000, null=True, blank=True) + retest = MarkdownField(max_length=30000, null=True, blank=True) + # status choices + status_choices = ( + ("Open", "Open"), + ("Partially Fixed", "Partially Fixed"), + ("Risk Accepted", "Risk Accepted"), + ("Fixed", "Fixed"), + ("Not Fixed", "Not Fixed"), + ("Closed", "Closed"), +) + status = models.CharField(max_length=30, choices=status_choices, default="Open") # Overridden by child class scoringType = models.CharField(default='None', max_length=50) diff --git a/writehat/lib/findingForm.py b/writehat/lib/findingForm.py index cc46c13..eff7aa8 100644 --- a/writehat/lib/findingForm.py +++ b/writehat/lib/findingForm.py @@ -29,6 +29,12 @@ class FindingForm(forms.Form): max_length=30000, required=False) + retest = forms.CharField( + label='Retest', + widget=forms.Textarea(), + max_length=30000, + required=False) + categoryID = forms.UUIDField( label='Category', widget=CategoryBootstrapSelectEngagements( @@ -36,6 +42,19 @@ class FindingForm(forms.Form): ), required=True) + #vulnerability status + statusChoices = ( + ("Open", "Open"), + ("Partially Fixed", "Partially Fixed"), + ("Risk Accepted", "Risk Accepted"), + ("Fixed", "Fixed"), + ("Not Fixed", "Not Fixed"), + ("Closed", "Closed") + ) + status = forms.ChoiceField(choices=statusChoices, + label='Status', + required=True) + @property def className(self): @@ -420,7 +439,7 @@ def __init__(self, *args, **kwargs): class CVSSEngagementFindingForm(EngagementFindingForm,CVSSForm): findingGroup = forms.UUIDField(label='Finding Group',required=True) - field_order = ['name','findingGroup','categoryID','description','affectedResources','background','proofOfConcept','toolsUsed','remediation','references','cvssAV','cvssAC','cvssPR','cvssUI','cvssS','cvssC','cvssI','cvssA','cvssE','cvssRL','cvssRC','cvssCR','cvssIR','cvssAR','cvssMAV','cvssMAC','cvssMPR','cvssMUI','cvssMS','cvssMC','cvssMI','cvssMA',] + field_order = ['name','status','findingGroup','categoryID','description','affectedResources','background','proofOfConcept','retest','toolsUsed','remediation','references','cvssAV','cvssAC','cvssPR','cvssUI','cvssS','cvssC','cvssI','cvssA','cvssE','cvssRL','cvssRC','cvssCR','cvssIR','cvssAR','cvssMAV','cvssMAC','cvssMPR','cvssMUI','cvssMS','cvssMC','cvssMI','cvssMA',] class DREADEngagementFindingForm(EngagementFindingForm,DREADForm): @@ -452,12 +471,14 @@ class DREADEngagementFindingForm(EngagementFindingForm,DREADForm): field_order = [ 'name', + 'status', 'findingGroup', 'categoryID', 'description', 'affectedResources', 'dreadImpact', 'background', + 'retest', 'remediation', 'references', 'dreadDamage', @@ -476,7 +497,7 @@ class DREADEngagementFindingForm(EngagementFindingForm,DREADForm): class ProactiveEngagementFindingForm(EngagementFindingForm,ProactiveForm): findingGroup = forms.UUIDField(label='Finding Group',required=True) - field_order = ['name','findingGroup','categoryID','description','affectedResources','background','references'] + field_order = ['name','status','findingGroup','categoryID','description','affectedResources','background','retest','references'] class CVSSDatabaseFindingForm(CVSSForm): diff --git a/writehat/static/css/component/FindingsList.css b/writehat/static/css/component/FindingsList.css index 270c56b..0356f19 100644 --- a/writehat/static/css/component/FindingsList.css +++ b/writehat/static/css/component/FindingsList.css @@ -112,6 +112,16 @@ background-color: var(--stripe-background-color); } +div.finding div.finding-content > div.status::before { content: "Status" !important; } +div.finding div.finding-content > div.category::before { content: "Category" !important; } +div.finding div.finding-content > div.affected-resources::before { content: "Affected Resources" !important; } +div.finding div.finding-content > div.description::before { content: "Description" !important; } +div.finding div.finding-content > div.background::before { content: "Background" !important; } +div.finding div.finding-content > div.retest::before { content: "Retest" !important; } +div.finding div.finding-content > div.remediation::before { content: "Remediation" !important; } +div.finding div.finding-content > div.references::before { content: "References" !important; } + +/* CVSS SPECIFIC */ .finding .finding-content:last-child{ height: 100%; } diff --git a/writehat/static/css/component/FindingsStatusList.css b/writehat/static/css/component/FindingsStatusList.css new file mode 100644 index 0000000..a636e1a --- /dev/null +++ b/writehat/static/css/component/FindingsStatusList.css @@ -0,0 +1,89 @@ +div.finding-group-name { + padding: .5em; + margin: .5em; + font-weight: bold; + font-size: 1.1em; + width: 100%; + text-align: center; + } + + p.findings-status-summary-entry { + padding: .5rem; + padding-left: 1rem; + padding-right: 1rem; + margin: 0 10rem 2px calc(2rem + 4px); + position: relative; + background-color: #BEDDBA; + } + + p.findings-status-summary-entry::before { + content: ''; + padding: 1rem; + position: absolute; + background-color: #7BB274; + display: inline-block; + left: calc(-2rem - 2px); + bottom: 0; + top: 0; + } + + p.findings-status-summary-entry::after { + content: attr(finding-status); + padding: .5rem; + padding-left: 1rem; + padding-right: 1rem; + position: absolute; + background-color: #BEDDBA; + display: inline-block; + left: calc(36.8rem + 2px); + bottom: 0; + top: 0; + color: black; + font-weight: bold; + font-size: 16px; + overflow: hidden; + white-space: nowrap; + width: 8rem; + text-align: center; +} + + p.findings-status-summary-entry a { + text-decoration: none; + color: black; + font-weight: bold; + font-size: 16px; + } + + p.findings-status-summary-title-entry { + color: black; + padding: .5rem; + padding-left: 1rem; + padding-right: 1rem; + margin: 0 10rem 2px calc(2rem + 4px); + position: relative; + text-decoration: none; + color: black; + font-weight: bold; + font-size: 16px; +} + + p.findings-status-summary-title-entry::after { + content: 'Status'; + padding: .5rem; + padding-left: 1rem; + padding-right: 1rem; + position: absolute; + background-color: #ffffff; + display: inline-block; + left: calc(36.8rem + 2px); + bottom: 0; + top: 0; + color: black; + font-weight: bold; + font-size: 16px; + overflow: hidden; + white-space: nowrap; + width: 8rem; + text-align: center; +} + diff --git a/writehat/templates/componentTemplates/CVSSFinding.html b/writehat/templates/componentTemplates/CVSSFinding.html index 8126588..0439de7 100644 --- a/writehat/templates/componentTemplates/CVSSFinding.html +++ b/writehat/templates/componentTemplates/CVSSFinding.html @@ -13,6 +13,24 @@
{{ finding.severity }} + + {% endif %} + {% if showStatus %} +
+
+ {{ finding.status }} +
+
+ {% endif %} +
+
+ {{ finding.categoryFull }} +
+
+ {% if finding.affectedResources %} +
+
+ {% markdown finding.affectedResources %}
{% if showFindingNumbers %}[{{ finding.number }}] {% endif %}{{ finding.name }}
@@ -54,6 +72,19 @@ {% markdown finding.description %}
+ + {% endif %} + {% if finding.retest %} +
+
+ {% markdown finding.retest %} +
+
+ {% endif %} + {% if finding.remediation %} +
+
+ {% markdown finding.remediation %} {% endif %} {% if finding.background %}
diff --git a/writehat/templates/componentTemplates/DREADFinding.html b/writehat/templates/componentTemplates/DREADFinding.html index d4af1d3..96951da 100644 --- a/writehat/templates/componentTemplates/DREADFinding.html +++ b/writehat/templates/componentTemplates/DREADFinding.html @@ -5,6 +5,16 @@ {% include 'componentTemplates/Heading.html' with classes="finding-heading" %} {% endif %}
+ {% if showStatus %} +
+
+ {{ finding.status }} +
+
+ {% endif %} +
+
+ {{ finding.categoryFull }}
@@ -117,6 +127,24 @@ {% markdown finding.descDiscoverability %}
+ {% endif %} +
+
( + D:{{ finding.dread.dict.dreadDamage }} + + R:{{ finding.dread.dict.dreadReproducibility }} + + E:{{ finding.dread.dict.dreadExploitability }} + + A:{{ finding.dread.dict.dreadAffectedUsers }} + + D:{{ finding.dread.dict.dreadDiscoverability }} + ) / 5 = {{ finding.score }} ({{ finding.severity }})
+
+ {% if finding.retest %} +
+
+ {% markdown finding.retest %} +
+
+ {% endif %} + {% if finding.remediation %} {% endif %}
diff --git a/writehat/templates/componentTemplates/FindingsStatusList.html b/writehat/templates/componentTemplates/FindingsStatusList.html new file mode 100644 index 0000000..bc12b4c --- /dev/null +++ b/writehat/templates/componentTemplates/FindingsStatusList.html @@ -0,0 +1,24 @@ +
+ {% include 'componentTemplates/Heading.html' with name=name %} + + {% for fgroup in report.ordered_fgroups %} + + + {% if fgroup.findings %} +
+ {{ fgroup.name }} +
+

+ Finding +

+ {% for finding in fgroup %} + {% if not report.finding_uuids or finding.id in report.finding_uuids %} +

+ [{{ finding.number }}] {{ finding.name }} +

+ {% endif %} + {% endfor %} + + {% endif %} + {% endfor %} +
\ No newline at end of file diff --git a/writehat/templates/componentTemplates/ProactiveFinding.html b/writehat/templates/componentTemplates/ProactiveFinding.html index 9ddbff5..ea796df 100644 --- a/writehat/templates/componentTemplates/ProactiveFinding.html +++ b/writehat/templates/componentTemplates/ProactiveFinding.html @@ -1,4 +1,23 @@ {% load custom_tags %} +
+
+
+ {{ finding.severity }} +
+
+ {% if showFindingNumbers %}[{{ finding.number }}] {% endif %}{{ finding.name }} +
+
+ {% if showStatus %} +
+
+ {{ finding.status }} +
+
+ {% endif %} +
+
+ {{ finding.categoryFull }}
{% if first %} @@ -43,6 +62,15 @@ {% markdown finding.background %}
+ {% endif %} + {% if finding.retest %} +
+
+ {% markdown finding.retest %} +
+
+ {% endif %} + {% if finding.references %} {% endif %} {% if finding.references %}