audit log: Create audit log when a realm is created.

This is mainly useful in recording the user who created the realm,
when possible.
This commit is contained in:
Vishnu KS 2021-04-20 15:59:19 +05:30 committed by Tim Abbott
parent 0023f7f9a0
commit 7f3fc3423b
8 changed files with 112 additions and 4 deletions

View File

@ -652,6 +652,18 @@ def do_create_user(
} }
).decode(), ).decode(),
) )
if realm_creation:
# If this user just created a realm, make sure they are
# properly tagged as the creator of the realm.
realm_creation_audit_log = (
RealmAuditLog.objects.filter(event_type=RealmAuditLog.REALM_CREATED, realm=realm)
.order_by("id")
.last()
)
realm_creation_audit_log.acting_user = user_profile
realm_creation_audit_log.save(update_fields=["acting_user"])
do_increment_logging_stat( do_increment_logging_stat(
user_profile.realm, user_profile.realm,
COUNT_STATS["active_users_log:is_bot:day"], COUNT_STATS["active_users_log:is_bot:day"],
@ -4531,8 +4543,14 @@ def do_create_realm(
# suites that want to backdate the date of a realm's creation. # suites that want to backdate the date of a realm's creation.
assert not settings.PRODUCTION assert not settings.PRODUCTION
kwargs["date_created"] = date_created kwargs["date_created"] = date_created
realm = Realm(string_id=string_id, name=name, **kwargs)
realm.save() with transaction.atomic():
realm = Realm(string_id=string_id, name=name, **kwargs)
realm.save()
RealmAuditLog.objects.create(
realm=realm, event_type=RealmAuditLog.REALM_CREATED, event_time=realm.date_created
)
# Create stream once Realm object has been saved # Create stream once Realm object has been saved
notifications_stream = ensure_stream( notifications_stream = ensure_stream(

View File

@ -1045,6 +1045,22 @@ def do_import_realm(import_dir: Path, subdomain: str, processes: int = 1) -> Rea
) )
logging.info("done with create_subscription_events") logging.info("done with create_subscription_events")
# Ensure the invariant that there's always a realm-creation audit
# log event, even if the export was generated by an export tool
# that does not create RealmAuditLog events.
if not RealmAuditLog.objects.filter(
realm=realm, event_type=RealmAuditLog.REALM_CREATED
).exists():
RealmAuditLog.objects.create(
realm=realm,
event_type=RealmAuditLog.REALM_CREATED,
event_time=realm.date_created,
# Mark these as backfilled, since they weren't created
# when the realm was actaully created, and thus do not
# have the creating user associated with them.
backfilled=True,
)
if "zerver_huddle" in data: if "zerver_huddle" in data:
process_huddle_hash(data, "zerver_huddle") process_huddle_hash(data, "zerver_huddle")
bulk_import_model(data, Huddle) bulk_import_model(data, Huddle)

View File

@ -3,7 +3,7 @@ from typing import Iterable, Optional, Tuple
from django.conf import settings from django.conf import settings
from zerver.lib.bulk_create import bulk_create_users from zerver.lib.bulk_create import bulk_create_users
from zerver.models import Realm, UserProfile, get_client, get_system_bot from zerver.models import Realm, RealmAuditLog, UserProfile, get_client, get_system_bot
def server_initialized() -> bool: def server_initialized() -> bool:
@ -14,6 +14,9 @@ def create_internal_realm() -> None:
from zerver.lib.actions import do_change_can_forge_sender from zerver.lib.actions import do_change_can_forge_sender
realm = Realm.objects.create(string_id=settings.SYSTEM_BOT_REALM) realm = Realm.objects.create(string_id=settings.SYSTEM_BOT_REALM)
RealmAuditLog.objects.create(
realm=realm, event_type=RealmAuditLog.REALM_CREATED, event_time=realm.date_created
)
# Create some client objects for common requests. Not required; # Create some client objects for common requests. Not required;
# just ensures these get low IDs in production, and in development # just ensures these get low IDs in production, and in development

View File

@ -0,0 +1,44 @@
# Generated by Django 3.1.8 on 2021-04-20 10:09
from django.db import migrations
from django.db.backends.postgresql.schema import DatabaseSchemaEditor
from django.db.migrations.state import StateApps
def backfill_realm_creation_log_events(
apps: StateApps, schema_editor: DatabaseSchemaEditor
) -> None:
RealmAuditLog = apps.get_model("zerver", "RealmAuditLog")
RealmAuditLog.REALM_CREATED = 215
Realm = apps.get_model("zerver", "Realm")
objects_to_create = []
for realm in Realm.objects.all():
entry = RealmAuditLog(
realm=realm,
event_type=RealmAuditLog.REALM_CREATED,
event_time=realm.date_created,
backfilled=True,
)
objects_to_create.append(entry)
RealmAuditLog.objects.bulk_create(objects_to_create)
def reverse_code(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
RealmAuditLog = apps.get_model("zerver", "RealmAuditLog")
RealmAuditLog.REALM_CREATED = 215
RealmAuditLog.objects.filter(event_type=RealmAuditLog.REALM_CREATED, backfilled=True).delete()
class Migration(migrations.Migration):
dependencies = [
("zerver", "0321_userprofile_enable_marketing_emails"),
]
operations = [
migrations.RunPython(
backfill_realm_creation_log_events, reverse_code=reverse_code, elidable=True
)
]

View File

@ -3329,6 +3329,7 @@ class AbstractRealmAuditLog(models.Model):
REALM_REACTIVATION_EMAIL_SENT = 212 REALM_REACTIVATION_EMAIL_SENT = 212
REALM_SPONSORSHIP_PENDING_STATUS_CHANGED = 213 REALM_SPONSORSHIP_PENDING_STATUS_CHANGED = 213
REALM_SUBDOMAIN_CHANGED = 214 REALM_SUBDOMAIN_CHANGED = 214
REALM_CREATED = 215
SUBSCRIPTION_CREATED = 301 SUBSCRIPTION_CREATED = 301
SUBSCRIPTION_ACTIVATED = 302 SUBSCRIPTION_ACTIVATED = 302

View File

@ -85,6 +85,7 @@ from zerver.models import (
Message, Message,
PreregistrationUser, PreregistrationUser,
Realm, Realm,
RealmAuditLog,
Recipient, Recipient,
ScheduledEmail, ScheduledEmail,
Stream, Stream,
@ -2760,6 +2761,12 @@ class RealmCreationTest(ZulipTestCase):
self.assertIn("signed up", messages[1].content) self.assertIn("signed up", messages[1].content)
self.assertEqual("zuliptest", messages[1].topic_name()) self.assertEqual("zuliptest", messages[1].topic_name())
realm_creation_audit_log = RealmAuditLog.objects.get(
realm=realm, event_type=RealmAuditLog.REALM_CREATED
)
self.assertEqual(realm_creation_audit_log.acting_user, user)
self.assertEqual(realm_creation_audit_log.event_time, realm.date_created)
# Piggyback a little check for how we handle # Piggyback a little check for how we handle
# empty string_ids. # empty string_ids.
realm.string_id = "" realm.string_id = ""

View File

@ -1069,7 +1069,11 @@ class SlackImporter(ZulipTestCase):
realmauditlog_event_type = {log.event_type for log in realmauditlog} realmauditlog_event_type = {log.event_type for log in realmauditlog}
self.assertEqual( self.assertEqual(
realmauditlog_event_type, realmauditlog_event_type,
{RealmAuditLog.SUBSCRIPTION_CREATED, RealmAuditLog.REALM_PLAN_TYPE_CHANGED}, {
RealmAuditLog.SUBSCRIPTION_CREATED,
RealmAuditLog.REALM_PLAN_TYPE_CHANGED,
RealmAuditLog.REALM_CREATED,
},
) )
Realm.objects.filter(name=test_realm_subdomain).delete() Realm.objects.filter(name=test_realm_subdomain).delete()

View File

@ -312,6 +312,11 @@ class Command(BaseCommand):
invite_required=False, invite_required=False,
org_type=Realm.CORPORATE, org_type=Realm.CORPORATE,
) )
RealmAuditLog.objects.create(
realm=zulip_realm,
event_type=RealmAuditLog.REALM_CREATED,
event_time=zulip_realm.date_created,
)
RealmDomain.objects.create(realm=zulip_realm, domain="zulip.com") RealmDomain.objects.create(realm=zulip_realm, domain="zulip.com")
if options["test_suite"]: if options["test_suite"]:
mit_realm = Realm.objects.create( mit_realm = Realm.objects.create(
@ -321,6 +326,11 @@ class Command(BaseCommand):
invite_required=False, invite_required=False,
org_type=Realm.CORPORATE, org_type=Realm.CORPORATE,
) )
RealmAuditLog.objects.create(
realm=mit_realm,
event_type=RealmAuditLog.REALM_CREATED,
event_time=mit_realm.date_created,
)
RealmDomain.objects.create(realm=mit_realm, domain="mit.edu") RealmDomain.objects.create(realm=mit_realm, domain="mit.edu")
lear_realm = Realm.objects.create( lear_realm = Realm.objects.create(
@ -330,6 +340,11 @@ class Command(BaseCommand):
invite_required=False, invite_required=False,
org_type=Realm.CORPORATE, org_type=Realm.CORPORATE,
) )
RealmAuditLog.objects.create(
realm=lear_realm,
event_type=RealmAuditLog.REALM_CREATED,
event_time=lear_realm.date_created,
)
# Default to allowing all members to send mentions in # Default to allowing all members to send mentions in
# large streams for the test suite to keep # large streams for the test suite to keep