Skip to content

Commit fa3ce1b

Browse files
committed
wip cicd split
1 parent daf6d57 commit fa3ce1b

7 files changed

Lines changed: 181 additions & 8 deletions

File tree

dojo/api_v2/serializers.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
App_Analysis,
5050
BurpRawRequestResponse,
5151
Check_List,
52+
CICDInfrastructure,
5253
Development_Environment,
5354
Dojo_User,
5455
DojoMeta,
@@ -811,6 +812,12 @@ class Meta:
811812
fields = "__all__"
812813

813814

815+
class CICDInfrastructureSerializer(serializers.ModelSerializer):
816+
class Meta:
817+
model = CICDInfrastructure
818+
fields = "__all__"
819+
820+
814821
class ToolTypeSerializer(serializers.ModelSerializer):
815822
class Meta:
816823
model = Tool_Type

dojo/api_v2/views.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
App_Analysis,
8787
BurpRawRequestResponse,
8888
Check_List,
89+
CICDInfrastructure,
8990
Development_Environment,
9091
Dojo_User,
9192
DojoMeta,
@@ -2209,6 +2210,19 @@ def get_queryset(self):
22092210

22102211

22112212
# Authorization: configuration
2213+
class CICDInfrastructureViewSet(
2214+
DojoModelViewSet,
2215+
):
2216+
serializer_class = serializers.CICDInfrastructureSerializer
2217+
queryset = CICDInfrastructure.objects.none()
2218+
filter_backends = (DjangoFilterBackend,)
2219+
filterset_fields = ["id", "name", "infrastructure_type"]
2220+
permission_classes = (permissions.UserHasConfigurationPermissionSuperuser,)
2221+
2222+
def get_queryset(self):
2223+
return CICDInfrastructure.objects.all().order_by("id")
2224+
2225+
22122226
class ToolTypesViewSet(
22132227
DojoModelViewSet,
22142228
):
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import logging
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
logger = logging.getLogger(__name__)
7+
8+
9+
def migrate_tool_configs_to_cicd_infrastructure(apps, schema_editor):
10+
"""
11+
For each Tool_Configuration referenced by an engagement's build_server,
12+
source_code_management_server, or orchestration_engine FK, create a
13+
CICDInfrastructure record and point the new engagement FK to it.
14+
"""
15+
Engagement = apps.get_model("dojo", "Engagement")
16+
CICDInfrastructure = apps.get_model("dojo", "CICDInfrastructure")
17+
18+
field_mappings = [
19+
("build_server", "cicd_build_server", "build_server"),
20+
("source_code_management_server", "cicd_scm_server", "scm_server"),
21+
("orchestration_engine", "cicd_orchestration_engine", "orchestration"),
22+
]
23+
24+
for old_field, new_field, infra_type in field_mappings:
25+
engagements_with_old_fk = Engagement.objects.filter(
26+
**{f"{old_field}__isnull": False},
27+
).select_related(old_field)
28+
29+
for engagement in engagements_with_old_fk:
30+
tc = getattr(engagement, old_field)
31+
if tc is None:
32+
continue
33+
34+
cicd_infra, created = CICDInfrastructure.objects.get_or_create(
35+
name=tc.name,
36+
infrastructure_type=infra_type,
37+
defaults={
38+
"description": tc.description or "",
39+
"url": tc.url or "",
40+
},
41+
)
42+
if created:
43+
logger.info(
44+
"Created CICDInfrastructure '%s' (type=%s) from Tool_Configuration '%s'",
45+
cicd_infra.name, infra_type, tc.name,
46+
)
47+
48+
setattr(engagement, new_field, cicd_infra)
49+
engagement.save(update_fields=[new_field])
50+
51+
52+
class Migration(migrations.Migration):
53+
54+
dependencies = [
55+
("dojo", "0263_language_type_unique_language"),
56+
]
57+
58+
operations = [
59+
# Step 1: Create CICDInfrastructure model
60+
migrations.CreateModel(
61+
name="CICDInfrastructure",
62+
fields=[
63+
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
64+
("name", models.CharField(max_length=200)),
65+
("description", models.CharField(blank=True, max_length=2000, null=True)),
66+
("url", models.URLField(blank=True, help_text="Public URL of the tool (e.g., https://jenkins.company.com)", max_length=2000, null=True)),
67+
("infrastructure_type", models.CharField(choices=[("build_server", "Build Server"), ("scm_server", "SCM Server"), ("orchestration", "Orchestration Engine")], max_length=30)),
68+
],
69+
options={
70+
"ordering": ["name"],
71+
},
72+
),
73+
# Step 2: Add new FK fields to Engagement (before removing old ones)
74+
migrations.AddField(
75+
model_name="engagement",
76+
name="cicd_build_server",
77+
field=models.ForeignKey(
78+
blank=True, null=True,
79+
help_text="Build server used for this CI/CD engagement",
80+
limit_choices_to={"infrastructure_type": "build_server"},
81+
on_delete=django.db.models.deletion.SET_NULL,
82+
related_name="engagements_as_build_server",
83+
to="dojo.cicdinfrastructure",
84+
verbose_name="Build Server",
85+
),
86+
),
87+
migrations.AddField(
88+
model_name="engagement",
89+
name="cicd_scm_server",
90+
field=models.ForeignKey(
91+
blank=True, null=True,
92+
help_text="Source code management server used for this CI/CD engagement",
93+
limit_choices_to={"infrastructure_type": "scm_server"},
94+
on_delete=django.db.models.deletion.SET_NULL,
95+
related_name="engagements_as_scm_server",
96+
to="dojo.cicdinfrastructure",
97+
verbose_name="SCM Server",
98+
),
99+
),
100+
migrations.AddField(
101+
model_name="engagement",
102+
name="cicd_orchestration_engine",
103+
field=models.ForeignKey(
104+
blank=True, null=True,
105+
help_text="Orchestration engine used for this CI/CD engagement",
106+
limit_choices_to={"infrastructure_type": "orchestration"},
107+
on_delete=django.db.models.deletion.SET_NULL,
108+
related_name="engagements_as_orchestration",
109+
to="dojo.cicdinfrastructure",
110+
verbose_name="Orchestration Engine",
111+
),
112+
),
113+
# Step 3: Migrate data from Tool_Configuration to CICDInfrastructure
114+
migrations.RunPython(
115+
migrate_tool_configs_to_cicd_infrastructure,
116+
reverse_code=migrations.RunPython.noop,
117+
),
118+
# Step 4: Remove old FK fields from Engagement
119+
migrations.RemoveField(
120+
model_name="engagement",
121+
name="build_server",
122+
),
123+
migrations.RemoveField(
124+
model_name="engagement",
125+
name="source_code_management_server",
126+
),
127+
migrations.RemoveField(
128+
model_name="engagement",
129+
name="orchestration_engine",
130+
),
131+
]

