Skip to content

Commit a844ac5

Browse files
committed
Enable more ruff rules
Signed-off-by: Stephen Finucane <stephen@that.guru>
1 parent b666541 commit a844ac5

18 files changed

Lines changed: 66 additions & 46 deletions

File tree

‎patchwork/api/project.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ class ProjectMixin(object):
7070
def get_object(self):
7171
queryset = self.filter_queryset(self.get_queryset())
7272

73-
assert 'pk' in self.kwargs
73+
# Enforces a routing invariant, not guarding against user input.
74+
assert 'pk' in self.kwargs # noqa: S101
7475

7576
try:
7677
obj = queryset.get(id=int(self.kwargs['pk']))

‎patchwork/fields.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
class HashField(models.CharField):
1313
def __init__(self, *args, **kwargs):
14-
self.n_bytes = len(hashlib.sha1().hexdigest())
14+
self.n_bytes = len(hashlib.sha1(usedforsecurity=False).hexdigest())
1515
kwargs['max_length'] = self.n_bytes
1616

1717
super(HashField, self).__init__(*args, **kwargs)
@@ -20,7 +20,7 @@ def construct(self, value):
2020
# TODO: should this be unconditional?
2121
if isinstance(value, str):
2222
value = value.encode('utf-8')
23-
return hashlib.sha1(value)
23+
return hashlib.sha1(value, usedforsecurity=False)
2424

2525
def from_db_value(self, value, *args, **kwargs):
2626
return self.to_python(value)

‎patchwork/filters.py‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ def form(self):
278278
escape(state.name),
279279
)
280280
out += '</select>'
281-
return mark_safe(out)
281+
# All user-supplied values are run through escape() above.
282+
return mark_safe(out) # noqa: S308
282283

283284

284285
class SearchFilter(Filter):
@@ -315,7 +316,8 @@ def form(self):
315316
value = ''
316317
if self.search:
317318
value = escape(self.search)
318-
return mark_safe(
319+
# self.param is a hardcoded class attribute; value is escaped above.
320+
return mark_safe( # noqa: S308
319321
'<input name="%s" class="form-control" value="%s">'
320322
% (self.param, value)
321323
)
@@ -389,7 +391,9 @@ def form(self):
389391
'selected': selected,
390392
'value': self.param_map[b],
391393
}
392-
return mark_safe(s)
394+
# all values come from hardcoded class attributes (description_map,
395+
# param_map)
396+
return mark_safe(s) # noqa: S308
393397

394398

395399
class DelegateFilter(Filter):
@@ -463,7 +467,9 @@ def kwargs(self):
463467
@property
464468
def form(self):
465469
if self.forced:
466-
return mark_safe(
470+
# when forced, condition is a delegate username set
471+
# programmatically, not from user input
472+
return mark_safe( # noqa: S308
467473
'<input type="hidden" value="%s">%s'
468474
% (self.param, self.condition)
469475
)
@@ -499,7 +505,9 @@ def form(self):
499505
delegate.username,
500506
)
501507
out += '</select>'
502-
return mark_safe(out)
508+
# delegate.id is an integer; delegate.username is restricted to safe
509+
# characters by Django
510+
return mark_safe(out) # noqa: S308
503511

504512
def set_status(self, *args, **kwargs):
505513
if 'delegate' in kwargs:

‎patchwork/hasher.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def hash_diff(diff):
2323
diff = diff.strip() + '\n'
2424

2525
prefixes = ['-', '+', ' ']
26-
hashed = hashlib.sha1()
26+
hashed = hashlib.sha1(usedforsecurity=False)
2727

2828
for line in diff.split('\n'):
2929
if len(line) <= 0:

‎patchwork/models.py‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from collections import Counter
88
import datetime
9-
import random
9+
import secrets
1010
import re
1111

1212
from django.conf import settings
@@ -381,7 +381,8 @@ def patch_responses(self):
381381
def url_msgid(self):
382382
"""A trimmed Message ID, suitable for inclusion in URLs"""
383383
if settings.DEBUG:
384-
assert self.msgid[0] == '<' and self.msgid[-1] == '>'
384+
# Only reached in development; never runs in production.
385+
assert self.msgid[0] == '<' and self.msgid[-1] == '>' # noqa: S101
385386

386387
return self.msgid.strip('<>')
387388

