Skip to content

Commit 2673b5a

Browse files
authored
Merge branch 'bugfix' into wizcli-improvements
2 parents f8dcca7 + 05a74d5 commit 2673b5a

File tree

1,921 files changed

+637546
-90142
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,921 files changed

+637546
-90142
lines changed

.dryrunsecurity.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,21 +52,21 @@ sensitiveCodepaths:
5252
- 'docker/entrypoint-celery-beat.sh'
5353
- 'docker/entrypoint-celery-worker.sh'
5454
- 'docker/entrypoint-initializer.sh'
55+
- 'docker/entrypoint-first-boot.sh'
5556
- 'docker/entrypoint-nginx.sh'
5657
- 'docker/entrypoint-uwsgi.sh'
5758
- 'docker/wait-for-it.sh'
5859
allowedAuthors:
5960
usernames:
6061
- mtesauro
6162
- devGregA
62-
- grendel513
6363
- cneill
6464
- Maffooch
6565
- blakeaowens
6666
- kiblik
6767
- dsever
6868
- dogboat
6969
- hblankenship
70+
- valentijnscholten
7071
notificationList:
7172
- '@mtesauro'
72-
- '@grendel513'

.github/CODEOWNERS

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Any kind of package updates only need 2 approvals,
2+
# So let's add three folks here
3+
requirements.txt @cneill @mtesauro @Maffooch
4+
# Any dockerfile or compose changes will need to be viewed by
5+
# these people
6+
Dockerfile.* @mtesauro @Maffooch
7+
docker-compose.* @mtesauro @Maffooch
8+
/docker/ @mtesauro @Maffooch
9+
# Documentation changes
10+
/docs/content/ @paulOsinski @valentijnscholten @Maffooch
11+
# Kubernetes should be reviewed by reviewed first by those that know it
12+
/helm/ @cneill @kiblik @Maffooch
13+
# Anything UI related needs to be checked out by those with the eye for it
14+
/dojo/static/ @blakeaowens @Maffooch
15+
/dojo/templates/ @blakeaowens @Maffooch
16+
# Any model changes should be closely looked at
17+
/dojo/models.py @Maffooch
18+
# All other code changes should be reviewed by someone
19+
* @Maffooch @mtesauro

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,11 @@ A clear and concise description of what you expected to happen.
3333

3434
**Environment information**
3535
- Operating System: [e.g. Ubuntu 18.04]
36+
- Docker Compose or Helm version (Output of `docker compose version` or `helm version`)
3637
- DefectDojo version (see footer) or commit message: [use `git show -s --format="[%ci] %h: %s [%d]"`]
3738

3839
**Logs**
39-
Use `docker-compose logs` (or similar, depending on your deployment method) to get the logs and add the relevant sections here showing the error occurring (if applicable).
40+
Use `docker compose logs` (or similar, depending on your deployment method) to get the logs and add the relevant sections here showing the error occurring (if applicable).
4041

4142
**Sample scan files**
4243
If applicable, add sample scan files to help reproduce your problem.

.github/ISSUE_TEMPLATE/feature_request.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ assignees: ''
88
---
99
## :warning: Note on feature completeness :warning:
1010

11-
We are narrowing the scope of acceptable enhancements to DefectDojo in preparation for v3. Learn more here:
11+
We are narrowing the scope of acceptable enhancements to DefectDojo. Learn more here:
1212
https://github.com/DefectDojo/django-DefectDojo/blob/master/readme-docs/CONTRIBUTING.md
1313

1414
**Is your feature request related to a problem? Please describe**

.github/ISSUE_TEMPLATE/support_request.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ assignees: ''
77

88
---
99
**Slack us first!**
10-
The easiest and fastest way to help you is via Slack. There's a free and easy signup to join our #defectdojo channel in the OWASP Slack workspace: [Get Access.](https://owasp-slack.herokuapp.com/)
10+
The easiest and fastest way to help you is via Slack. There's a free and easy signup to join our #defectdojo channel in the OWASP Slack workspace: [Get Access.](https://owasp.org/slack/invite)
1111
If you're confident you've found a bug, or are allergic to Slack, you can submit an issue anyway.
1212