dojo/engagement/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1606,8 +1606,8 @@ def get_excludes():
16061606

16071607

16081608
def get_foreign_keys():
1609-
return ["build_server", "lead", "orchestration_engine", "preset", "product",
1610-
"report_type", "requester", "source_code_management_server"]
1609+
return ["cicd_build_server", "cicd_orchestration_engine", "cicd_scm_server",
1610+
"lead", "preset", "product", "report_type", "requester"]
16111611

16121612

16131613
def csv_export(request):

dojo/forms.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,10 +1058,10 @@ def __init__(self, *args, **kwargs):
10581058
del self.fields["build_id"]
10591059
del self.fields["commit_hash"]
10601060
del self.fields["branch_tag"]
1061-
del self.fields["build_server"]
1062-
del self.fields["source_code_management_server"]
1061+
del self.fields["cicd_build_server"]
1062+
del self.fields["cicd_scm_server"]
10631063
# del self.fields['source_code_management_uri']
1064-
del self.fields["orchestration_engine"]
1064+
del self.fields["cicd_orchestration_engine"]
10651065
else:
10661066
del self.fields["test_strategy"]
10671067
del self.fields["status"]

dojo/models.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,25 @@ def __str__(self):
13371337
return self.name
13381338

13391339

1340+
class CICDInfrastructure(models.Model):
1341+
INFRASTRUCTURE_TYPE_CHOICES = (
1342+
("build_server", "Build Server"),
1343+
("scm_server", "SCM Server"),
1344+
("orchestration", "Orchestration Engine"),
1345+
)
1346+
1347+
name = models.CharField(max_length=200)
1348+
description = models.CharField(max_length=2000, null=True, blank=True)
1349+
url = models.URLField(max_length=2000, null=True, blank=True, help_text=_("Public URL of the tool (e.g., https://jenkins.company.com)"))
1350+
infrastructure_type = models.CharField(max_length=30, choices=INFRASTRUCTURE_TYPE_CHOICES)
1351+
1352+
class Meta:
1353+
ordering = ["name"]
1354+
1355+
def __str__(self):
1356+
return self.name
1357+
1358+
13401359
class Product_API_Scan_Configuration(models.Model):
13411360
product = models.ForeignKey(Product, null=False, blank=False, on_delete=models.CASCADE)
13421361
tool_configuration = models.ForeignKey(Tool_Configuration, null=False, blank=False, on_delete=models.CASCADE)
@@ -1472,10 +1491,10 @@ class Engagement(BaseModel):
14721491
null=True, blank=True, help_text=_("Commit hash from repo"), verbose_name=_("Commit Hash"))
14731492
branch_tag = models.CharField(editable=True, max_length=150,
14741493
null=True, blank=True, help_text=_("Tag or branch of the product the engagement tested."), verbose_name=_("Branch/Tag"))
1475-
build_server = models.ForeignKey(Tool_Configuration, verbose_name=_("Build Server"), help_text=_("Build server responsible for CI/CD test"), null=True, blank=True, related_name="build_server", on_delete=models.CASCADE)
1476-
source_code_management_server = models.ForeignKey(Tool_Configuration, null=True, blank=True, verbose_name=_("SCM Server"), help_text=_("Source code server for CI/CD test"), related_name="source_code_management_server", on_delete=models.CASCADE)
14771494
source_code_management_uri = models.URLField(max_length=600, null=True, blank=True, editable=True, verbose_name=_("Repo"), help_text=_("Resource link to source code"))
1478-
orchestration_engine = models.ForeignKey(Tool_Configuration, verbose_name=_("Orchestration Engine"), help_text=_("Orchestration service responsible for CI/CD test"), null=True, blank=True, related_name="orchestration", on_delete=models.CASCADE)
1495+
cicd_build_server = models.ForeignKey("CICDInfrastructure", null=True, blank=True, related_name="engagements_as_build_server", on_delete=models.SET_NULL, limit_choices_to={"infrastructure_type": "build_server"}, verbose_name=_("Build Server"), help_text=_("Build server used for this CI/CD engagement"))
1496+
cicd_scm_server = models.ForeignKey("CICDInfrastructure", null=True, blank=True, related_name="engagements_as_scm_server", on_delete=models.SET_NULL, limit_choices_to={"infrastructure_type": "scm_server"}, verbose_name=_("SCM Server"), help_text=_("Source code management server used for this CI/CD engagement"))
1497+
cicd_orchestration_engine = models.ForeignKey("CICDInfrastructure", null=True, blank=True, related_name="engagements_as_orchestration", on_delete=models.SET_NULL, limit_choices_to={"infrastructure_type": "orchestration"}, verbose_name=_("Orchestration Engine"), help_text=_("Orchestration engine used for this CI/CD engagement"))
14791498
deduplication_on_engagement = models.BooleanField(default=False, verbose_name=_("Deduplication within this engagement only"), help_text=_("If enabled deduplication will only mark a finding in this engagement as duplicate of another finding if both findings are in this engagement. If disabled, deduplication is on the product level."))
14801499

14811500
tags = TagField(blank=True, force_lowercase=True, help_text=_("Add tags that help describe this engagement. Choose from the list or add new tags. Press Enter key to add."))

dojo/urls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
AppAnalysisViewSet,
1717
BurpRawRequestResponseViewSet,
1818
CeleryViewSet,
19+
CICDInfrastructureViewSet,
1920
ConfigurationPermissionViewSet,
2021
DevelopmentEnvironmentViewSet,
2122
DojoMetaViewSet,
@@ -152,6 +153,7 @@
152153
v2_api.register(r"tests", TestsViewSet, basename="test")
153154
v2_api.register(r"test_types", TestTypesViewSet, basename="test_type")
154155
v2_api.register(r"test_imports", TestImportViewSet, basename="test_imports")
156+
v2_api.register(r"cicd_infrastructure", CICDInfrastructureViewSet, basename="cicd_infrastructure")
155157
v2_api.register(r"tool_configurations", ToolConfigurationsViewSet, basename="tool_configuration")
156158
v2_api.register(r"tool_product_settings", ToolProductSettingsViewSet, basename="tool_product_settings")
157159
v2_api.register(r"tool_types", ToolTypesViewSet, basename="tool_type")

0 commit comments

Comments
 (0)