Skip to content

Commit c335314

Browse files
finding_templates: make tags work again
1 parent c0a717a commit c335314

1 file changed

Lines changed: 72 additions & 3 deletions

File tree

dojo/finding/views.py

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1704,6 +1704,9 @@ def mktemplate(request, fid):
17041704
)
17051705
template.save()
17061706
template.tags = finding.tags.all()
1707+
# Ensure template tags exist in Finding's tag model
1708+
# (They should already exist since they come from a finding, but ensure for consistency)
1709+
ensure_template_tags_in_finding_model(template)
17071710

17081711
for vulnerability_id in finding.vulnerability_ids:
17091712
Vulnerability_Id_Template(
@@ -1782,12 +1785,52 @@ def find_template_to_apply(request, fid):
17821785
def choose_finding_template_options(request, tid, fid):
17831786
finding = get_object_or_404(Finding, id=fid)
17841787
template = get_object_or_404(Finding_Template, id=tid)
1785-
data = finding.__dict__
1786-
# Not sure what's going on here, just leave same as with django-tagging
1787-
data["tags"] = [tag.name for tag in template.tags.all()]
1788+
data = finding.__dict__.copy()
1789+
# Remove tags and other non-serializable fields
1790+
data.pop("tags", None)
1791+
data.pop("_state", None)
1792+
data.pop("_tags_tagulous", None)
1793+
template_tag_names = [tag.name for tag in template.tags.all()]
1794+
# Add tags as comma-separated string for TagField
1795+
if template_tag_names:
1796+
data["tags"] = ", ".join(template_tag_names)
17881797
data["vulnerability_ids"] = "\n".join(finding.vulnerability_ids)
17891798

17901799
form = ApplyFindingTemplateForm(data=data, template=template)
1800+
# Combine tags from both Finding_Template and Finding tag models
1801+
# This ensures we don't lose tags that exist on templates but may have been removed from findings
1802+
if "tags" in form.fields:
1803+
finding_tag_model = Finding.tags.tag_model
1804+
template_tag_model = Finding_Template.tags.tag_model
1805+
1806+
# Get all tags from Finding_Template model
1807+
template_tags = set(template_tag_model.objects.values_list("name", flat=True))
1808+
# Get all tags from Finding model
1809+
finding_tags = set(finding_tag_model.objects.values_list("name", flat=True))
1810+
# Combine both sets to get all unique tag names
1811+
all_tag_names = template_tags | finding_tags
1812+
1813+
# Ensure all tags from both models exist in Finding's tag model (where they'll be applied)
1814+
# Strictly speaking, creating tags here isn't necessary since TagField can create them on save,
1815+
# but it's the safest option to avoid tags getting lost or not getting rendered properly.
1816+
# This prevents tagulous from removing tags that only exist on templates and ensures
1817+
# TagField can display them correctly during form rendering.
1818+
# Store tag objects in a dict for reuse
1819+
tag_objects = {}
1820+
for tag_name in all_tag_names:
1821+
tag, _ = finding_tag_model.objects.get_or_create(
1822+
name=tag_name,
1823+
defaults={"name": tag_name, "protected": False},
1824+
)
1825+
tag_objects[tag_name] = tag
1826+
1827+
# Update autocomplete_tags to include tags from both models
1828+
form.fields["tags"].autocomplete_tags = finding_tag_model.objects.all().order_by("name")
1829+
1830+
# Set initial value using template tags (already created above)
1831+
if template_tag_names:
1832+
template_finding_tags = [tag_objects[tag_name] for tag_name in template_tag_names]
1833+
form.fields["tags"].initial = template_finding_tags
17911834
product_tab = Product_Tab(
17921835
finding.test.engagement.product,
17931836
title="Finding Template Options",
@@ -2109,6 +2152,28 @@ def export_templates_to_json(request):
21092152
return HttpResponse(leads_as_json, content_type="json")
21102153

21112154

2155+
def ensure_template_tags_in_finding_model(template):
2156+
"""
2157+
Ensure all tags on a Finding_Template also exist in Finding's tag model.
2158+
This prevents tags from being lost when tagulous cleans up unused tags and ensures
2159+
tags can be properly applied when templates are used.
2160+
"""
2161+
if not template or not template.pk:
2162+
return
2163+
2164+
finding_tag_model = Finding.tags.tag_model
2165+
2166+
# Get all tag names from the template
2167+
template_tag_names = [tag.name for tag in template.tags.all()]
2168+
2169+
# Ensure each tag exists in Finding's tag model
2170+
for tag_name in template_tag_names:
2171+
finding_tag_model.objects.get_or_create(
2172+
name=tag_name,
2173+
defaults={"name": tag_name, "protected": False},
2174+
)
2175+
2176+
21122177
def apply_cwe_mitigation(apply_to_findings, template, *, update=True):
21132178
count = 0
21142179
if apply_to_findings and template.template_match and template.cwe is not None:
@@ -2191,6 +2256,8 @@ def add_template(request):
21912256
template, form.cleaned_data["vulnerability_ids"].split(),
21922257
)
21932258
form.save_m2m()
2259+
# Ensure template tags exist in Finding's tag model
2260+
ensure_template_tags_in_finding_model(template)
21942261
count = apply_cwe_mitigation(
21952262
form.cleaned_data["apply_to_findings"], template,
21962263
)
@@ -2238,6 +2305,8 @@ def edit_template(request, tid):
22382305
)
22392306
template.save()
22402307
form.save_m2m()
2308+
# Ensure template tags exist in Finding's tag model
2309+
ensure_template_tags_in_finding_model(template)
22412310

22422311
count = apply_cwe_mitigation(
22432312
form.cleaned_data["apply_to_findings"], template,

0 commit comments

Comments
 (0)