Skip to content

Commit a8246a0

Browse files
Maffoochclaude
andcommitted
Consolidate GitHub integration into self-contained dojo/github/ package
Collapse dojo/github.py and dojo/github_issue_link/ into a single dojo/github/ package matching the canonical dojo/url/ reference layout described in CLAUDE.md (models, admin, services, ui/forms, ui/views, ui/urls, templates). Backward-compat re-exports left in dojo/models.py and dojo/forms.py. No behavior change, no migrations. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 5178368 commit a8246a0

16 files changed

Lines changed: 151 additions & 120 deletions

File tree

dojo/forms.py

Lines changed: 8 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@
3232
from dojo.endpoint.utils import endpoint_filter, endpoint_get_or_create, validate_endpoints_to_add
3333
from dojo.engagement.queries import get_authorized_engagements
3434
from dojo.finding.queries import get_authorized_findings
35+
from dojo.github.ui.forms import ( # noqa: F401 -- backward compat
36+
DeleteGITHUBConfForm,
37+
ExpressGITHUBForm,
38+
GITHUB_IssueForm,
39+
GITHUB_Product_Form,
40+
GITHUBFindingForm,
41+
GITHUBForm,
42+
)
3543
from dojo.group.queries import get_authorized_groups, get_group_member_roles
3644
from dojo.jira import services as jira_services
3745
from dojo.jira.forms import ( # noqa: F401 backward compat
@@ -79,9 +87,6 @@
7987
Finding_Group,
8088
Finding_Template,
8189
General_Survey,
82-
GITHUB_Conf,
83-
GITHUB_Issue,
84-
GITHUB_PKey,
8590
Global_Role,
8691
Note_Type,
8792
Notes,
@@ -2801,42 +2806,6 @@ class Meta:
28012806
fields = ["id"]
28022807

28032808

2804-
class GITHUB_IssueForm(forms.ModelForm):
2805-
2806-
class Meta:
2807-
model = GITHUB_Issue
2808-
exclude = ["product"]
2809-
2810-
2811-
class GITHUBForm(forms.ModelForm):
2812-
api_key = forms.CharField(widget=forms.PasswordInput, required=True)
2813-
2814-
class Meta:
2815-
model = GITHUB_Conf
2816-
exclude = ["product"]
2817-
2818-
2819-
class DeleteGITHUBConfForm(forms.ModelForm):
2820-
id = forms.IntegerField(required=True,
2821-
widget=forms.widgets.HiddenInput())
2822-
2823-
class Meta:
2824-
model = GITHUB_Conf
2825-
fields = ["id"]
2826-
2827-
2828-
class ExpressGITHUBForm(forms.ModelForm):
2829-
password = forms.CharField(widget=forms.PasswordInput, required=True)
2830-
issue_key = forms.CharField(required=True, help_text="A valid issue ID is required to gather the necessary information.")
2831-
2832-
class Meta:
2833-
model = GITHUB_Conf
2834-
exclude = ["product", "epic_name_id", "open_status_key",
2835-
"close_status_key", "info_mapping_severity",
2836-
"low_mapping_severity", "medium_mapping_severity",
2837-
"high_mapping_severity", "critical_mapping_severity", "finding_text"]
2838-
2839-
28402809
class Benchmark_Product_SummaryForm(forms.ModelForm):
28412810

28422811
class Meta:
@@ -3222,25 +3191,6 @@ class Meta:
32223191
# fields = ['selenium_script']
32233192

32243193

3225-
class GITHUB_Product_Form(forms.ModelForm):
3226-
git_conf = forms.ModelChoiceField(queryset=GITHUB_Conf.objects.all(), label="GITHUB Configuration", required=False)
3227-
3228-
class Meta:
3229-
model = GITHUB_PKey
3230-
exclude = ["product"]
3231-
3232-
3233-
class GITHUBFindingForm(forms.Form):
3234-
def __init__(self, *args, **kwargs):
3235-
self.enabled = kwargs.pop("enabled")
3236-
super().__init__(*args, **kwargs)
3237-
self.fields["push_to_github"] = forms.BooleanField()
3238-
self.fields["push_to_github"].required = False
3239-
self.fields["push_to_github"].help_text = "Checking this will overwrite content of your Github issue, or create one."
3240-
3241-
push_to_github = forms.BooleanField(required=False)
3242-
3243-
32443194
class LoginBanner(forms.Form):
32453195
banner_enable = forms.BooleanField(
32463196
label="Enable login banner",

dojo/github/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import dojo.github.admin # noqa: F401

dojo/github/admin.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from django.contrib import admin
2+
3+
from dojo.github.models import (
4+
GITHUB_Clone,
5+
GITHUB_Conf,
6+
GITHUB_Details_Cache,
7+
GITHUB_Issue,
8+
GITHUB_PKey,
9+
)
10+
11+
admin.site.register(GITHUB_Conf)
12+
admin.site.register(GITHUB_Issue)
13+
admin.site.register(GITHUB_Clone)
14+
admin.site.register(GITHUB_Details_Cache)
15+
admin.site.register(GITHUB_PKey)

dojo/github/models.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from django.db import models
2+
from django.utils.translation import gettext as _
3+
4+
from dojo.models import Finding, Product
5+
6+
7+
class GITHUB_Conf(models.Model):
8+
configuration_name = models.CharField(max_length=2000, help_text=_("Enter a name to give to this configuration"), default="")
9+
api_key = models.CharField(max_length=2000, help_text=_("Enter your Github API Key"), default="")
10+
11+
def __str__(self):
12+
return self.configuration_name
13+
14+
15+
class GITHUB_Issue(models.Model):
16+
issue_id = models.CharField(max_length=200)
17+
issue_url = models.URLField(max_length=2000, verbose_name=_("GitHub issue URL"))
18+
finding = models.OneToOneField(Finding, null=True, blank=True, on_delete=models.CASCADE)
19+
20+
def __str__(self):
21+
return str(self.issue_id) + "| GitHub Issue URL: " + str(self.issue_url)
22+
23+
24+
class GITHUB_Clone(models.Model):
25+
github_id = models.CharField(max_length=200)
26+
github_clone_id = models.CharField(max_length=200)
27+
28+
29+
class GITHUB_Details_Cache(models.Model):
30+
github_id = models.CharField(max_length=200)
31+
github_key = models.CharField(max_length=200)
32+
github_status = models.CharField(max_length=200)
33+
github_resolution = models.CharField(max_length=200)
34+
35+
36+
class GITHUB_PKey(models.Model):
37+
product = models.ForeignKey(Product, on_delete=models.CASCADE)
38+
39+
git_project = models.CharField(max_length=200, blank=True, verbose_name=_("Github project"), help_text=_("Specify your project location. (:user/:repo)"))
40+
git_conf = models.ForeignKey(GITHUB_Conf, verbose_name=_("Github Configuration"),
41+
null=True, blank=True, on_delete=models.CASCADE)
42+
git_push_notes = models.BooleanField(default=False, blank=True, help_text=_("Notes added to findings will be automatically added to the corresponding github issue"))
43+
44+
def __str__(self):
45+
return self.product.name + " | " + self.git_project

dojo/github.py renamed to dojo/github/services.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
1-
# python
21
import logging
32
import sys
43

54
from django.template.loader import render_to_string
6-
7-
# External libs
85
from github import Auth, Github
96

10-
# Dojo related imports
11-
from dojo.models import Engagement, GITHUB_Issue, GITHUB_PKey, Product
7+
from dojo.github.models import GITHUB_Issue, GITHUB_PKey
8+
from dojo.models import Engagement, Product
129

13-
# Create global
1410
logger = logging.getLogger(__name__)
1511

1612

13+
def validate_github_credentials(api_key):
14+
"""Verify a GitHub API key by fetching the authenticated user. Raises on failure."""
15+
g = Github(api_key)
16+
user = g.get_user()
17+
logger.debug("Using user " + user.login)
18+
return user.login
19+
20+
1721
def reopen_external_issue_github(find, note, prod, eng):
1822
# Ensure the system setting for GitHub integration is enabled
1923
from dojo.utils import get_system_setting # noqa: PLC0415 circular import
File renamed without changes.
File renamed without changes.

dojo/github/ui/forms.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from django import forms
2+
3+
from dojo.github.models import GITHUB_Conf, GITHUB_Issue, GITHUB_PKey
4+
5+
6+
class GITHUB_IssueForm(forms.ModelForm):
7+
8+
class Meta:
9+
model = GITHUB_Issue
10+
exclude = ["product"]
11+
12+
13+
class GITHUBForm(forms.ModelForm):
14+
api_key = forms.CharField(widget=forms.PasswordInput, required=True)
15+
16+
class Meta:
17+
model = GITHUB_Conf
18+
exclude = ["product"]
19+
20+
21+
class DeleteGITHUBConfForm(forms.ModelForm):
22+
id = forms.IntegerField(required=True,
23+
widget=forms.widgets.HiddenInput())
24+
25+
class Meta:
26+
model = GITHUB_Conf
27+
fields = ["id"]
28+
29+
30+
class ExpressGITHUBForm(forms.ModelForm):
31+
password = forms.CharField(widget=forms.PasswordInput, required=True)
32+
issue_key = forms.CharField(required=True, help_text="A valid issue ID is required to gather the necessary information.")
33+
34+
class Meta:
35+
model = GITHUB_Conf
36+
exclude = ["product", "epic_name_id", "open_status_key",
37+
"close_status_key", "info_mapping_severity",
38+
"low_mapping_severity", "medium_mapping_severity",
39+
"high_mapping_severity", "critical_mapping_severity", "finding_text"]
40+
41+
42+
class GITHUB_Product_Form(forms.ModelForm):
43+
git_conf = forms.ModelChoiceField(queryset=GITHUB_Conf.objects.all(), label="GITHUB Configuration", required=False)
44+
45+
class Meta:
46+
model = GITHUB_PKey
47+
exclude = ["product"]
48+
49+
50+
class GITHUBFindingForm(forms.Form):
51+
def __init__(self, *args, **kwargs):
52+
self.enabled = kwargs.pop("enabled")
53+
super().__init__(*args, **kwargs)
54+
self.fields["push_to_github"] = forms.BooleanField()
55+
self.fields["push_to_github"].required = False
56+
self.fields["push_to_github"].help_text = "Checking this will overwrite content of your Github issue, or create one."
57+
58+
push_to_github = forms.BooleanField(required=False)

0 commit comments

Comments
 (0)