diff --git a/atst/domain/application_roles.py b/atst/domain/application_roles.py index e1956aba..c0e8e79b 100644 --- a/atst/domain/application_roles.py +++ b/atst/domain/application_roles.py @@ -14,7 +14,9 @@ class ApplicationRoles(object): @classmethod def create(cls, user, application, permission_set_names): - application_role = ApplicationRole(user=user, application_id=application.id) + application_role = ApplicationRole( + user=user, application_id=application.id, application=application + ) application_role.permission_sets = ApplicationRoles._permission_sets_for_names( permission_set_names diff --git a/atst/domain/audit_log.py b/atst/domain/audit_log.py index 97bb6603..4090ccfd 100644 --- a/atst/domain/audit_log.py +++ b/atst/domain/audit_log.py @@ -1,5 +1,3 @@ -from sqlalchemy import or_ - from atst.database import db from atst.domain.common import Query from atst.models.audit_event import AuditEvent diff --git a/atst/models/application_invitation.py b/atst/models/application_invitation.py index 9f1db550..328ac59e 100644 --- a/atst/models/application_invitation.py +++ b/atst/models/application_invitation.py @@ -26,6 +26,10 @@ class ApplicationInvitation(Base, TimestampsMixin, AuditableMixin, InvitesMixin) def application_id(self): return self.role.application_id + @property + def portfolio_id(self): + return self.role.portfolio_id + @property def event_details(self): return {"email": self.email, "dod_id": self.user_dod_id} diff --git a/atst/models/application_role.py b/atst/models/application_role.py index fe56a37d..b98f57a7 100644 --- a/atst/models/application_role.py +++ b/atst/models/application_role.py @@ -75,6 +75,9 @@ class ApplicationRole( lambda prms: prms.name == perm_set_name, self.permission_sets ) + @property + def portfolio_id(self): + return self.application.portfolio_id Index( "application_role_user_application", diff --git a/atst/models/environment.py b/atst/models/environment.py index 1817517b..e15373b4 100644 --- a/atst/models/environment.py +++ b/atst/models/environment.py @@ -35,7 +35,8 @@ class Environment( def portfolio(self): return self.application.portfolio - def auditable_portfolio_id(self): + @property + def portfolio_id(self): return self.application.portfolio_id def __repr__(self): diff --git a/atst/models/environment_role.py b/atst/models/environment_role.py index 55cf742e..5ad67f6c 100644 --- a/atst/models/environment_role.py +++ b/atst/models/environment_role.py @@ -38,6 +38,14 @@ class EnvironmentRole( def history(self): return self.get_changes() + @property + def portfolio_id(self): + return self.environment.application.portfolio_id + + @property + def application_id(self): + return self.environment.application_id + @property def displayname(self): return self.role diff --git a/atst/models/mixins/auditable.py b/atst/models/mixins/auditable.py index 70c462a2..1d83da82 100644 --- a/atst/models/mixins/auditable.py +++ b/atst/models/mixins/auditable.py @@ -13,33 +13,20 @@ class AuditableMixin(object): @staticmethod def create_audit_event(connection, resource, action, changed_state=None): user_id = getattr_path(g, "current_user.id") - resource_type = resource.resource_type - display_name = resource.displayname - event_details = resource.event_details - - if resource_type == "portfolio": - portfolio_id = resource.id - else: - portfolio_id = resource.portfolio_id - - if resource_type == "application": - application_id = resource.id - else: - application_id = resource.application_id if changed_state is None: changed_state = resource.history if action == ACTION_UPDATE else None audit_event = AuditEvent( user_id=user_id, - portfolio_id=portfolio_id, - application_id=application_id, - resource_type=resource_type, + portfolio_id=resource.portfolio_id, + application_id=resource.application_id, + resource_type=resource.resource_type, resource_id=resource.id, - display_name=display_name, + display_name=resource.displayname, action=action, changed_state=changed_state, - event_details=event_details, + event_details=resource.event_details, ) app.logger.info( diff --git a/tests/domain/test_audit_log.py b/tests/domain/test_audit_log.py index 687b2395..da74e7b0 100644 --- a/tests/domain/test_audit_log.py +++ b/tests/domain/test_audit_log.py @@ -4,12 +4,17 @@ from atst.domain.applications import Applications from atst.domain.audit_log import AuditLog from atst.domain.exceptions import UnauthorizedError from atst.domain.permission_sets import PermissionSets +from atst.domain.portfolios import Portfolios from atst.models.portfolio_role import Status as PortfolioRoleStatus from tests.factories import ( - UserFactory, + ApplicationFactory, + ApplicationInvitationFactory, + ApplicationRoleFactory, + EnvironmentFactory, + EnvironmentRoleFactory, PortfolioFactory, PortfolioRoleFactory, - ApplicationFactory, + UserFactory, ) @@ -63,23 +68,52 @@ def test_portfolio_audit_log_only_includes_current_portfolio_events(): ) -def test_portfolio_audit_log_includes_app_and_env_events(): - # TODO: add in events for - # creating/updating/deleting env_role and app_role - # creating an app_invitation +def test_get_portfolio_events_includes_app_and_env_events(): owner = UserFactory.create() + # add portfolio level events portfolio = PortfolioFactory.create(owner=owner) + portfolio_events = AuditLog.get_portfolio_events(portfolio) + + # add application level events application = ApplicationFactory.create(portfolio=portfolio) Applications.update(application, {"name": "Star Cruiser"}) + app_role = ApplicationRoleFactory.create(application=application) + app_invite = ApplicationInvitationFactory.create(role=app_role) + portfolio_and_app_events = AuditLog.get_portfolio_events(portfolio) + assert len(portfolio_events) < len(portfolio_and_app_events) - events = AuditLog.get_portfolio_events(portfolio) + # add environment level events + env = EnvironmentFactory.create(application=application) + env_role = EnvironmentRoleFactory.create(environment=env, user=app_role.user) + portfolio_app_and_env_events = AuditLog.get_portfolio_events(portfolio) + assert len(portfolio_and_app_events) < len(portfolio_app_and_env_events) + resource_types = [event.resource_type for event in portfolio_app_and_env_events] + assert "application" in resource_types + assert "application_role" in resource_types + assert "application_invitation" in resource_types + assert "environment" in resource_types + assert "environment_role" in resource_types + + +def test_get_application_events(): + # add in some portfolio level events + portfolio = PortfolioFactory.create() + Portfolios.update(portfolio, {"name": "New Name"}) + # add app level events + application = ApplicationFactory.create(portfolio=portfolio) + Applications.update(application, {"name": "Star Cruiser"}) + app_role = ApplicationRoleFactory.create(application=application) + app_invite = ApplicationInvitationFactory.create(role=app_role) + env = EnvironmentFactory.create(application=application) + env_role = EnvironmentRoleFactory.create(environment=env, user=app_role.user) + # add rando app + rando_app = ApplicationFactory.create(portfolio=portfolio) + + events = AuditLog.get_application_events(application) for event in events: - assert event.portfolio_id == portfolio.id - if event.resource_type == 'application': - assert event.application_id == application.id - pass + assert event.application_id == application.id + assert not event.application_id == rando_app.id - -def test_application_audit_log_does_not_include_portfolio_events(): - pass + resource_types = [event.resource_type for event in events] + assert "portfolio" not in resource_types