diff --git a/content/response_integrations/power_ups/git_sync/core/GitSyncManager.py b/content/response_integrations/power_ups/git_sync/core/GitSyncManager.py index 3f6e2d34f..5694eaf1c 100644 --- a/content/response_integrations/power_ups/git_sync/core/GitSyncManager.py +++ b/content/response_integrations/power_ups/git_sync/core/GitSyncManager.py @@ -640,6 +640,7 @@ def update_local_workflow(self, workflow: Workflow) -> None: """Update an existing workflow in the platform.""" self.logger.info(f"Updating existing workflow '{workflow.name}'") self._adjust_workflow_ids(workflow) + self._remap_workflow_roles(workflow) self.api.save_playbook(workflow.raw_data) self._save_workflow_mod_time_to_context(workflow) self.logger.info(f"Workflow '{workflow.name}' was updated successfully") @@ -658,10 +659,43 @@ def install_new_workflow(self, workflow: Workflow) -> None: self.logger.info(f"Installing new workflow '{workflow.name}'") self._define_workflow_as_new(workflow) self._process_steps(workflow) + self._remap_workflow_roles(workflow) self.api.save_playbook(workflow.raw_data) self._save_workflow_mod_time_to_context(workflow) self.logger.info(f"New workflow '{workflow.name}' was installed successfully") + def _remap_workflow_roles(self, workflow: Workflow) -> None: + """Remap the role IDs of a workflow overviewTemplate based on the roles available in the system. + + Args: + workflow: The workflow object to remap roles for. + """ + if not workflow.raw_data.get("overviewTemplates"): + return + + roles_map = { + role["name"]: role["id"] + for role in self._soc_roles + if "name" in role and "id" in role + } + + for template in workflow.raw_data["overviewTemplates"]: + role_names = template.pop("roleNames", None) + if not role_names: + continue + + valid_role_ids = [] + for role_name in role_names: + if role_name in roles_map: + valid_role_ids.append(roles_map[role_name]) + else: + self.logger.warn( + f"Role '{role_name}' for view '{template.get('name')}' in workflow " + f"'{workflow.name}' does not exist in the destination system. It will be removed." + ) + + template["roles"] = valid_role_ids + def _process_steps( self, workflow: Workflow, @@ -793,6 +827,13 @@ def _installed_playbooks(self) -> dict[str, dict[str, Any]]: } return self._cache.get("playbooks") + @property + def _soc_roles(self) -> list[dict[str, Any]]: + """Currently configured SOC roles""" + if "soc_roles" not in self._cache: + self._cache["soc_roles"] = self.api.get_soc_roles() + return self._cache.get("soc_roles") + @property def _playbook_categories(self) -> dict: """Currently configured playbook categories""" diff --git a/content/response_integrations/power_ups/git_sync/core/SiemplifyApiClient.py b/content/response_integrations/power_ups/git_sync/core/SiemplifyApiClient.py index 8c904b5f6..ee502bc53 100644 --- a/content/response_integrations/power_ups/git_sync/core/SiemplifyApiClient.py +++ b/content/response_integrations/power_ups/git_sync/core/SiemplifyApiClient.py @@ -501,6 +501,14 @@ def get_playbook_categories(self): self.validate_response(res) return res.json() + def get_soc_roles(self) -> list[dict]: + """Get the SOC roles from the platform. + + Returns: + A list of SOC roles. + """ + return self.get_page_results("socroles/getSocRoles") + def get_simulated_cases(self): res = self.session.get("attackssimulator/GetCustomCases") self.validate_response(res) diff --git a/content/response_integrations/power_ups/git_sync/release_notes.yaml b/content/response_integrations/power_ups/git_sync/release_notes.yaml index 2253cfa60..d209c7880 100644 --- a/content/response_integrations/power_ups/git_sync/release_notes.yaml +++ b/content/response_integrations/power_ups/git_sync/release_notes.yaml @@ -485,3 +485,9 @@ item_type: Jobs publish_time: '2026-04-22' ticket_number: '461900756' +- description: Remap playbook view roles by name to destination IDs. + integration_version: 45.0 + item_name: GitSync + item_type: Integration + publish_time: '2026-04-20' + ticket_number: ''