@@ -1361,7 +1362,7 @@ def is_valid(self):
13611362
def save(self, *args, **kwargs):
13621363
limit = 1 << 32
13631364
if not self.key:
1364-
key = '%s%s%d' % (self.user, self.email, random.randint(0, limit))
1365+
key = '%s%s%d' % (self.user, self.email, secrets.randbelow(limit))
13651366
self.key = self._meta.get_field('key').construct(key).hexdigest()
13661367
super(EmailConfirmation, self).save()
13671368

‎patchwork/notifications.py‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,7 @@ def delete_notifications():
7373
'patchwork/mails/patch-change-notification.txt', context
7474
)
7575

76-
# Got one case where recipient.email == "<>". That causes Django to fail with:
77-
# File "/usr/lib/python3/dist-packages/django/core/mail/message.py", line 99, in sanitize_address
78-
# address_parts = nm + localpart + domain
79-
# ~~~^~~~~~~~~~~
80-
# TypeError: can only concatenate str (not "NoneType") to str
76+
# we can't concatenate empty emails
8177
if (
8278
not recipient.email
8379
or recipient.email == '<>'

‎patchwork/parser.py‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,7 +1069,7 @@ def find_series_from_url(url):
10691069
try:
10701070
result = resolve(parse_result.path)
10711071
except Resolver404:
1072-
logging.warning('Failed to resolve series or patch URL: %s', url)
1072+
logger.warning('Failed to resolve series or patch URL: %s', url)
10731073
return None
10741074

10751075
# TODO: Use the series detail view here.
@@ -1083,15 +1083,16 @@ def find_series_from_url(url):
10831083
try:
10841084
series_id_num = int(series_id[0])
10851085
except ValueError:
1086-
logging.warning(
1087-
'Series URL with an invalid series query parameter was given: %s',
1086+
logger.warning(
1087+
'Series URL with an invalid series query parameter was '
1088+
'given: %s',
10881089
url,
10891090
)
10901091
return None
10911092
# This will return None if there are no matches.
10921093
return Series.objects.filter(id=series_id_num).first()
10931094

1094-
logging.warning(
1095+
logger.warning(
10951096
'Series URL did not have a series query parameter: %s', url
10961097
)
10971098
return None

‎patchwork/settings/production.example.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,6 @@
6161
'BACKEND': 'django.core.files.storage.FileSystemStorage',
6262
},
6363
'staticfiles': {
64-
'BACKEND': 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage',
64+
'BACKEND': 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage', # noqa: E501
6565
},
6666
}

‎patchwork/templatetags/admins.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ def site_admins():
2222
return ''
2323

2424
if len(admins) == 1:
25-
return mark_safe(admins[0])
25+
# admins come from settings.ADMINS, a developer-controlled config value
26+
return mark_safe(admins[0]) # noqa: S308
2627

27-
return mark_safe(', '.join(admins[:-2]) + admins[-2] + ' or ' + admins[-1])
28+
# admins come from settings.ADMINS, a developer-controlled config value
29+
return mark_safe(', '.join(admins[:-2]) + admins[-2] + ' or ' + admins[-1]) # noqa: S308

‎patchwork/templatetags/patch.py‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ def patch_tags(patch):
2727
else:
2828
counts.append(str(count))
2929

30-
return mark_safe(
30+
# counts are integers; titles contain tag names set by project maintainers
31+
return mark_safe( # noqa: S308
3132
'<span title="%s">%s</span>' % (' / '.join(titles), ' '.join(counts))
3233
)
3334

@@ -53,7 +54,9 @@ def patch_checks(patch):
5354

5455
check_elements.reverse()
5556

56-
return mark_safe(
57+
# titles are hardcoded strings; check_elements contain hardcoded CSS class
58+
# names and integer counts
59+
return mark_safe( # noqa: S308
5760
'<span title="%s">%s</span>'
5861
% (' / '.join(titles), ''.join(check_elements))
5962
)
@@ -67,6 +70,7 @@ def patch_commit_display(patch):
6770
if not fmt:
6871
return escape(commit)
6972

70-
return mark_safe(
73+
# both the URL and display text are run through escape() above
74+
return mark_safe( # noqa: S308
7175
'<a href="%s">%s</a>' % (escape(fmt.format(commit)), escape(commit))
7276
)

0 commit comments

Comments
 (0)