Skip to content

Commit

Permalink
Add GitHub workflow to protect certain files from modifications (#8927)
Browse files Browse the repository at this point in the history
* Adds github action workflow to protect certain files from modifications

* Added empty line to the end of the git-protect script

* Added preliminary list of files to protect

* Cleared empty line of spaces
  • Loading branch information
dwalleck authored Nov 6, 2023
1 parent f1b8898 commit dd71f74
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 0 deletions.
103 changes: 103 additions & 0 deletions .github/scripts/git_protect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import argparse
import logging
import re
import subprocess
from pathlib import Path

log = logging.getLogger(__name__)


def gitignore_to_regex(pattern) -> str:
# Replace .gitignore-style patterns with regex equivalents
pattern = pattern.replace("*", ".*") # * -> .*
pattern = pattern.replace("?", ".") # ? -> .
pattern = pattern.replace("[!", "[^") # [!abc] -> [^abc]

# If the pattern ends with '/', it matches directories
if pattern.endswith("/"):
pattern = f"{pattern}.*"

return rf"^{pattern}"


def get_protected_files(file_name: str) -> list[str]:
# Check to see if the .gitprotect file exists
config_path = Path(file_name)
if not config_path.exists():
log.error(f"ERROR: Could not find .gitprotect at {config_path.absolute()}")
exit(1)

# Open the file and read in file paths
with open(file_name, "r") as file:
return [gitignore_to_regex(line.strip()) for line in file]


def get_changed_files(base_ref: str, head_ref: str) -> list[str]:
result = subprocess.run(
[
"git",
"diff",
"--name-only",
base_ref,
head_ref,
],
capture_output=True,
text=True,
)
return result.stdout.splitlines()


def check_changes_against_protect_list(
changed_files: list[str], protected_files: list[str], comment_only: bool
):
violations = set()

# If any modified file is one in the protect list, add the files to the violations list
for protected_file in protected_files:
pattern = re.compile(protected_file)
files_with_pattern = [f for f in changed_files if pattern.search(f)]
violations.update(files_with_pattern)

violations_list = "\n".join(violations)
if violations:
log.error(
f"The following files are protected and cannot be modified:\n{violations_list}"
)
if comment_only:
exit_code = 0
else:
exit_code = 1
exit(exit_code)
else:
log.debug("No changes to protected files were detected.")


def main(args):
changed_files = get_changed_files(
args.base_ref,
args.head_ref,
)
protected_files = get_protected_files(".gitprotect")
check_changes_against_protect_list(
protected_files=protected_files,
changed_files=changed_files,
comment_only=args.comment_only
)


if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="A utility function to check if protected files have been modified."
)
parser.add_argument(
"base_ref", help="The git SHA for the most recent merged commit."
)
parser.add_argument("head_ref", help="The git SHA for the incoming commit")
parser.add_argument(
"--comment-only",
action="store_true",
help="Sets git-protect to not exit with an error code",
)

args = parser.parse_args()
main(args)
45 changes: 45 additions & 0 deletions .github/workflows/check-protected-files.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Check For Modifications to Protected Files

on:
pull_request_target:

jobs:
check-if-protected-files-are-modified:
permissions: write-all
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'

- name: Check for file changes using git-protect
run: |
python .github/scripts/git_protect.py ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} --comment-only &> output.txt
- name: Post a comment back to the PR if protected files have changed
if: ${{ always() }}
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
fs.readFile('output.txt', 'utf8', (err, data) => {
if (err) {
console.error('Error reading the file:', err);
return;
}
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: data
})
});
91 changes: 91 additions & 0 deletions .gitprotect
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
docker-compose.yml
requirements.txt
wsgi.py
Dockerfile.nginx-debian
Dockerfile.nginx-alpine
Dockerfile.django-debian
Dockerfile.django-alpine

dojo/announcement/
dojo/api_v2/
dojo/authorization/
dojo/banner/
dojo/benchmark/
dojo/components/
dojo/cred/
dojo/db_migrations/
dojo/development_environment/
dojo/endpoint/
dojo/engagement/
dojo/finding/
dojo/finding_group/
dojo/github_issue_link/
dojo/group/
dojo/importers/
dojo/jira_link/
dojo/management/
dojo/metrics/
dojo/note_type/
dojo/notes/
dojo/notifications/
dojo/object/
dojo/product/
dojo/product_type/
dojo/regulations/
dojo/reports/
dojo/risk_acceptance/
dojo/rules/
dojo/scans/
dojo/search/
dojo/settings/
dojo/sla_config/
dojo/survey/
dojo/system_settings/
dojo/templates/
dojo/templatetags/
dojo/test/
dojo/test_type/
dojo/tool_config/
dojo/tool_product/
dojo/tool_type/
dojo/user/
dojo/apps.py
dojo/celery.py
dojo/checks.py
dojo/context_processors.py
dojo/decorators.py
dojo/filters.py
dojo/forms.py
dojo/github.py
dojo/middleware.py
dojo/models.py
dojo/okta.py
dojo/pipeline.py
dojo/remote_user.py
dojo/tasks.py
dojo/urls.py
dojo/utils.py
dojo/views.py
dojo/wsgi.py

helm/defectdojo/values.yaml
helm/defectdojo/templates/

docker/certs/
docker/environments/
docker/extra_fixtures/
docker/extra_settings/
docker/docker-compose-check.sh
docker/entrypoint-celery-beat.sh
docker/entrypoint-celery-worker.sh
docker/entrypoint-initializer.sh
docker/entrypoint-integration-tests.sh
docker/entrypoint-nginx.sh
docker/entrypoint-unit-tests-devDocker.sh
docker/entrypoint-unit-tests.sh
docker/entrypoint-uwsgi-dev.sh
docker/entrypoint-uwsgi.sh
docker/entrypoint.sh
docker/setEnv.sh
docker/unit-tests.sh
docker/wait-for-it.sh

0 comments on commit dd71f74

Please sign in to comment.