zulip/tools/semgrep.yml

184 lines
6.7 KiB
YAML

# See https://semgrep.dev/docs/writing-rules/rule-syntax/ for documentation on YAML rule syntax
rules:
####################### PYTHON RULES #######################
- id: deprecated-render-usage
pattern: django.shortcuts.render_to_response(...)
message: "Use render() (from django.shortcuts) instead of render_to_response()"
languages: [python]
severity: ERROR
- id: dont-use-stream-objects-filter
pattern: Stream.objects.filter(...)
message: "Please use access_stream_by_*() to fetch Stream objects"
languages: [python]
severity: ERROR
paths:
include:
- zerver/views/
- id: dont-import-models-in-migrations
patterns:
- pattern-not: from zerver.lib.redis_utils import get_redis_client
- pattern-not: from zerver.models import filter_pattern_validator
- pattern-not: from zerver.models import filter_format_validator
- pattern-not: from zerver.models import generate_email_token_for_stream
- pattern-either:
- pattern: from zerver import $X
- pattern: from analytics import $X
- pattern: from confirmation import $X
message: "Don't import models or other code in migrations; see https://zulip.readthedocs.io/en/latest/subsystems/schema-migrations.html"
languages: [python]
severity: ERROR
paths:
include:
- "**/migrations"
exclude:
- zerver/migrations/0032_verify_all_medium_avatar_images.py
- zerver/migrations/0104_fix_unreads.py
- zerver/migrations/0206_stream_rendered_description.py
- zerver/migrations/0209_user_profile_no_empty_password.py
- zerver/migrations/0260_missed_message_addresses_from_redis_to_db.py
- pgroonga/migrations/0002_html_escape_subject.py
- id: logging-format
languages: [python]
patterns:
- pattern-either:
- pattern: $LOGGER.debug($FORMATTED)
- pattern: $LOGGER.info($FORMATTED)
- pattern: $LOGGER.warning($FORMATTED)
- pattern: $LOGGER.error($FORMATTED)
- pattern: $LOGGER.critical($FORMATTED)
- pattern: $LOGGER.exception($FORMATTED)
- metavariable-pattern:
metavariable: $LOGGER
patterns:
- pattern-either:
- pattern: logging
- pattern: logger
- metavariable-pattern:
metavariable: $FORMATTED
patterns:
- pattern-either:
- pattern: ... .format(...)
- pattern: f"..."
severity: ERROR
message: "Pass format arguments to logging (https://docs.python.org/3/howto/logging.html#optimization)"
- id: sql-format
languages: [python]
pattern-either:
- pattern: ... .execute("...".format(...))
- pattern: ... .execute(f"...")
- pattern: psycopg2.sql.SQL(... .format(...))
- pattern: psycopg2.sql.SQL(f"...")
- pattern: django.db.migrations.RunSQL(..., "..." .format(...), ...)
- pattern: django.db.migrations.RunSQL(..., f"...", ...)
- pattern: django.db.migrations.RunSQL(..., [..., "..." .format(...), ...], ...)
- pattern: django.db.migrations.RunSQL(..., [..., f"...", ...], ...)
severity: ERROR
message: "Do not write a SQL injection vulnerability please"
- id: translated-format
languages: [python]
pattern-either:
- pattern: django.utils.translation.gettext(... .format(...))
- pattern: django.utils.translation.gettext(f"...")
- pattern: django.utils.translation.gettext_lazy(... .format(...))
- pattern: django.utils.translation.gettext_lazy(f"...")
severity: ERROR
message: "Format strings after translation, not before"
- id: translated-format-lazy
languages: [python]
pattern: django.utils.translation.gettext_lazy(...).format(...)
severity: ERROR
message: "Immediately formatting a lazily translated string destroys its laziness"
- id: mutable-default-type
languages: [python]
pattern-either:
- pattern: |
def $F(..., $A: typing.List[...] = [...], ...) -> ...:
...
- pattern: |
def $F(..., $A: typing.Optional[typing.List[...]] = [...], ...) -> ...:
...
- pattern: |
def $F(..., $A: typing.List[...] = zerver.lib.request.REQ(..., default=[...], ...), ...) -> ...:
...
- pattern: |
def $F(..., $A: typing.Optional[typing.List[...]] = zerver.lib.request.REQ(..., default=[...], ...), ...) -> ...:
...
- pattern: |
def $F(..., $A: typing.Dict[...] = {}, ...) -> ...:
...
- pattern: |
def $F(..., $A: typing.Optional[typing.Dict[...]] = {}, ...) -> ...:
...
- pattern: |
def $F(..., $A: typing.Dict[...] = zerver.lib.request.REQ(..., default={}, ...), ...) -> ...:
...
- pattern: |
def $F(..., $A: typing.Optional[typing.Dict[...]] = zerver.lib.request.REQ(..., default={}, ...), ...) -> ...:
...
- pattern: |
def $F(..., $A: typing.Set[...] = set(), ...) -> ...:
...
- pattern: |
def $F(..., $A: typing.Optional[typing.Set[...]] = set(), ...) -> ...:
...
severity: ERROR
message: "Guard mutable default with read-only type (Sequence, Mapping, AbstractSet)"
- id: percent-formatting
languages: [python]
pattern-either:
- pattern: '"..." % ...'
- pattern: django.utils.translation.gettext(...) % ...
- pattern: django.utils.translation.gettext_lazy(...) % ...
severity: ERROR
message: "Prefer f-strings or .format for string formatting"
- id: eval
languages: [python]
pattern: eval
severity: ERROR
message: "Do not use eval under any circumstances; consider json.loads instead"
- id: typing-text
languages: [python]
pattern: typing.Text
severity: ERROR
message: "Use str instead of typing.Text"
- id: change-user-is-active
languages: [python]
patterns:
- pattern-either:
- pattern: |
$X.is_active = ...
- pattern: |
setattr($X, 'is_active', ...)
- pattern-not-inside: |
def change_user_is_active(...):
...
message: "Use change_user_is_active to mutate user_profile.is_active"
severity: ERROR
- id: confirmation-object-get
languages: [python]
patterns:
- pattern-either:
- pattern: Confirmation.objects.get(...)
- pattern: Confirmation.objects.filter(..., confirmation_key=..., ...)
- pattern-not-inside: |
def get_object_from_key(...):
...
paths:
exclude:
- zerver/tests/
message: "Do not fetch a Confirmation object directly, use get_object_from_key instead"
severity: ERROR