diff --git a/src/dispatch/plugins/dispatch_slack/case/interactive.py b/src/dispatch/plugins/dispatch_slack/case/interactive.py index abf0175bf674..a4d6bf587424 100644 --- a/src/dispatch/plugins/dispatch_slack/case/interactive.py +++ b/src/dispatch/plugins/dispatch_slack/case/interactive.py @@ -39,7 +39,6 @@ from dispatch.participant_role import service as participant_role_service from dispatch.participant_role.models import ParticipantRoleType from dispatch.plugin import service as plugin_service -from dispatch.plugins.dispatch_duo.enums import PushResponseResult from dispatch.plugins.dispatch_slack import service as dispatch_slack_service from dispatch.plugins.dispatch_slack.bolt import app from dispatch.plugins.dispatch_slack.case.enums import ( @@ -860,8 +859,7 @@ def _create_snooze_filter( db_session.commit() # Check if last_mfa_time was within the last hour - last_hour = datetime.now() - timedelta(hours=1) - if (user.last_mfa_time and user.last_mfa_time > last_hour) or mfa_enabled is False: + if not mfa_enabled: _create_snooze_filter( db_session=db_session, user=user, @@ -874,12 +872,23 @@ def _create_snooze_filter( message="Snooze Filter added successfully.", ) else: - # Send the MFA push notification - response = mfa_plugin.instance.send_push_notification( - username=context["user"].email, - type="Are you creating a snooze filter in Dispatch?", + challenge, challenge_url = mfa_plugin.instance.create_mfa_challenge( + action="signal-snooze", + current_user=user, + db_session=db_session, + project_id=context["subject"].project_id, + ) + ack_engagement_submission_event( + ack=ack, mfa_enabled=mfa_enabled, challenge_url=challenge_url + ) + + # wait for the mfa challenge + response = mfa_plugin.instance.wait_for_challenge( + challenge_id=challenge.challenge_id, + db_session=db_session, ) - if response == PushResponseResult.allow: + + if response == MfaChallengeStatus.APPROVED: # Get the existing filters for the signal _create_snooze_filter( db_session=db_session, @@ -895,10 +904,10 @@ def _create_snooze_filter( user.last_mfa_time = datetime.now() db_session.commit() else: - if response == PushResponseResult.timeout: + if response == MfaChallengeStatus.EXPIRED: text = "Adding Snooze failed, the MFA request timed out." - elif response == PushResponseResult.user_not_found: - text = "Adding Snooze failed, user not found in MFA provider." + elif response == MfaChallengeStatus.DENIED: + text = "Adding Snooze failed, challenge did not complete succsfully." else: text = "Adding Snooze failed, you must accept the MFA prompt." @@ -1735,7 +1744,7 @@ def report_issue( Context( elements=[ MarkdownText( - text="Cases are meant to triage events that do not raise to the level of incidents, but can be escalated to incidents if necessary. If you suspect a security issue and need help, please fill out this form to the best of your abilities.." + text="Cases are meant for triaging events that do not raise to the level of incidents, but can be escalated to incidents if necessary." ) ] ), @@ -1780,13 +1789,6 @@ def handle_report_project_select_action( ) blocks = [ - Context( - elements=[ - MarkdownText( - text="Cases are meant to triage events that do not raise to the level of incidents, but can be escalated to incidents if necessary. If you suspect a security issue and need help, please fill out this form to the best of your abilities.." - ) - ] - ), title_input(), description_input(), project_select( @@ -1809,13 +1811,6 @@ def handle_report_project_select_action( ) ] ), - case_priority_select( - db_session=db_session, - project_id=project.id, - initial_option=None, - optional=True, - block_id=None, # ensures state is reset - ), ] modal = Modal( @@ -1899,13 +1894,6 @@ def handle_report_case_type_select_action( assignee_slack_id = None blocks = [ - Context( - elements=[ - MarkdownText( - text="Cases are meant to triage events that do not raise to the level of incidents, but can be escalated to incidents if necessary. If you suspect a security issue and need help, please fill out this form to the best of your abilities." - ) - ] - ), title_input(), description_input(), project_select( @@ -1928,13 +1916,6 @@ def handle_report_case_type_select_action( ) ] ), - case_priority_select( - db_session=db_session, - project_id=project.id, - initial_option=None, - optional=True, - block_id=None, # ensures state is reset - ), ] # Create a new assignee_select block with a unique block_id @@ -1944,7 +1925,7 @@ def handle_report_case_type_select_action( initial_user=assignee_slack_id if assignee_slack_id else None, action_id=CaseReportActions.assignee_select, block_id=new_block_id, - ) + ), ) # Conditionally add context blocks @@ -1983,6 +1964,16 @@ def handle_report_case_type_select_action( ] ) + blocks.append( + case_priority_select( + db_session=db_session, + project_id=project.id, + initial_option=None, + optional=True, + block_id=None, # ensures state is reset + ), + ) + modal = Modal( title="Open a Case", blocks=blocks, diff --git a/src/dispatch/plugins/dispatch_slack/case/messages.py b/src/dispatch/plugins/dispatch_slack/case/messages.py index 733e93ec4a3d..c4fd2993c601 100644 --- a/src/dispatch/plugins/dispatch_slack/case/messages.py +++ b/src/dispatch/plugins/dispatch_slack/case/messages.py @@ -152,19 +152,17 @@ def create_case_message(case: Case, channel_id: str) -> list[Block]: Button( text="Edit", action_id=CaseNotificationActions.edit, - style="primary", value=button_metadata, ), Button( - text="Escalate", - action_id=CaseNotificationActions.escalate, - style="danger", + text=":slack: Create Channel", + action_id=CaseNotificationActions.migrate, value=button_metadata, ), Button( - text="Create Channel", - action_id=CaseNotificationActions.migrate, - style="primary", + text="🔥 Escalate", + action_id=CaseNotificationActions.escalate, + style="danger", value=button_metadata, ), ] @@ -208,7 +206,7 @@ def create_signal_messages(case_id: int, channel_id: str, db_session: Session) - # Define the initial elements with "Raw Data" and "Snooze" buttons elements = [ Button( - text="Snooze", + text="💤 Snooze", action_id=SignalNotificationActions.snooze, value=button_metadata, ), @@ -219,7 +217,7 @@ def create_signal_messages(case_id: int, channel_id: str, db_session: Session) - # If `first_instance_signal.external_url` is not empty, add the "Response Plan" button elements.append( Button( - text="Response Plan", + text="🔖 Response Plan", action_id="button-link", url=first_instance_signal.external_url, ) @@ -308,9 +306,13 @@ def create_genai_signal_summary( instances = signal_service.get_instances_in_case(db_session=db_session, case_id=case.id) (first_instance_id, first_instance_signal) = instances.first() - related_cases = signal_service.get_cases_for_signal( - db_session=db_session, signal_id=first_instance_signal.id - ).filter(Case.id != case.id) + related_cases = ( + signal_service.get_cases_for_signal( + db_session=db_session, signal_id=first_instance_signal.id + ) + .from_self() + .filter(Case.id != case.id) + ) # Prepare historical context historical_context = [] @@ -345,11 +347,19 @@ def create_genai_signal_summary( genai_plugin = plugin_service.get_active_instance( db_session=db_session, project_id=case.project.id, plugin_type="artificial-intelligence" ) + if not genai_plugin: + log.warning("artificial-intelligence plugin not enabled, will not generate signal summary") + return signal_metadata_blocks + + if not signal_instance.signal.genai_prompt: + log.warning( + f"artificial-intelligence plugin enabled but no prompt defined for {signal_instance.signal.name}" + ) return signal_metadata_blocks response = genai_plugin.instance.chat_completion( - prompt=f"""{first_instance_signal.prompt} + prompt=f"""{signal_instance.signal.genai_prompt} Current Event: {str(signal_instance.raw)} diff --git a/src/dispatch/plugins/dispatch_slack/plugin.py b/src/dispatch/plugins/dispatch_slack/plugin.py index 4907742fdb13..edf04edde695 100644 --- a/src/dispatch/plugins/dispatch_slack/plugin.py +++ b/src/dispatch/plugins/dispatch_slack/plugin.py @@ -122,18 +122,20 @@ def create_threaded(self, case: Case, conversation_id: str, db_session: Session) except Exception as e: logger.exception(f"Error uploading alert JSON to the Case thread: {e}") - message = create_genai_signal_summary( - case=case, - channel_id=conversation_id, - db_session=db_session, - client=client, - ) - send_message( - client=client, - conversation_id=conversation_id, - ts=case.signal_thread_ts, - blocks=message, - ) + try: + send_message( + client=client, + conversation_id=conversation_id, + ts=case.signal_thread_ts, + blocks=create_genai_signal_summary( + case=case, + channel_id=conversation_id, + db_session=db_session, + client=client, + ), + ) + except Exception as e: + logger.exception(f"Error generating Gen AI response to case: {e}") db_session.commit() return response diff --git a/src/dispatch/static/dispatch/src/signal/NewEditDialog.vue b/src/dispatch/static/dispatch/src/signal/NewEditDialog.vue index adbb1cf96f72..0200e10f4f45 100644 --- a/src/dispatch/static/dispatch/src/signal/NewEditDialog.vue +++ b/src/dispatch/static/dispatch/src/signal/NewEditDialog.vue @@ -242,7 +242,6 @@ hint="The model to use for processing." persistent-hint name="model" - readonly /> @@ -254,7 +253,6 @@ hint="The system message to set the behavior of the assistant" persistent-hint name="systemMessage" - readonly /> @@ -266,7 +264,6 @@ hint="The prompt to use for the assistant." persistent-hint name="Prompt" - readonly />