1313
**Be informative**
@@ -33,10 +33,11 @@ A clear and concise description of what you expected to happen.
3333

3434
**Environment information**
3535
- Operating System: [e.g. Ubuntu 18.04]
36+
- Docker Compose or Helm version (Output of `docker compose version` or `helm version`)
3637
- DefectDojo version (see footer) or commit message: [use `git show -s --format="[%ci] %h: %s [%d]"`]
3738

3839
**Logs**
39-
Use `docker-compose logs` (or similar, depending on your deployment method) to get the logs and add the relevant sections here showing the error occurring (if applicable).
40+
Use `docker compose logs` (or similar, depending on your deployment method) to get the logs and add the relevant sections here showing the error occurring (if applicable).
4041

4142
**Sample scan files**
4243
If applicable, add sample scan files to help reproduce your problem.

.github/labeler.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,8 @@ localization:
6060
- any-glob-to-any-file:
6161
- dojo/locale/*
6262
- dojo/locale/**/*
63+
64+
lint:
65+
- changed-files:
66+
- any-glob-to-any-file:
67+
- ruff.toml

.github/pr-reminder.py

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
import logging
2+
import os
3+
from datetime import datetime, timedelta
4+
5+
import requests
6+
7+
logger = logging.getLogger(__name__)
8+
9+
# Set up the GitHub and Slack tokens from environment variables
10+
GH_TOKEN = os.getenv("GH_TOKEN")
11+
SLACK_TOKEN = os.getenv("SLACK_TOKEN")
12+
REPO_OWNER = "DefectDojo"
13+
REPO_NAME = "django-DefectDojo"
14+
GITHUB_USER_NAME_TO_SLACK_EMAIL = {
15+
"Maffooch": "cody@defectdojo.com",
16+
"mtesauro": "matt@defectdojo.com",
17+
"devGregA": "greg@defectdojo.com",
18+
"blakeaowens": "blake@defectdojo.com",
19+
"dogboat": "sean@defectdojo.com",
20+
"cneill": "charles@defectdojo.com",
21+
"hblankenship": "harold@defectdojo.com",
22+
"valentijnscholten": "valentijn@defectdojo.com",
23+
}
24+
25+
26+
# Helper function to calculate the prior Thursday from a given date
27+
def get_prior_thursday(date: datetime) -> str:
28+
# Calculate the day of the week (0=Monday, 1=Tuesday, ..., 6=Sunday)
29+
weekday = date.weekday()
30+
# If today is Thursday (weekday 3), return the same day.
31+
if weekday == 3:
32+
return date
33+
# Calculate how many days to subtract to reach the most recent Thursday
34+
days_to_subtract = (
35+
weekday - 3
36+
) % 7 # (weekday - 3) gives the number of days past Thursday
37+
prior_thursday = date - timedelta(days=days_to_subtract)
38+
39+
return prior_thursday.strftime("%Y-%m-%d")
40+
41+
42+
# Helper function to get Slack User ID from Slack Email
43+
def get_slack_user_id(slack_email: str) -> int:
44+
headers = {"Authorization": f"Bearer {SLACK_TOKEN}"}
45+
params = {"email": slack_email}
46+
response = requests.get(
47+
"https://slack.com/api/users.lookupByEmail",
48+
headers=headers,
49+
params=params,
50+
timeout=30,
51+
)
52+
53+
if response.status_code != 200 or not response.json().get("ok"):
54+
logger.info(f"Error fetching Slack user ID for email {slack_email}: {response.text}")
55+
return None
56+
57+
return response.json().get("user", {}).get("id")
58+
59+
60+
# Helper function to fetch pull requests from GitHub
61+
def get_pull_requests() -> dict:
62+
headers = {"Authorization": f"token {GH_TOKEN}"}
63+
response = requests.get(
64+
f"https://api.github.com/repos/{REPO_OWNER}/{REPO_NAME}/pulls",
65+
headers=headers,
66+
timeout=30,
67+
)
68+
69+
if response.status_code != 200:
70+
logger.info(f"Error fetching PRs: {response.text}")
71+
response.raise_for_status()
72+
73+
return response.json()
74+
75+
76+
# Helper function to get PR reviews (approved, changes requested, or pending)
77+
def get_pr_reviews(pull_request: dict) -> list[dict]:
78+
pr_number = pull_request["number"]
79+
reviews_url = f"https://api.github.com/repos/{REPO_OWNER}/{REPO_NAME}/pulls/{pr_number}/reviews"
80+
headers = {"Authorization": f"token {GH_TOKEN}"}
81+
response = requests.get(
82+
reviews_url,
83+
headers=headers,
84+
timeout=30,
85+
)
86+
87+
if response.status_code != 200:
88+
logger.info(f"Error fetching reviews for PR {pr_number}: {response.text}")
89+
return []
90+
91+
reviews = response.json()
92+
# Dictionary to store the latest review for each user
93+
latest_reviews = {}
94+
# Iterate over each review to find the latest one for each user
95+
for review in reviews:
96+
user = review["user"]["login"]
97+
submitted_at = review["submitted_at"]
98+
state = review["state"]
99+
# Convert the submitted_at timestamp to a datetime object for comparison
100+
review_time = datetime.strptime(submitted_at, "%Y-%m-%dT%H:%M:%SZ")
101+
# If the user doesn't have a review or the current one is later, update
102+
if user not in latest_reviews or (
103+
review_time > latest_reviews[user]["submitted_at"] and state != "COMMENTED"
104+
):
105+
latest_reviews[user] = {
106+
"user": user,
107+
"state": state,
108+
"submitted_at": review_time,
109+
"url": review["html_url"],
110+
}
111+
# Determine if there are any pending reviewers
112+
latest_reviews.update(
113+
{
114+
user_dict.get("login"): {
115+
"user": user_dict.get("login"),
116+
"state": "PENDING",
117+
}
118+
for user_dict in pull_request.get("requested_reviewers", [])
119+
},
120+
)
121+
# Return the latest review state and URL for each user
122+
return latest_reviews.values()
123+
124+
125+
# Helper function to send a message via Slack
126+
def send_slack_message(slack_user_id: int, message: str) -> None:
127+
headers = {
128+
"Content-Type": "application/json",
129+
"Authorization": f"Bearer {SLACK_TOKEN}",
130+
}
131+
payload = {"channel": slack_user_id, "text": message}
132+
response = requests.post(
133+
"https://slack.com/api/chat.postMessage",
134+
json=payload,
135+
headers=headers,
136+
timeout=30,
137+
)
138+
139+
if response.status_code != 200 or not response.json().get("ok"):
140+
logger.info(f"Error sending Slack message: {response.text}")
141+
response.raise_for_status()
142+
143+
144+
# Helper function to format the PR message with review statuses
145+
def format_pr_message(pull_request: dict, reviews: list[dict]) -> str:
146+
repo_name = pull_request["head"]["repo"]["name"]
147+
pull_request_title = pull_request["title"]
148+
pull_request_url = pull_request["html_url"]
149+
pull_request_number = pull_request["number"]
150+
constructed_title = f"{repo_name} (#{pull_request_number}): {pull_request_title}"
151+
message = f"• <{pull_request_url}|{constructed_title}>"
152+
# Fetch the milestone due date and URL
153+
if (milestone := pull_request.get("milestone")) is not None and (
154+
(milestone_due_date := milestone.get("due_on"))
155+
and (milestone_url := milestone.get("html_url"))
156+
and (milestone_title := milestone.get("title"))
157+
):
158+
message += f"\n Merge by: {get_prior_thursday(datetime.strptime(milestone_due_date, '%Y-%m-%dT%H:%M:%SZ'))} for release <{milestone_url}|{milestone_title}>"
159+
# Format reviews and append to the message (only latest review status per user)
160+
message += "\n Review Status:\n"
161+
for review in reviews:
162+
user = review["user"]
163+
state = review["state"]
164+
if url := review.get("url"):
165+
message += f" • {user}: <{url}|{state.lower().capitalize()}>\n"
166+
else:
167+
message += f" • {user}: {state.lower().capitalize()}\n"
168+
169+
return message
170+
171+
172+
# Main function to process PRs and notify Slack users
173+
def notify_reviewers():
174+
try:
175+
user_pr_map = {}
176+
slack_email_to_slack_id = {}
177+
pull_requests = get_pull_requests()
178+
# Logging all fetched PR details
179+
logger.info(f"Fetched {len(pull_requests)} PRs from GitHub.")
180+
for pull_request in pull_requests:
181+
title = pull_request["title"]
182+
pr_number = pull_request["number"]
183+
logger.info(f"Processing PR: {pr_number} - {title}")
184+
reviews = get_pr_reviews(pull_request)
185+
logger.info(f"Found {len(reviews)} reviews for PR {pr_number}.")
186+
message = format_pr_message(pull_request, reviews)
187+
# Map Slack users to PR messages
188+
for review in reviews:
189+
github_username = review["user"]
190+
if github_username not in user_pr_map:
191+
user_pr_map[github_username] = ""
192+
# Determine if we should prune any non pending reviews
193+
if f"{github_username}: Pending" in message:
194+
user_pr_map[github_username] += message + "\n"
195+
# Add the Header at the beginning of the list
196+
header_message = "Here are the PRs that are still requiring review:"
197+
# Add Tips and Tricks at the end of the list
198+
tips_message = "*Tips and Tricks*\n"
199+
tips_message += (
200+
"• This is how to remove a PR from the list: Approve, Request changes, or leave a general comment.\n"
201+
"• If someone else has requested changes, then leave a general comment to remove the pending review from yourself."
202+
)
203+
# Send Slack messages to reviewers
204+
for github_username, pr_list in user_pr_map.items():
205+
if pr_list:
206+
if slack_email := GITHUB_USER_NAME_TO_SLACK_EMAIL.get(github_username):
207+
if slack_user_id := slack_email_to_slack_id.get(
208+
slack_email,
209+
get_slack_user_id(slack_email),
210+
):
211+
message_content = f"Hello {github_username}! {header_message}\n{pr_list}\n{tips_message}"
212+
# logger.info("\n\n", message_content, "\n\n")
213+
send_slack_message(slack_user_id, message_content)
214+
except Exception as e:
215+
logger.info(f"Error occurred: {e}")
216+
raise
217+
218+
219+
if __name__ == "__main__":
220+
notify_reviewers()

