# 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.lib.utils import generate_api_key - pattern-not: from zerver.models import filter_pattern_validator - pattern-not: from zerver.models import url_template_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 - zerver/migrations/0387_reupload_realmemoji_again.py - pgroonga/migrations/0002_html_escape_subject.py - id: html-format languages: [python] pattern-either: - pattern: markupsafe.Markup(... .format(...)) - pattern: markupsafe.Markup(f"...") - pattern: markupsafe.Markup(... + ...) severity: ERROR message: "Do not write an HTML injection vulnerability please" - id: sql-format languages: [python] pattern-either: - pattern: ... .execute("...".format(...)) - pattern: ... .execute(f"...") - pattern: ... .execute(... + ...) - pattern: psycopg2.sql.SQL(... .format(...)) - pattern: psycopg2.sql.SQL(f"...") - pattern: psycopg2.sql.SQL(... + ...) - pattern: django.db.migrations.RunSQL(..., "..." .format(...), ...) - pattern: django.db.migrations.RunSQL(..., f"...", ...) - pattern: django.db.migrations.RunSQL(..., ... + ..., ...) - pattern: django.db.migrations.RunSQL(..., [..., "..." .format(...), ...], ...) - pattern: django.db.migrations.RunSQL(..., [..., f"...", ...], ...) - pattern: django.db.migrations.RunSQL(..., [..., ... + ..., ...], ...) severity: ERROR message: "Do not write a SQL injection vulnerability please" - 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: translated-positional-field languages: [python] patterns: - pattern-either: - pattern: django.utils.translation.gettext("$MESSAGE") - pattern: django.utils.translation.pgettext($CONTEXT, "$MESSAGE") - pattern: django.utils.translation.gettext_lazy("$MESSAGE") - pattern: django.utils.translation.pgettext_lazy($CONTEXT, "$MESSAGE") - metavariable-regex: metavariable: $MESSAGE regex: (^|.*[^{])(\{\{)*\{[:!}].* severity: ERROR message: "Prefer {named} fields over positional {} in translated strings" - id: mutable-default-type languages: [python] pattern-either: - 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[...] = zerver.lib.request.REQ(..., default={}, ...), ...) -> ...: ... - pattern: | def $F(..., $A: typing.Optional[typing.Dict[...]] = zerver.lib.request.REQ(..., default={}, ...), ...) -> ...: ... 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.pgettext(...) % ... - pattern: django.utils.translation.gettext_lazy(...) % ... - pattern: django.utils.translation.pgettext_lazy(...) % ... severity: ERROR message: "Prefer f-strings or .format for string formatting" - 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 paths: exclude: - zerver/migrations/0373_fix_deleteduser_dummies.py - 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 - id: dont-make-batched-migration-atomic patterns: - pattern: | class Migration(migrations.Migration): ... - pattern-inside: | ... BATCH_SIZE = ... ... - pattern-not: | class Migration(migrations.Migration): atomic = False paths: include: - "**/migrations" message: 'A batched migration should not be atomic. Add "atomic = False" to the Migration class' languages: [python] severity: ERROR