From 9ac3dc9e2c70004df31fb47e8ace392f4f7ff486 Mon Sep 17 00:00:00 2001 From: Fabian Schindler Date: Mon, 1 Sep 2025 17:41:41 +0200 Subject: [PATCH 1/2] ref(auditlog): unified auditlog event definition into register.py with a decorator for custom render function --- src/sentry/audit_log/events.py | 367 -------- src/sentry/audit_log/manager.py | 66 +- src/sentry/audit_log/register.py | 1396 ++++++++++++++++-------------- 3 files changed, 812 insertions(+), 1017 deletions(-) delete mode 100644 src/sentry/audit_log/events.py diff --git a/src/sentry/audit_log/events.py b/src/sentry/audit_log/events.py deleted file mode 100644 index 0ac39f9be9867f..00000000000000 --- a/src/sentry/audit_log/events.py +++ /dev/null @@ -1,367 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -from sentry.audit_log.manager import AuditLogEvent -from sentry.utils.strings import truncatechars - -if TYPE_CHECKING: - from sentry.models.auditlogentry import AuditLogEntry - from sentry.users.models.user import User - - -# AuditLogEvents with custom render functions - - -def _get_member_display(email: str | None, target_user: User | None) -> str: - if email is not None: - return email - elif target_user is not None: - return target_user.get_display_name() - else: - return "(unknown member)" - - -class MemberAddAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=2, name="MEMBER_ADD", api_name="member.add") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - if audit_log_entry.target_user == audit_log_entry.actor: - return "joined the organization" - - member = _get_member_display(audit_log_entry.data.get("email"), audit_log_entry.target_user) - return f"add member {member}" - - -class MemberEditAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=4, name="MEMBER_EDIT", api_name="member.edit") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - member = _get_member_display(audit_log_entry.data.get("email"), audit_log_entry.target_user) - role = audit_log_entry.data.get("role") or "N/A" - - if "team_slugs" in audit_log_entry.data: - teams = ", ".join(str(x) for x in audit_log_entry.data.get("team_slugs", [])) - else: - teams = "N/A" - return f"edited member {member} (role: {role}, teams: {teams})" - - -class MemberRemoveAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=5, name="MEMBER_REMOVE", api_name="member.remove") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - if audit_log_entry.target_user == audit_log_entry.actor: - return "left the organization" - - member = _get_member_display(audit_log_entry.data.get("email"), audit_log_entry.target_user) - return f"removed member {member}" - - -class MemberJoinTeamAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=6, name="MEMBER_JOIN_TEAM", api_name="member.join-team") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - if audit_log_entry.target_user == audit_log_entry.actor: - return "joined team {team_slug}".format(**audit_log_entry.data) - - user_display_name = _get_member_display( - audit_log_entry.data.get("email"), audit_log_entry.target_user - ) - return "added {} to team {team_slug}".format(user_display_name, **audit_log_entry.data) - - -class MemberLeaveTeamAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=7, name="MEMBER_LEAVE_TEAM", api_name="member.leave-team") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - if audit_log_entry.target_user == audit_log_entry.actor: - return "left team {team_slug}".format(**audit_log_entry.data) - - user_display_name = _get_member_display( - audit_log_entry.data.get("email"), audit_log_entry.target_user - ) - return "removed {} from team {team_slug}".format(user_display_name, **audit_log_entry.data) - - -class MemberPendingAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=8, name="MEMBER_PENDING", api_name="member.pending") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - user_display_name = _get_member_display( - audit_log_entry.data.get("email"), audit_log_entry.target_user - ) - return f"required member {user_display_name} to setup 2FA" - - -class OrgAddAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=10, name="ORG_ADD", api_name="org.create") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - if channel := audit_log_entry.data.get("channel"): - return f"created the organization with {channel} integration" - return "created the organization" - - -class OrgEditAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=11, name="ORG_EDIT", api_name="org.edit") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - items_string = ", ".join(f"{k} {v}" for k, v in audit_log_entry.data.items()) - return "edited the organization setting: " + items_string - - -class TeamEditAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=21, name="TEAM_EDIT", api_name="team.edit") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - slug = audit_log_entry.data["slug"] - - return f"edited team {slug}" - - -class ProjectEditAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=31, name="PROJECT_EDIT", api_name="project.edit") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - if "old_slug" in audit_log_entry.data: - return "renamed project slug from {old_slug} to {new_slug}".format( - **audit_log_entry.data - ) - items_string = " ".join( - f"in {key} to {value}" for (key, value) in audit_log_entry.data.items() - ) - return "edited project settings " + items_string - - -class ProjectKeyEditAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=51, name="PROJECTKEY_EDIT", api_name="projectkey.edit") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - items_strings = [] - if "prev_rate_limit_count" in audit_log_entry.data: - items_strings.append( - " rate limit count from {prev_rate_limit_count} to {rate_limit_count}".format( - **audit_log_entry.data - ) - ) - if "prev_rate_limit_window" in audit_log_entry.data: - items_strings.append( - " rate limit window from {prev_rate_limit_window} to {rate_limit_window}".format( - **audit_log_entry.data - ) - ) - - item_string = "" - if items_strings: - item_string = ":" + ",".join(items_strings) - - return "edited project key {public_key}".format(**audit_log_entry.data) + item_string - - -class ProjectPerformanceDetectionSettingsAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__( - event_id=178, - name="PROJECT_PERFORMANCE_ISSUE_DETECTION_CHANGE", - api_name="project.change-performance-issue-detection", - ) - - def render(self, audit_log_entry: AuditLogEntry) -> str: - from sentry.issues.endpoints.project_performance_issue_settings import ( - project_settings_to_group_map as map, - ) - - data = audit_log_entry.data - items_string = ", ".join( - f"to {'enable' if value else 'disable'} detection of {map[key].description} issue" - for (key, value) in data.items() - if key in map.keys() - ) - return "edited project performance issue detector settings " + items_string - - -def render_project_action(audit_log_entry: AuditLogEntry, action: str): - # Most logs will just be name of the filter, but legacy browser changes can be bool, str, list, or sets - filter_name = audit_log_entry.data["state"] - slug = audit_log_entry.data.get("slug") - - message = f"{action} project filter {filter_name}" - - if filter_name in ("0", "1") or isinstance(filter_name, (bool, list, set)): - message = f"{action} project filter legacy-browsers" - if isinstance(filter_name, (list, set)): - message += ": {}".format(", ".join(sorted(filter_name))) - if slug: - message += f" for project {slug}" - return message - - -class ProjectEnableAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=37, name="PROJECT_ENABLE", api_name="project.enable") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - return render_project_action(audit_log_entry, "enable") - - -class ProjectDisableAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=38, name="PROJECT_DISABLE", api_name="project.disable") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - return render_project_action(audit_log_entry, "disable") - - -class ProjectOwnershipRuleEditAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__( - event_id=179, name="PROJECT_OWNERSHIPRULE_EDIT", api_name="project.ownership-rule.edit" - ) - - def render(self, audit_log_entry: AuditLogEntry) -> str: - return "modified ownership rules" - - -class SSOEditAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=62, name="SSO_EDIT", api_name="sso.edit") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - settings = ", ".join(f"{k} {v}" for k, v in audit_log_entry.data.items()) - return "edited sso settings: " + settings - - -class ServiceHookAddAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=100, name="SERVICEHOOK_ADD", api_name="servicehook.create") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - full_url = audit_log_entry.data.get("url") - return f'added a service hook for "{truncatechars(full_url, 64)}"' - - -class ServiceHookEditAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=101, name="SERVICEHOOK_EDIT", api_name="servicehook.edit") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - full_url = audit_log_entry.data.get("url") - return f'edited the service hook for "{truncatechars(full_url, 64)}"' - - -class ServiceHookRemoveAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=102, name="SERVICEHOOK_REMOVE", api_name="servicehook.remove") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - full_url = audit_log_entry.data.get("url") - return f'removed the service hook for "{truncatechars(full_url, 64)}"' - - -class IntegrationDisabledAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=108, name="INTEGRATION_DISABLED", api_name="integration.disable") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - provider = audit_log_entry.data.get("provider") or "" - return f"disabled {provider} integration".format(**audit_log_entry.data) - - -class IntegrationUpgradeAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=109, name="INTEGRATION_UPGRADE", api_name="integration.upgrade") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - if audit_log_entry.data.get("provider"): - return "upgraded {name} for the {provider} integration".format(**audit_log_entry.data) - return "updated an integration" - - -class IntegrationAddAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=110, name="INTEGRATION_ADD", api_name="integration.add") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - if audit_log_entry.data.get("provider"): - return "installed {name} for the {provider} integration".format(**audit_log_entry.data) - return "enabled integration {integration} for project {project}".format( - **audit_log_entry.data - ) - - -class IntegrationEditAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=111, name="INTEGRATION_EDIT", api_name="integration.edit") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - if audit_log_entry.data.get("provider"): - return "edited the {name} for the {provider} integration".format(**audit_log_entry.data) - return "edited integration {integration} for project {project}".format( - **audit_log_entry.data - ) - - -class IntegrationRemoveAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__(event_id=112, name="INTEGRATION_REMOVE", api_name="integration.remove") - - def render(self, audit_log_entry: AuditLogEntry) -> str: - if audit_log_entry.data.get("provider"): - return "uninstalled {name} for the {provider} integration".format( - **audit_log_entry.data - ) - return "disabled integration {integration} from project {project}".format( - **audit_log_entry.data - ) - - -class InternalIntegrationAddAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__( - event_id=130, name="INTERNAL_INTEGRATION_ADD", api_name="internal-integration.create" - ) - - def render(self, audit_log_entry: AuditLogEntry) -> str: - integration_name = audit_log_entry.data.get("name") or "" - return f"created internal integration {integration_name}" - - -class InternalIntegrationDisabledAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__( - event_id=131, - name="INTERNAL_INTEGRATION_DISABLED", - api_name="internal-integration.disable", - ) - - def render(self, audit_log_entry: AuditLogEntry) -> str: - integration_name = audit_log_entry.data.get("name") or "" - return f"disabled internal integration {integration_name}".format(**audit_log_entry.data) - - -class MonitorAddAuditLogEvent(AuditLogEvent): - def __init__(self) -> None: - super().__init__( - event_id=120, - name="MONITOR_ADD", - api_name="monitor.add", - ) - - def render(self, audit_log_entry: AuditLogEntry) -> str: - entry_data = audit_log_entry.data - name = entry_data.get("name") - upsert = entry_data.get("upsert") - - return f"added{" upsert " if upsert else " "}monitor {name}" diff --git a/src/sentry/audit_log/manager.py b/src/sentry/audit_log/manager.py index fa2e0fac0b99f1..f7b4e2c9146da8 100644 --- a/src/sentry/audit_log/manager.py +++ b/src/sentry/audit_log/manager.py @@ -1,7 +1,8 @@ from __future__ import annotations +from collections.abc import Callable from dataclasses import dataclass -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, overload if TYPE_CHECKING: from sentry.models.auditlogentry import AuditLogEntry @@ -65,7 +66,7 @@ class AuditLogEvent: # Simple template for rendering the audit log message using # the AuditLogEntry.data fields. For more complicated messages, # subclass AuditLogEvent and override the render method. - template: str | None = None + template: str | Callable[[AuditLogEntry], str] | None = None def __init__(self, event_id, name, api_name, template=None): self.event_id = event_id @@ -76,6 +77,8 @@ def __init__(self, event_id, name, api_name, template=None): def render(self, audit_log_entry: AuditLogEntry) -> str: if not self.template: return "" + elif callable(self.template): + return self.template(audit_log_entry) return self.template.format(**audit_log_entry.data) @@ -85,7 +88,29 @@ def __init__(self) -> None: self._event_id_lookup: dict[int, AuditLogEvent] = {} self._api_name_lookup: dict[str, AuditLogEvent] = {} - def add(self, audit_log_event: AuditLogEvent) -> None: + @overload + def add(self, event_id: AuditLogEvent) -> None: ... + + @overload + def add(self, event_id: int, name: str, api_name: str, template: str | None = None) -> None: ... + + def add( + self, + event_id: AuditLogEvent | int, + name: str | None = None, + api_name: str | None = None, + template: str | None = None, + ) -> None: + if isinstance(event_id, AuditLogEvent): + audit_log_event = event_id + else: + audit_log_event = AuditLogEvent( + event_id=event_id, + name=name, + api_name=api_name, + template=template, + ) + if ( audit_log_event.name in self._event_registry or audit_log_event.event_id in self._event_id_lookup @@ -99,6 +124,41 @@ def add(self, audit_log_event: AuditLogEvent) -> None: self._event_id_lookup[audit_log_event.event_id] = audit_log_event self._api_name_lookup[audit_log_event.api_name] = audit_log_event + @overload + def add_with_render_func( + self, event_id: AuditLogEvent + ) -> Callable[[Callable[[AuditLogEntry], str]], AuditLogEvent]: ... + + @overload + def add_with_render_func( + self, event_id: int, name: str, api_name: str, template: str | None = None + ) -> Callable[[Callable[[AuditLogEntry], str]], AuditLogEvent]: ... + + def add_with_render_func( + self, + event_id: AuditLogEvent | int, + name: str | None = None, + api_name: str | None = None, + template: str | None = None, + ) -> Callable[[Callable[[AuditLogEntry], str]], AuditLogEvent]: + """Decorator to add an audit log event with a custom render function""" + if isinstance(event_id, AuditLogEvent): + audit_log_event = event_id + else: + audit_log_event = AuditLogEvent( + event_id=event_id, + name=name, + api_name=api_name, + template=template, + ) + self.add(audit_log_event) + + def decorator(render_func: Callable[[AuditLogEntry], str]) -> AuditLogEvent: + audit_log_event.template = render_func + return audit_log_event + + return decorator + def get(self, event_id: int) -> AuditLogEvent: if event_id not in self._event_id_lookup: raise AuditLogEventNotRegistered(f"Event ID {event_id} does not exist") diff --git a/src/sentry/audit_log/register.py b/src/sentry/audit_log/register.py index f31ff5cb037715..b3a37e4f5d664e 100644 --- a/src/sentry/audit_log/register.py +++ b/src/sentry/audit_log/register.py @@ -1,688 +1,790 @@ -from sentry.audit_log import events -from sentry.audit_log.manager import AuditLogEvent, AuditLogEventManager +from __future__ import annotations + +from typing import TYPE_CHECKING + +from sentry.audit_log.manager import AuditLogEventManager +from sentry.utils.strings import truncatechars + +if TYPE_CHECKING: + from sentry.models.auditlogentry import AuditLogEntry + from sentry.users.models.user import User + + +def _get_member_display(email: str | None, target_user: User | None) -> str: + if email is not None: + return email + elif target_user is not None: + return target_user.get_display_name() + else: + return "(unknown member)" + default_manager = AuditLogEventManager() +add = default_manager.add +add_with_render_func = default_manager.add_with_render_func + # Register the AuditLogEvent objects to the `default_manager` -default_manager.add( - AuditLogEvent( - event_id=1, - name="MEMBER_INVITE", - api_name="member.invite", - template="invited member {email}", - ) -) -default_manager.add(events.MemberAddAuditLogEvent()) -default_manager.add( - AuditLogEvent( - event_id=3, - name="MEMBER_ACCEPT", - api_name="member.accept-invite", - template="accepted the membership invite", - ) -) -default_manager.add(events.MemberEditAuditLogEvent()) -default_manager.add(events.MemberRemoveAuditLogEvent()) -default_manager.add(events.MemberJoinTeamAuditLogEvent()) -default_manager.add(events.MemberLeaveTeamAuditLogEvent()) -default_manager.add(events.MemberPendingAuditLogEvent()) -default_manager.add(events.OrgAddAuditLogEvent()) -default_manager.add(events.OrgEditAuditLogEvent()) -default_manager.add( - AuditLogEvent( - event_id=12, - name="ORG_REMOVE", - api_name="org.remove", - template="removed the organization", - ) -) -default_manager.add( - AuditLogEvent( - event_id=13, - name="ORG_RESTORE", - api_name="org.restore", - template="restored the organization", - ) -) -default_manager.add( - AuditLogEvent( - event_id=20, - name="TEAM_ADD", - api_name="team.create", - template="created team {slug}", - ) -) -default_manager.add(events.TeamEditAuditLogEvent()) -default_manager.add( - AuditLogEvent( - event_id=22, - name="TEAM_REMOVE", - api_name="team.remove", - template="removed team {slug}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=30, - name="PROJECT_ADD", - api_name="project.create", - template="created project {slug}", - ) -) -default_manager.add(events.ProjectEditAuditLogEvent()) -default_manager.add(events.ProjectPerformanceDetectionSettingsAuditLogEvent()) -default_manager.add( - AuditLogEvent( - event_id=32, - name="PROJECT_REMOVE", - api_name="project.remove", - template="removed project {slug}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=33, - name="PROJECT_REMOVE_WITH_ORIGIN", - api_name="project.remove-with-origin", - template="removed project {slug} in {origin}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=35, - name="PROJECT_REQUEST_TRANSFER", - api_name="project.request-transfer", - template="requested to transfer project {slug}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=36, - name="PROJECT_ACCEPT_TRANSFER", - api_name="project.accept-transfer", - template="accepted transfer of project {project_slug} from {old_organization_slug} to {new_organization_slug}", - ) -) -default_manager.add(events.ProjectEnableAuditLogEvent()) -default_manager.add(events.ProjectDisableAuditLogEvent()) -default_manager.add( - AuditLogEvent( - event_id=40, - name="TAGKEY_REMOVE", - api_name="tagkey.remove", - template="removed tags matching {key} = *", - ) -) -default_manager.add( - AuditLogEvent( - event_id=50, - name="PROJECTKEY_ADD", - api_name="projectkey.create", - template="added project key {public_key}", - ) -) -default_manager.add(events.ProjectKeyEditAuditLogEvent()) -default_manager.add( - AuditLogEvent( - event_id=52, - name="PROJECTKEY_REMOVE", - api_name="projectkey.remove", - template="removed project key {public_key}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=53, - name="PROJECTKEY_CHANGE", - api_name="projectkey.change", - template="edited project key {public_key}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=60, - name="SSO_ENABLE", - api_name="sso.enable", - template="enabled sso ({provider})", - ) -) -default_manager.add( - AuditLogEvent( - event_id=61, - name="SSO_DISABLE", - api_name="sso.disable", - template="disabled sso ({provider})", - ) -) -default_manager.add(events.SSOEditAuditLogEvent()) -default_manager.add( - AuditLogEvent( - event_id=63, - name="SSO_IDENTITY_LINK", - api_name="sso-identity.link", - template="linked their account to a new identity", - ) -) -default_manager.add( - AuditLogEvent( - event_id=70, - name="APIKEY_ADD", - api_name="api-key.create", - template="added api key {label}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=71, - name="APIKEY_EDIT", - api_name="api-key.edit", - template="edited api key {label}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=72, - name="APIKEY_REMOVE", - api_name="api-key.remove", - template="removed api key {label}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=80, - name="RULE_ADD", - api_name="rule.create", - template='added rule "{label}"', - ) -) -default_manager.add( - AuditLogEvent( - event_id=81, - name="RULE_EDIT", - api_name="rule.edit", - template='edited rule "{label}"', - ) -) -default_manager.add( - AuditLogEvent( - event_id=82, - name="RULE_REMOVE", - api_name="rule.remove", - template='removed rule "{label}"', - ) -) -default_manager.add( - AuditLogEvent( - event_id=83, - name="RULE_SNOOZE", - api_name="rule.mute", - template='muted rule "{label}"', - ) -) -default_manager.add( - AuditLogEvent( - event_id=84, - name="RULE_DISABLE", - api_name="rule.disable", - template='disabled rule "{label}"', - ) -) -default_manager.add(events.ServiceHookAddAuditLogEvent()) -default_manager.add(events.ServiceHookEditAuditLogEvent()) -default_manager.add(events.ServiceHookRemoveAuditLogEvent()) -default_manager.add(events.IntegrationDisabledAuditLogEvent()) -default_manager.add(events.IntegrationUpgradeAuditLogEvent()) -default_manager.add(events.IntegrationAddAuditLogEvent()) -default_manager.add(events.IntegrationEditAuditLogEvent()) -default_manager.add(events.IntegrationRemoveAuditLogEvent()) -default_manager.add( - AuditLogEvent( - event_id=113, - name="SENTRY_APP_ADD", - api_name="sentry-app.add", - template="created sentry app {sentry_app}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=115, - name="SENTRY_APP_REMOVE", - api_name="sentry-app.remove", - template="removed sentry app {sentry_app}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=116, - name="SENTRY_APP_INSTALL", - api_name="sentry-app.install", - template="installed sentry app {sentry_app}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=117, - name="SENTRY_APP_UNINSTALL", - api_name="sentry-app.uninstall", - template="uninstalled sentry app {sentry_app}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=118, - name="INTEGRATION_ROTATE_CLIENT_SECRET", - api_name="integration.rotate-client-secret", - template="rotated a client secret for {status} integration {sentry_app}", - ) -) -default_manager.add(events.MonitorAddAuditLogEvent()) -default_manager.add( - AuditLogEvent( - event_id=121, - name="MONITOR_EDIT", - api_name="monitor.edit", - template="edited monitor {name}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=122, - name="MONITOR_REMOVE", - api_name="monitor.remove", - template="removed monitor {name}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=123, - name="MONITOR_ENVIRONMENT_REMOVE", - api_name="monitor.environment.remove", - template="removed an environment from monitor {name}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=124, - name="MONITOR_ENVIRONMENT_EDIT", - api_name="monitor.environment.edit", - template="edited an environment from monitor {name}", - ) -) -default_manager.add(events.InternalIntegrationAddAuditLogEvent()) -default_manager.add(events.InternalIntegrationDisabledAuditLogEvent()) -default_manager.add( - AuditLogEvent( - event_id=135, - name="INTERNAL_INTEGRATION_ADD_TOKEN", - api_name="internal-integration.add-token", - template="created a token for internal integration {sentry_app}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=136, - name="INTERNAL_INTEGRATION_REMOVE_TOKEN", - api_name="internal-integration.remove-token", - template="revoked a token for internal integration {sentry_app}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=140, - name="INVITE_REQUEST_ADD", - api_name="invite-request.create", - template="request added to invite {email}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=141, - name="INVITE_REQUEST_REMOVE", - api_name="invite-request.remove", - template="removed the invite request for {email}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=142, - name="INVITE_REMOVE", - api_name="invite.remove", - template="removed the invite for {email}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=160, - name="ALERT_RULE_ADD", - api_name="alertrule.create", - template='added metric alert rule "{label}"', - ) -) -default_manager.add( - AuditLogEvent( - event_id=161, - name="ALERT_RULE_EDIT", - api_name="alertrule.edit", - template='edited metric alert rule "{label}"', - ) -) -default_manager.add( - AuditLogEvent( - event_id=162, - name="ALERT_RULE_REMOVE", - api_name="alertrule.remove", - template='removed metric alert rule "{label}"', - ) -) -default_manager.add( - AuditLogEvent( - event_id=168, - name="ALERT_RULE_SNOOZE", - api_name="alertrule.mute", - template='muted metric alert rule "{label}"', - ) -) -default_manager.add( - AuditLogEvent( - event_id=163, - name="SAMPLING_BIAS_ENABLED", - api_name="sampling_priority.enabled", - template='enabled dynamic sampling priority "{name}"', - ) -) -default_manager.add( - AuditLogEvent( - event_id=164, - name="SAMPLING_BIAS_DISABLED", - api_name="sampling_priority.disabled", - template='disabled dynamic sampling priority "{name}"', - ) -) -default_manager.add( - AuditLogEvent( - event_id=165, - name="NOTIFICATION_ACTION_ADD", - api_name="notification_action.create", - template="added an action with the '{trigger}' trigger", - ) -) -default_manager.add( - AuditLogEvent( - event_id=166, - name="NOTIFICATION_ACTION_EDIT", - api_name="notification_action.edit", - template="edited an action with the '{trigger}' trigger", - ) -) -default_manager.add( - AuditLogEvent( - event_id=167, - name="NOTIFICATION_ACTION_REMOVE", - api_name="notification_action.remove", - template="removed an action with the '{trigger}' trigger", - ) -) -default_manager.add( - AuditLogEvent( - event_id=175, - name="TEAM_AND_PROJECT_CREATED", - api_name="team-and-project.created", - template="created team {team_slug} and added user as Team Admin while creating project {project_slug}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=176, - name="ORGAUTHTOKEN_ADD", - api_name="org-auth-token.create", - template="added org auth token {name}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=177, - name="ORGAUTHTOKEN_REMOVE", - api_name="org-auth-token.remove", - template="removed org auth token {name}", - ) -) -default_manager.add(events.ProjectOwnershipRuleEditAuditLogEvent()) -default_manager.add( - AuditLogEvent( - event_id=180, - name="PROJECT_TEAM_REMOVE", - api_name="project-team.remove", - template="removed team {team_slug} from project {project_slug}", - ) +add( + event_id=1, + name="MEMBER_INVITE", + api_name="member.invite", + template="invited member {email}", ) -default_manager.add( - AuditLogEvent( - event_id=181, - name="PROJECT_TEAM_ADD", - api_name="project-team.add", - template="added team {team_slug} to project {project_slug}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=182, - name="METRIC_BLOCK", - api_name="metric.block", - template="blocked metric {metric_mri} for project {project_slug}", - ) -) -default_manager.add( - AuditLogEvent( - event_id=183, - name="METRIC_TAGS_BLOCK", - api_name="metric.tags.block", - template="blocked {tags} tags of metric {metric_mri} for project {project_slug}", - ) + + +@add_with_render_func(event_id=2, name="MEMBER_ADD", api_name="member.add") +def render_member_add(audit_log_entry: AuditLogEntry) -> str: + if audit_log_entry.target_user == audit_log_entry.actor: + return "joined the organization" + + member = _get_member_display(audit_log_entry.data.get("email"), audit_log_entry.target_user) + return f"add member {member}" + + +add( + event_id=3, + name="MEMBER_ACCEPT", + api_name="member.accept-invite", + template="accepted the membership invite", ) -default_manager.add( - AuditLogEvent( - event_id=184, - name="METRIC_UNBLOCK", - api_name="metric.unblock", - template="unblocked metric {metric_mri} for project {project_slug}", + + +@add_with_render_func(event_id=4, name="MEMBER_EDIT", api_name="member.edit") +def render_member_edit(audit_log_entry: AuditLogEntry) -> str: + member = _get_member_display(audit_log_entry.data.get("email"), audit_log_entry.target_user) + role = audit_log_entry.data.get("role") or "N/A" + + if "team_slugs" in audit_log_entry.data: + teams = ", ".join(str(x) for x in audit_log_entry.data.get("team_slugs", [])) + else: + teams = "N/A" + return f"edited member {member} (role: {role}, teams: {teams})" + + +@add_with_render_func(event_id=5, name="MEMBER_REMOVE", api_name="member.remove") +def render_member_remove(audit_log_entry: AuditLogEntry) -> str: + if audit_log_entry.target_user == audit_log_entry.actor: + return "left the organization" + + member = _get_member_display(audit_log_entry.data.get("email"), audit_log_entry.target_user) + return f"removed member {member}" + + +@add_with_render_func(event_id=6, name="MEMBER_JOIN_TEAM", api_name="member.join-team") +def render_member_join_team(audit_log_entry: AuditLogEntry) -> str: + if audit_log_entry.target_user == audit_log_entry.actor: + return "joined team {team_slug}".format(**audit_log_entry.data) + + user_display_name = _get_member_display( + audit_log_entry.data.get("email"), audit_log_entry.target_user ) -) -default_manager.add( - AuditLogEvent( - event_id=185, - name="METRIC_TAGS_UNBLOCK", - api_name="metric.tags.unblock", - template="unblocked {tags} tags of metric {metric_mri} for project {project_slug}", + return "added {} to team {team_slug}".format(user_display_name, **audit_log_entry.data) + + +@add_with_render_func(event_id=7, name="MEMBER_LEAVE_TEAM", api_name="member.leave-team") +def render_member_leave_team(audit_log_entry: AuditLogEntry) -> str: + if audit_log_entry.target_user == audit_log_entry.actor: + return "left team {team_slug}".format(**audit_log_entry.data) + + user_display_name = _get_member_display( + audit_log_entry.data.get("email"), audit_log_entry.target_user ) -) -default_manager.add( - AuditLogEvent( - event_id=186, - name="ISSUE_DELETE", - api_name="issue.delete", - template="Deleted issue {issue_id} for project {project_slug}", + return "removed {} from team {team_slug}".format(user_display_name, **audit_log_entry.data) + + +@add_with_render_func(event_id=8, name="MEMBER_PENDING", api_name="member.pending") +def render_member_pending(audit_log_entry: AuditLogEntry) -> str: + user_display_name = _get_member_display( + audit_log_entry.data.get("email"), audit_log_entry.target_user ) + return f"required member {user_display_name} to setup 2FA" + + +@add_with_render_func(event_id=10, name="ORG_ADD", api_name="org.create") +def render_org_add(audit_log_entry: AuditLogEntry) -> str: + if channel := audit_log_entry.data.get("channel"): + return f"created the organization with {channel} integration" + return "created the organization" + + +@add_with_render_func(event_id=11, name="ORG_EDIT", api_name="org.edit") +def render_org_edit(audit_log_entry: AuditLogEntry) -> str: + items_string = ", ".join(f"{k} {v}" for k, v in audit_log_entry.data.items()) + return "edited the organization setting: " + items_string + + +add( + event_id=12, + name="ORG_REMOVE", + api_name="org.remove", + template="removed the organization", +) +add( + event_id=13, + name="ORG_RESTORE", + api_name="org.restore", + template="restored the organization", +) +add( + event_id=20, + name="TEAM_ADD", + api_name="team.create", + template="created team {slug}", +) +add( + event_id=21, + name="TEAM_EDIT", + api_name="team.edit", + template="edited team {slug}", +) +add( + event_id=22, + name="TEAM_REMOVE", + api_name="team.remove", + template="removed team {slug}", +) +add( + event_id=30, + name="PROJECT_ADD", + api_name="project.create", + template="created project {slug}", ) -default_manager.add( - AuditLogEvent( - event_id=187, - name="SPAN_BASED_METRIC_CREATE", - api_name="span_extraction_rule_config.create", - template="Created span-based metric for span attribute {span_attribute} for project {project_slug}", - ) + + +@add_with_render_func( + event_id=31, + name="PROJECT_EDIT", + api_name="project.edit", +) +def render_project_edit(audit_log_entry: AuditLogEntry) -> str: + if "old_slug" in audit_log_entry.data: + return "renamed project slug from {old_slug} to {new_slug}".format(**audit_log_entry.data) + items_string = " ".join(f"in {key} to {value}" for (key, value) in audit_log_entry.data.items()) + return "edited project settings " + items_string + + +add( + event_id=32, + name="PROJECT_REMOVE", + api_name="project.remove", + template="removed project {slug}", +) +add( + event_id=33, + name="PROJECT_REMOVE_WITH_ORIGIN", + api_name="project.remove-with-origin", + template="removed project {slug} in {origin}", +) +add( + event_id=35, + name="PROJECT_REQUEST_TRANSFER", + api_name="project.request-transfer", + template="requested to transfer project {slug}", +) +add( + event_id=36, + name="PROJECT_ACCEPT_TRANSFER", + api_name="project.accept-transfer", + template="accepted transfer of project {project_slug} from {old_organization_slug} to {new_organization_slug}", ) -default_manager.add( - AuditLogEvent( - event_id=188, - name="SPAN_BASED_METRIC_UPDATE", - api_name="span_extraction_rule_config.update", - template="Updated span-based metric for span attribute {span_attribute} for project {project_slug}", - ) + +def render_project_action(audit_log_entry: AuditLogEntry, action: str) -> str: + # Most logs will just be name of the filter, but legacy browser changes can be bool, str, list, or sets + filter_name = audit_log_entry.data["state"] + slug = audit_log_entry.data.get("slug") + + message = f"{action} project filter {filter_name}" + + if filter_name in ("0", "1") or isinstance(filter_name, (bool, list, set)): + message = f"{action} project filter legacy-browsers" + if isinstance(filter_name, (list, set)): + message += ": {}".format(", ".join(sorted(filter_name))) + if slug: + message += f" for project {slug}" + return message + + +@add_with_render_func(event_id=37, name="PROJECT_ENABLE", api_name="project.enable") +def render_project_enable(audit_log_entry: AuditLogEntry) -> str: + return render_project_action(audit_log_entry, "enable") + + +@add_with_render_func( + event_id=38, + name="PROJECT_DISABLE", + api_name="project.disable", ) +def render_project_disable(audit_log_entry: AuditLogEntry) -> str: + return render_project_action(audit_log_entry, "disable") -default_manager.add( - AuditLogEvent( - event_id=189, - name="SPAN_BASED_METRIC_DELETE", - api_name="span_extraction_rule_config.delete", - template="Deleted span-based metric for span attribute {span_attribute} for project {project_slug}", - ) + +add( + event_id=40, + name="TAGKEY_REMOVE", + api_name="tagkey.remove", + template="removed tags matching {key} = *", +) +add( + event_id=50, + name="PROJECTKEY_ADD", + api_name="projectkey.create", + template="added project key {public_key}", ) -default_manager.add( - AuditLogEvent( - event_id=190, - name="PROJECT_TEMPLATE_CREATED", - api_name="project_template.create", - template="Created project template {name} for organization {organization_id}", - ) + +@add_with_render_func(event_id=51, name="PROJECTKEY_EDIT", api_name="projectkey.edit") +def render_project_key_edit(audit_log_entry: AuditLogEntry) -> str: + items_strings = [] + if "prev_rate_limit_count" in audit_log_entry.data: + items_strings.append( + " rate limit count from {prev_rate_limit_count} to {rate_limit_count}".format( + **audit_log_entry.data + ) + ) + if "prev_rate_limit_window" in audit_log_entry.data: + items_strings.append( + " rate limit window from {prev_rate_limit_window} to {rate_limit_window}".format( + **audit_log_entry.data + ) + ) + + item_string = "" + if items_strings: + item_string = ":" + ",".join(items_strings) + + return "edited project key {public_key}".format(**audit_log_entry.data) + item_string + + +add( + event_id=52, + name="PROJECTKEY_REMOVE", + api_name="projectkey.remove", + template="removed project key {public_key}", +) +add( + event_id=53, + name="PROJECTKEY_CHANGE", + api_name="projectkey.change", + template="edited project key {public_key}", +) +add( + event_id=60, + name="SSO_ENABLE", + api_name="sso.enable", + template="enabled sso ({provider})", +) +add( + event_id=61, + name="SSO_DISABLE", + api_name="sso.disable", + template="disabled sso ({provider})", ) -default_manager.add( - AuditLogEvent( - event_id=200, - name="UPTIME_MONITOR_ADD", - api_name="uptime_monitor.add", - template="added uptime monitor {name}", - ) + +@add_with_render_func(event_id=62, name="SSO_EDIT", api_name="sso.edit") +def render_sso_edit(audit_log_entry: AuditLogEntry) -> str: + settings = ", ".join(f"{k} {v}" for k, v in audit_log_entry.data.items()) + return "edited sso settings: " + settings + + +add( + event_id=63, + name="SSO_IDENTITY_LINK", + api_name="sso-identity.link", + template="linked their account to a new identity", +) +add( + event_id=70, + name="APIKEY_ADD", + api_name="api-key.create", + template="added api key {label}", +) +add( + event_id=71, + name="APIKEY_EDIT", + api_name="api-key.edit", + template="edited api key {label}", +) +add( + event_id=72, + name="APIKEY_REMOVE", + api_name="api-key.remove", + template="removed api key {label}", +) +add( + event_id=80, + name="RULE_ADD", + api_name="rule.create", + template='added rule "{label}"', +) +add( + event_id=81, + name="RULE_EDIT", + api_name="rule.edit", + template='edited rule "{label}"', +) +add( + event_id=82, + name="RULE_REMOVE", + api_name="rule.remove", + template='removed rule "{label}"', +) +add( + event_id=83, + name="RULE_SNOOZE", + api_name="rule.mute", + template='muted rule "{label}"', +) +add( + event_id=84, + name="RULE_DISABLE", + api_name="rule.disable", + template='disabled rule "{label}"', ) -default_manager.add( - AuditLogEvent( - event_id=201, - name="UPTIME_MONITOR_EDIT", - api_name="uptime_monitor.edit", - template="edited uptime monitor {name}", + + +@add_with_render_func(event_id=100, name="SERVICEHOOK_ADD", api_name="servicehook.create") +def render_service_hook_add(audit_log_entry: AuditLogEntry) -> str: + full_url = audit_log_entry.data.get("url") + return f'added a service hook for "{truncatechars(full_url, 64)}"' + + +@add_with_render_func(event_id=101, name="SERVICEHOOK_EDIT", api_name="servicehook.edit") +def render_service_hook_edit(audit_log_entry: AuditLogEntry) -> str: + full_url = audit_log_entry.data.get("url") + return f'edited the service hook for "{truncatechars(full_url, 64)}"' + + +@add_with_render_func(event_id=102, name="SERVICEHOOK_REMOVE", api_name="servicehook.remove") +def render_service_hook_remove(audit_log_entry: AuditLogEntry) -> str: + full_url = audit_log_entry.data.get("url") + return f'removed the service hook for "{truncatechars(full_url, 64)}"' + + +@add_with_render_func(event_id=108, name="INTEGRATION_DISABLED", api_name="integration.disable") +def render_integration_disabled(audit_log_entry: AuditLogEntry) -> str: + provider = audit_log_entry.data.get("provider") or "" + return f"disabled {provider} integration".format(**audit_log_entry.data) + + +@add_with_render_func(event_id=109, name="INTEGRATION_UPGRADE", api_name="integration.upgrade") +def render_integration_upgrade(audit_log_entry: AuditLogEntry) -> str: + if audit_log_entry.data.get("provider"): + return "upgraded {name} for the {provider} integration".format(**audit_log_entry.data) + return "updated an integration" + + +@add_with_render_func(event_id=110, name="INTEGRATION_ADD", api_name="integration.add") +def render_integration_add(audit_log_entry: AuditLogEntry) -> str: + if audit_log_entry.data.get("provider"): + return "installed {name} for the {provider} integration".format(**audit_log_entry.data) + return "enabled integration {integration} for project {project}".format(**audit_log_entry.data) + + +@add_with_render_func(event_id=111, name="INTEGRATION_EDIT", api_name="integration.edit") +def render_integration_edit(audit_log_entry: AuditLogEntry) -> str: + if audit_log_entry.data.get("provider"): + return "edited the {name} for the {provider} integration".format(**audit_log_entry.data) + return "edited integration {integration} for project {project}".format(**audit_log_entry.data) + + +@add_with_render_func(event_id=112, name="INTEGRATION_REMOVE", api_name="integration.remove") +def render_integration_remove(audit_log_entry: AuditLogEntry) -> str: + if audit_log_entry.data.get("provider"): + return "uninstalled {name} for the {provider} integration".format(**audit_log_entry.data) + return "disabled integration {integration} from project {project}".format( + **audit_log_entry.data ) + + +add( + event_id=113, + name="SENTRY_APP_ADD", + api_name="sentry-app.add", + template="created sentry app {sentry_app}", +) +add( + event_id=115, + name="SENTRY_APP_REMOVE", + api_name="sentry-app.remove", + template="removed sentry app {sentry_app}", +) +add( + event_id=116, + name="SENTRY_APP_INSTALL", + api_name="sentry-app.install", + template="installed sentry app {sentry_app}", +) +add( + event_id=117, + name="SENTRY_APP_UNINSTALL", + api_name="sentry-app.uninstall", + template="uninstalled sentry app {sentry_app}", +) +add( + event_id=118, + name="INTEGRATION_ROTATE_CLIENT_SECRET", + api_name="integration.rotate-client-secret", + template="rotated a client secret for {status} integration {sentry_app}", ) -default_manager.add( - AuditLogEvent( - event_id=202, - name="UPTIME_MONITOR_REMOVE", - api_name="uptime_monitor.remove", - template="removed uptime monitor {name}", - ) + + +@add_with_render_func(event_id=120, name="MONITOR_ADD", api_name="monitor.add") +def render_monitor_add(audit_log_entry: AuditLogEntry) -> str: + entry_data = audit_log_entry.data + name = entry_data.get("name") + upsert = entry_data.get("upsert") + + return f"added{" upsert " if upsert else " "}monitor {name}" + + +add( + event_id=121, + name="MONITOR_EDIT", + api_name="monitor.edit", + template="edited monitor {name}", +) +add( + event_id=122, + name="MONITOR_REMOVE", + api_name="monitor.remove", + template="removed monitor {name}", +) +add( + event_id=123, + name="MONITOR_ENVIRONMENT_REMOVE", + api_name="monitor.environment.remove", + template="removed an environment from monitor {name}", +) +add( + event_id=124, + name="MONITOR_ENVIRONMENT_EDIT", + api_name="monitor.environment.edit", + template="edited an environment from monitor {name}", ) -default_manager.add( - AuditLogEvent( - event_id=210, - name="DETECTOR_ADD", - api_name="detector.add", - template="added detector {name}", - ) + + +@add_with_render_func( + event_id=130, name="INTERNAL_INTEGRATION_ADD", api_name="internal-integration.create" ) -default_manager.add( - AuditLogEvent( - event_id=211, - name="DETECTOR_EDIT", - api_name="detector.edit", - template="edited detector {name}", - ) +def render_internal_integration_add(audit_log_entry: AuditLogEntry) -> str: + integration_name = audit_log_entry.data.get("name") or "" + return f"created internal integration {integration_name}" + + +@add_with_render_func( + event_id=131, name="INTERNAL_INTEGRATION_DISABLED", api_name="internal-integration.disable" ) -default_manager.add( - AuditLogEvent( - event_id=212, - name="DETECTOR_REMOVE", - api_name="detector.remove", - template="removed detector {name}", - ) +def render_internal_integration_disabled(audit_log_entry: AuditLogEntry) -> str: + integration_name = audit_log_entry.data.get("name") or "" + return f"disabled internal integration {integration_name}".format(**audit_log_entry.data) + + +add( + event_id=135, + name="INTERNAL_INTEGRATION_ADD_TOKEN", + api_name="internal-integration.add-token", + template="created a token for internal integration {sentry_app}", +) +add( + event_id=136, + name="INTERNAL_INTEGRATION_REMOVE_TOKEN", + api_name="internal-integration.remove-token", + template="revoked a token for internal integration {sentry_app}", +) +add( + event_id=140, + name="INVITE_REQUEST_ADD", + api_name="invite-request.create", + template="request added to invite {email}", +) +add( + event_id=141, + name="INVITE_REQUEST_REMOVE", + api_name="invite-request.remove", + template="removed the invite request for {email}", +) +add( + event_id=160, + name="ALERT_RULE_ADD", + api_name="alertrule.create", + template='added metric alert rule "{label}"', +) +add( + event_id=161, + name="ALERT_RULE_EDIT", + api_name="alertrule.edit", + template='edited metric alert rule "{label}"', +) +add( + event_id=162, + name="ALERT_RULE_REMOVE", + api_name="alertrule.remove", + template='removed metric alert rule "{label}"', +) +add( + event_id=168, + name="ALERT_RULE_SNOOZE", + api_name="alertrule.mute", + template='muted metric alert rule "{label}"', +) +add( + event_id=163, + name="SAMPLING_BIAS_ENABLED", + api_name="sampling_priority.enabled", + template='enabled dynamic sampling priority "{name}"', +) +add( + event_id=164, + name="SAMPLING_BIAS_DISABLED", + api_name="sampling_priority.disabled", + template='disabled dynamic sampling priority "{name}"', +) +add( + event_id=165, + name="NOTIFICATION_ACTION_ADD", + api_name="notification_action.create", + template="added an action with the '{trigger}' trigger", +) +add( + event_id=166, + name="NOTIFICATION_ACTION_EDIT", + api_name="notification_action.edit", + template="edited an action with the '{trigger}' trigger", +) +add( + event_id=167, + name="NOTIFICATION_ACTION_REMOVE", + api_name="notification_action.remove", + template="removed an action with the '{trigger}' trigger", +) +add( + event_id=175, + name="TEAM_AND_PROJECT_CREATED", + api_name="team-and-project.created", + template="created team {team_slug} and added user as Team Admin while creating project {project_slug}", +) +add( + event_id=176, + name="ORGAUTHTOKEN_ADD", + api_name="org-auth-token.create", + template="added org auth token {name}", +) +add( + event_id=177, + name="ORGAUTHTOKEN_REMOVE", + api_name="org-auth-token.remove", + template="removed org auth token {name}", ) -default_manager.add( - AuditLogEvent( - event_id=213, - name="WORKFLOW_ADD", - api_name="workflow.add", - template="added workflow {name}", - ) + + +@add_with_render_func( + event_id=178, + name="PROJECT_PERFORMANCE_ISSUE_DETECTION_CHANGE", + api_name="project.change-performance-issue-detection", ) -default_manager.add( - AuditLogEvent( - event_id=214, - name="WORKFLOW_EDIT", - api_name="workflow.edit", - template="edited workflow {name}", +def render_project_performance_issue_detection_change(audit_log_entry: AuditLogEntry) -> str: + from sentry.issues.endpoints.project_performance_issue_settings import ( + project_settings_to_group_map as map, ) -) -default_manager.add( - AuditLogEvent( - event_id=215, - name="WORKFLOW_REMOVE", - api_name="workflow.remove", - template="removed workflow {name}", + + data = audit_log_entry.data + items_string = ", ".join( + f"to {'enable' if value else 'disable'} detection of {map[key].description} issue" + for (key, value) in data.items() + if key in map.keys() ) + return "edited project performance issue detector settings " + items_string + + +add( + event_id=179, + name="PROJECT_OWNERSHIPRULE_EDIT", + api_name="project.ownership-rule.edit", + template="modified ownership rules", +) +add( + event_id=180, + name="PROJECT_TEAM_REMOVE", + api_name="project-team.remove", + template="removed team {team_slug} from project {project_slug}", +) +add( + event_id=181, + name="PROJECT_TEAM_ADD", + api_name="project-team.add", + template="added team {team_slug} to project {project_slug}", +) +add( + event_id=182, + name="METRIC_BLOCK", + api_name="metric.block", + template="blocked metric {metric_mri} for project {project_slug}", +) +add( + event_id=183, + name="METRIC_TAGS_BLOCK", + api_name="metric.tags.block", + template="blocked {tags} tags of metric {metric_mri} for project {project_slug}", +) +add( + event_id=184, + name="METRIC_UNBLOCK", + api_name="metric.unblock", + template="unblocked metric {metric_mri} for project {project_slug}", +) +add( + event_id=185, + name="METRIC_TAGS_UNBLOCK", + api_name="metric.tags.unblock", + template="unblocked {tags} tags of metric {metric_mri} for project {project_slug}", +) +add( + event_id=186, + name="ISSUE_DELETE", + api_name="issue.delete", + template="Deleted issue {issue_id} for project {project_slug}", +) +add( + event_id=187, + name="SPAN_BASED_METRIC_CREATE", + api_name="span_extraction_rule_config.create", + template="Created span-based metric for span attribute {span_attribute} for project {project_slug}", ) -default_manager.add( - AuditLogEvent( - event_id=216, - name="DETECTOR_WORKFLOW_ADD", - api_name="detector_workflow.add", - template="connected detector {detector_name} to workflow {workflow_name}", - ) + +add( + event_id=188, + name="SPAN_BASED_METRIC_UPDATE", + api_name="span_extraction_rule_config.update", + template="Updated span-based metric for span attribute {span_attribute} for project {project_slug}", ) -default_manager.add( - AuditLogEvent( - event_id=217, - name="DETECTOR_WORKFLOW_REMOVE", - api_name="detector_workflow.remove", - template="disconnected detector {detector_name} from workflow {workflow_name}", - ) + +add( + event_id=189, + name="SPAN_BASED_METRIC_DELETE", + api_name="span_extraction_rule_config.delete", + template="Deleted span-based metric for span attribute {span_attribute} for project {project_slug}", ) -default_manager.add( - AuditLogEvent( - event_id=204, - name="MEMBER_REINVITE", - api_name="member.reinvite", - template="reinvited member {email}", - ) +add( + event_id=190, + name="PROJECT_TEMPLATE_CREATED", + api_name="project_template.create", + template="Created project template {name} for organization {organization_id}", ) -default_manager.add( - AuditLogEvent( - event_id=1152, - name="TEMPEST_CLIENT_ID_ADD", - api_name="playstation-client-id.create", - template="added playstation client id {client_id}", - ) +add( + event_id=200, + name="UPTIME_MONITOR_ADD", + api_name="uptime_monitor.add", + template="added uptime monitor {name}", +) +add( + event_id=201, + name="UPTIME_MONITOR_EDIT", + api_name="uptime_monitor.edit", + template="edited uptime monitor {name}", +) +add( + event_id=202, + name="UPTIME_MONITOR_REMOVE", + api_name="uptime_monitor.remove", + template="removed uptime monitor {name}", +) +add( + event_id=210, + name="DETECTOR_ADD", + api_name="detector.add", + template="added detector {name}", +) +add( + event_id=211, + name="DETECTOR_EDIT", + api_name="detector.edit", + template="edited detector {name}", +) +add( + event_id=212, + name="DETECTOR_REMOVE", + api_name="detector.remove", + template="removed detector {name}", +) +add( + event_id=213, + name="WORKFLOW_ADD", + api_name="workflow.add", + template="added workflow {name}", +) +add( + event_id=214, + name="WORKFLOW_EDIT", + api_name="workflow.edit", + template="edited workflow {name}", +) +add( + event_id=215, + name="WORKFLOW_REMOVE", + api_name="workflow.remove", + template="removed workflow {name}", +) +add( + event_id=216, + name="DETECTOR_WORKFLOW_ADD", + api_name="detector_workflow.add", + template="connected detector {detector_name} to workflow {workflow_name}", +) +add( + event_id=217, + name="DETECTOR_WORKFLOW_REMOVE", + api_name="detector_workflow.remove", + template="disconnected detector {detector_name} from workflow {workflow_name}", ) -default_manager.add( - AuditLogEvent( - event_id=1153, - name="TEMPEST_CLIENT_ID_REMOVE", - api_name="playstation-client-id.remove", - template="removed playstation client id {client_id}", - ) + +add( + event_id=204, + name="MEMBER_REINVITE", + api_name="member.reinvite", + template="reinvited member {email}", ) -default_manager.add( - AuditLogEvent( - event_id=1154, - name="PROJECT_ADD_WITH_ORIGIN", - api_name="project.create-with-origin", - template="created project {slug} via {origin}", - ) + +add( + event_id=1152, + name="TEMPEST_CLIENT_ID_ADD", + api_name="playstation-client-id.create", + template="added playstation client id {client_id}", +) +add( + event_id=1153, + name="TEMPEST_CLIENT_ID_REMOVE", + api_name="playstation-client-id.remove", + template="removed playstation client id {client_id}", +) +add( + event_id=1154, + name="PROJECT_ADD_WITH_ORIGIN", + api_name="project.create-with-origin", + template="created project {slug} via {origin}", ) # NOTE: 1155 is defined in the private repo but not here in the public repo so we skip it. -default_manager.add( - AuditLogEvent( - event_id=1156, - name="REPLAYDELETIONJOBMODEL_START", - api_name="replay-deletion-jobs.start", - template="started replay deletion job", - ) +add( + event_id=1156, + name="REPLAYDELETIONJOBMODEL_START", + api_name="replay-deletion-jobs.start", + template="started replay deletion job", ) -default_manager.add( - AuditLogEvent( - event_id=1157, - name="REPLAYDELETIONJOBMODEL_CANCELED", - api_name="replay-deletion-jobs.stop", - template="canceled replay deletion job", - ) + +add( + event_id=1157, + name="REPLAYDELETIONJOBMODEL_CANCELED", + api_name="replay-deletion-jobs.stop", + template="canceled replay deletion job", ) -default_manager.add( - AuditLogEvent( - event_id=1158, - name="ORG_CONSOLE_PLATFORM_EDIT", - api_name="org.console-platform.edit", - template="{console_platforms}", - ) + +add( + event_id=1158, + name="ORG_CONSOLE_PLATFORM_EDIT", + api_name="org.console-platform.edit", + template="{console_platforms}", ) From cb761a4d3d5fa85a14cb599cdf3f3d70e7ffb8ca Mon Sep 17 00:00:00 2001 From: Fabian Schindler Date: Mon, 1 Sep 2025 17:48:53 +0200 Subject: [PATCH 2/2] fix(auditlogs): add missing event 'INVITE_REMOVE' --- src/sentry/audit_log/register.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sentry/audit_log/register.py b/src/sentry/audit_log/register.py index b3a37e4f5d664e..fc0a9e59e0e359 100644 --- a/src/sentry/audit_log/register.py +++ b/src/sentry/audit_log/register.py @@ -506,6 +506,12 @@ def render_internal_integration_disabled(audit_log_entry: AuditLogEntry) -> str: api_name="invite-request.remove", template="removed the invite request for {email}", ) +add( + event_id=142, + name="INVITE_REMOVE", + api_name="invite.remove", + template="removed the invite for {email}", +) add( event_id=160, name="ALERT_RULE_ADD",