.github/release-drafter.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ categories:
4141
label: 'ui'
4242
- title: '🗣 Updates in localization'
4343
label: 'localization'
44+
- title: '🔧 Improved code quality with linters'
45+
label: 'lint'
4446
- title: '🧰 Maintenance'
4547
collapse-after: 3
4648
labels:
@@ -51,7 +53,7 @@ exclude-labels:
5153

5254
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
5355
template: |
54-
Please consult the [Upgrade notes in the documentation ](https://documentation.defectdojo.com/getting_started/upgrading/) for specific instructions for this release, and general upgrade instructions. Below is an automatically generated list of all PRs merged since the previous release.
56+
Please consult the [Upgrade notes in the documentation ](https://docs.defectdojo.com/en/open_source/upgrading/upgrading_guide/) for specific instructions for this release, and general upgrade instructions. Below is an automatically generated list of all PRs merged since the previous release.
5557
5658
## Changes since $PREVIOUS_TAG
5759
$CHANGES

.github/renovate.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"dependencyDashboardApproval": false,
77
"baseBranches": ["dev"],
88
"rebaseWhen": "conflicted",
9+
"separateMinorPatch": true,
910
"ignorePaths": ["requirements.txt", "requirements-lint.txt", "components/package.json", "components/package-lock.json", "dojo/components/yarn.lock", "dojo/components/package.json", "Dockerfile**"],
1011
"ignoreDeps": [],
1112
"packageRules": [{

0 commit comments

Comments
 (0)