From efc03cdd077471d388671f83675d3488ee095ac1 Mon Sep 17 00:00:00 2001 From: Charlie Luo Date: Mon, 6 Oct 2025 15:26:07 -0700 Subject: [PATCH 1/2] create audit logs for internal integration tokens being removed and added --- .../endpoints/sentry_internal_app_token_details.py | 10 +++++++++- .../api/endpoints/sentry_internal_app_tokens.py | 2 +- src/sentry/sentry_apps/installations.py | 2 +- .../test_sentry_internal_app_token_details.py | 14 ++++++++++++-- .../endpoints/test_sentry_internal_app_tokens.py | 13 ++++++++++++- 5 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/sentry/sentry_apps/api/endpoints/sentry_internal_app_token_details.py b/src/sentry/sentry_apps/api/endpoints/sentry_internal_app_token_details.py index f01645a57cbfcc..7400815286a9aa 100644 --- a/src/sentry/sentry_apps/api/endpoints/sentry_internal_app_token_details.py +++ b/src/sentry/sentry_apps/api/endpoints/sentry_internal_app_token_details.py @@ -4,7 +4,7 @@ from rest_framework.request import Request from rest_framework.response import Response -from sentry import analytics, deletions +from sentry import analytics, audit_log, deletions from sentry.analytics.events.sentry_app_installation_token_deleted import ( SentryAppInstallationTokenDeleted, ) @@ -18,6 +18,7 @@ ) from sentry.sentry_apps.api.endpoints.sentry_app_details import PARTNERSHIP_RESTRICTED_ERROR_MESSAGE from sentry.sentry_apps.models.sentry_app_installation_token import SentryAppInstallationToken +from sentry.utils.audit import create_audit_entry @control_silo_endpoint @@ -74,5 +75,12 @@ def delete(self, request: Request, sentry_app, api_token) -> Response: sentry_app=sentry_app.slug, ) ) + create_audit_entry( + request=request, + organization_id=sentry_app_installation.organization_id, + target_object=api_token.id, + event=audit_log.get_event_id("INTERNAL_INTEGRATION_REMOVE_TOKEN"), + data={"sentry_app": sentry_app.name}, + ) return Response(status=204) diff --git a/src/sentry/sentry_apps/api/endpoints/sentry_internal_app_tokens.py b/src/sentry/sentry_apps/api/endpoints/sentry_internal_app_tokens.py index 826f2f7c686a6a..bb3052f33a5a86 100644 --- a/src/sentry/sentry_apps/api/endpoints/sentry_internal_app_tokens.py +++ b/src/sentry/sentry_apps/api/endpoints/sentry_internal_app_tokens.py @@ -68,7 +68,7 @@ def post(self, request: Request, sentry_app) -> Response: request.user, (User, RpcUser) ), "User must be authenticated to install a sentry app" api_token = SentryAppInstallationTokenCreator( - sentry_app_installation=sentry_app_installation + sentry_app_installation=sentry_app_installation, generate_audit=True ).run(request=request, user=request.user) except ApiTokenLimitError as e: return Response(str(e), status=status.HTTP_403_FORBIDDEN) diff --git a/src/sentry/sentry_apps/installations.py b/src/sentry/sentry_apps/installations.py index 32a6d417dfdfd4..674be89c84b44c 100644 --- a/src/sentry/sentry_apps/installations.py +++ b/src/sentry/sentry_apps/installations.py @@ -92,7 +92,7 @@ def audit(self, request: HttpRequest | None, api_token: ApiToken) -> None: if request and self.generate_audit: create_audit_entry( request=request, - organization=self.organization_id, + organization_id=self.organization_id, target_object=api_token.id, event=audit_log.get_event_id("INTERNAL_INTEGRATION_ADD_TOKEN"), data={"sentry_app": self.sentry_app.name}, diff --git a/tests/sentry/sentry_apps/api/endpoints/test_sentry_internal_app_token_details.py b/tests/sentry/sentry_apps/api/endpoints/test_sentry_internal_app_token_details.py index 6ac20d996aadef..e84667f04815aa 100644 --- a/tests/sentry/sentry_apps/api/endpoints/test_sentry_internal_app_token_details.py +++ b/tests/sentry/sentry_apps/api/endpoints/test_sentry_internal_app_token_details.py @@ -1,7 +1,9 @@ from django.test import override_settings from rest_framework import status +from sentry import audit_log from sentry.models.apitoken import ApiToken +from sentry.testutils.asserts import assert_org_audit_log_exists from sentry.testutils.cases import APITestCase from sentry.testutils.helpers.options import override_options from sentry.testutils.silo import control_silo_test @@ -28,12 +30,20 @@ def setUp(self) -> None: def test_delete_token(self) -> None: self.login_as(user=self.user) + token_id = self.api_token.id self.get_success_response( self.internal_sentry_app.slug, - self.api_token.id, + token_id, status_code=status.HTTP_204_NO_CONTENT, ) - assert not ApiToken.objects.filter(pk=self.api_token.id).exists() + assert not ApiToken.objects.filter(pk=token_id).exists() + + assert_org_audit_log_exists( + organization=self.org, + event=audit_log.get_event_id("INTERNAL_INTEGRATION_REMOVE_TOKEN"), + target_object=token_id, + actor=self.user, + ) def test_delete_invalid_token(self) -> None: self.login_as(user=self.user) diff --git a/tests/sentry/sentry_apps/api/endpoints/test_sentry_internal_app_tokens.py b/tests/sentry/sentry_apps/api/endpoints/test_sentry_internal_app_tokens.py index 87dbfb143d81a5..52209999cd00d6 100644 --- a/tests/sentry/sentry_apps/api/endpoints/test_sentry_internal_app_tokens.py +++ b/tests/sentry/sentry_apps/api/endpoints/test_sentry_internal_app_tokens.py @@ -1,8 +1,10 @@ from django.test import override_settings from rest_framework import status +from sentry import audit_log from sentry.models.apitoken import ApiToken from sentry.sentry_apps.models.sentry_app import MASKED_VALUE +from sentry.testutils.asserts import assert_org_audit_log_exists from sentry.testutils.cases import APITestCase from sentry.testutils.helpers.options import override_options from sentry.testutils.silo import control_silo_test @@ -35,7 +37,16 @@ def test_create_token(self) -> None: self.internal_sentry_app.slug, status_code=status.HTTP_201_CREATED ) - assert ApiToken.objects.get(token=response.data["token"]) + api_token = ApiToken.objects.get(token=response.data["token"]) + assert api_token + + # Verify audit log entry was created + assert_org_audit_log_exists( + organization=self.org, + event=audit_log.get_event_id("INTERNAL_INTEGRATION_ADD_TOKEN"), + target_object=api_token.id, + actor=self.user, + ) def test_non_internal_app(self) -> None: sentry_app = self.create_sentry_app(name="My External App", organization=self.org) From 8140496b6753699c024d7335761936164824bee0 Mon Sep 17 00:00:00 2001 From: Charlie Luo Date: Mon, 6 Oct 2025 15:27:53 -0700 Subject: [PATCH 2/2] :bufo-ai: --- .../sentry_apps/api/endpoints/test_sentry_internal_app_tokens.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/sentry/sentry_apps/api/endpoints/test_sentry_internal_app_tokens.py b/tests/sentry/sentry_apps/api/endpoints/test_sentry_internal_app_tokens.py index 52209999cd00d6..b8f139c54342e5 100644 --- a/tests/sentry/sentry_apps/api/endpoints/test_sentry_internal_app_tokens.py +++ b/tests/sentry/sentry_apps/api/endpoints/test_sentry_internal_app_tokens.py @@ -40,7 +40,6 @@ def test_create_token(self) -> None: api_token = ApiToken.objects.get(token=response.data["token"]) assert api_token - # Verify audit log entry was created assert_org_audit_log_exists( organization=self.org, event=audit_log.get_event_id("INTERNAL_INTEGRATION_ADD_TOKEN"),