|
10 | 10 |
|
11 | 11 | import bleach |
12 | 12 | import dateutil.relativedelta |
13 | | -import git |
14 | 13 | import markdown |
15 | 14 | from bleach.css_sanitizer import CSSSanitizer |
16 | 15 | from django import template |
@@ -98,8 +97,11 @@ def markdown_render(value): |
98 | 97 |
|
99 | 98 | @register.filter |
100 | 99 | def bleach_with_a_tags(message): |
101 | | - allowed_attributes = bleach.ALLOWED_ATTRIBUTES |
102 | | - allowed_attributes["a"] += ["style", "target"] |
| 100 | + # Create a copy of ALLOWED_ATTRIBUTES to avoid mutating the global |
| 101 | + allowed_attributes = { |
| 102 | + **bleach.ALLOWED_ATTRIBUTES, |
| 103 | + "a": [*bleach.ALLOWED_ATTRIBUTES.get("a", []), "style", "target"], |
| 104 | + } |
103 | 105 | return mark_safe(bleach.clean( |
104 | 106 | message, |
105 | 107 | attributes=allowed_attributes, |
@@ -143,11 +145,57 @@ def dojo_version(): |
143 | 145 |
|
144 | 146 | @register.simple_tag |
145 | 147 | def dojo_current_hash(): |
| 148 | + """ |
| 149 | + Display git commit hash in footer if .git directory exists. |
| 150 | +
|
| 151 | + This uses direct file reading (no GitPython, no subprocesses) for |
| 152 | + negligible performance cost (~0.1ms, 57x faster than GitPython). |
| 153 | + Production images exclude .git via .dockerignore, so they show "release mode". |
| 154 | + See: https://github.com/DefectDojo/django-DefectDojo/issues/13899 |
| 155 | + """ |
146 | 156 | try: |
147 | | - repo = git.Repo(search_parent_directories=True) |
148 | | - sha = repo.head.object.hexsha |
149 | | - return sha[:8] |
150 | | - except: |
| 157 | + # Find .git directory (walk up from current file) |
| 158 | + current_dir = Path(__file__).resolve().parent |
| 159 | + git_dir = None |
| 160 | + for parent in [current_dir, *current_dir.parents]: |
| 161 | + candidate = parent / ".git" |
| 162 | + if candidate.exists(): |
| 163 | + git_dir = candidate |
| 164 | + break |
| 165 | + |
| 166 | + if not git_dir: |
| 167 | + return "release mode" |
| 168 | + |
| 169 | + # Read .git/HEAD to get current commit |
| 170 | + head_file = git_dir / "HEAD" |
| 171 | + if not head_file.exists(): |
| 172 | + return "release mode" |
| 173 | + |
| 174 | + head_content = head_file.read_text().strip() |
| 175 | + |
| 176 | + if head_content.startswith("ref: "): |
| 177 | + # It's a branch reference like "ref: refs/heads/main" |
| 178 | + ref_path = head_content[5:] # Remove "ref: " prefix |
| 179 | + ref_file = git_dir / ref_path |
| 180 | + |
| 181 | + # Try reading from loose ref file first |
| 182 | + if ref_file.exists(): |
| 183 | + return ref_file.read_text().strip()[:8] |
| 184 | + |
| 185 | + # Fallback: check packed-refs (after git gc, refs are packed) |
| 186 | + packed_refs = git_dir / "packed-refs" |
| 187 | + if packed_refs.exists(): |
| 188 | + for line in packed_refs.read_text().splitlines(): |
| 189 | + if line.startswith("#") or not line.strip(): |
| 190 | + continue |
| 191 | + parts = line.split() |
| 192 | + if len(parts) >= 2 and parts[1] == ref_path: |
| 193 | + return parts[0][:8] |
| 194 | + |
| 195 | + return "release mode" |
| 196 | + # It's a direct SHA (detached HEAD) |
| 197 | + return head_content[:8] |
| 198 | + except Exception: |
151 | 199 | return "release mode" |
152 | 200 |
|
153 | 201 |
|
|
0 commit comments