diff --git a/configurations/integrations/issueTmpl.json b/configurations/integrations/issueTmpl.json index c38c9155..6cd303a3 100644 --- a/configurations/integrations/issueTmpl.json +++ b/configurations/integrations/issueTmpl.json @@ -1,4 +1,5 @@ { + "collaborationGUID": "", "issueType": "clusterControl", "fields": { "summary": "armo system test", diff --git a/infrastructure/backend_api.py b/infrastructure/backend_api.py index 13593ee1..09fa905e 100644 --- a/infrastructure/backend_api.py +++ b/infrastructure/backend_api.py @@ -2879,19 +2879,36 @@ def get_runtime_policies_uniquevalues(self, body): return r def get_integration_status(self, provider: str): - url = API_INTEGRATIONS + "/connection/status" + url = API_INTEGRATIONS + "/connectionV2/status" r = self.get(url, params={"customerGUID": self.selected_tenant_id, "provider": provider}) assert 200 <= r.status_code < 300, f"{inspect.currentframe().f_code.co_name}, url: '{url}', customer: '{self.customer}' code: {r.status_code}, message: '{r.text}'" return r.json() def get_jira_config(self): - url = API_INTEGRATIONS + "/jira/config" + url = API_INTEGRATIONS + "/jira/configV2" r = self.get(url, params={"customerGUID": self.selected_tenant_id}) assert 200 <= r.status_code < 300, f"{inspect.currentframe().f_code.co_name}, url: '{url}', customer: '{self.customer}' code: {r.status_code}, message: '{r.text}'" return r.json() + + def get_jira_collaboration_guid_by_site_name(self, site_name: str): + config = self.get_jira_config() + jira_connections = config.get("jiraConnections", []) + if not jira_connections: + raise Exception("No Jira connections found in the response") + + for connection in jira_connections: + selected_site = connection.get("selectedSite", {}) + if selected_site.get("name") == site_name: + collabGUID = connection.get("jiraCollabGUID", "") + if collabGUID: + return collabGUID + else: + raise Exception(f"Jira collaboration GUID is empty or missing for site '{site_name}'") + + raise Exception(f"No Jira collaboration found for site '{site_name}'") def update_jira_config(self, body: dict): - url = API_INTEGRATIONS + "/jira/config" + url = API_INTEGRATIONS + "/jira/configV2" r = self.post(url, params={"customerGUID": self.selected_tenant_id}, json=body) @@ -2901,7 +2918,7 @@ def update_jira_config(self, body: dict): self.customer, r.status_code, r.text)) def search_jira_projects(self, body: dict): - url = API_INTEGRATIONS + "/jira/projects/search" + url = API_INTEGRATIONS + "/jira/projectsV2/search" r = self.post(url, params={"customerGUID": self.customer_guid}, json=body) if not 200 <= r.status_code < 300: @@ -2911,7 +2928,7 @@ def search_jira_projects(self, body: dict): return r.json() def search_jira_issue_types(self, body: dict): - url = API_INTEGRATIONS + "/jira/issueTypes/search" + url = API_INTEGRATIONS + "/jira/issueTypesV2/search" r = self.post(url, params={"customerGUID": self.customer_guid}, json=body) if not 200 <= r.status_code < 300: @@ -2921,7 +2938,7 @@ def search_jira_issue_types(self, body: dict): return r.json() def search_jira_schema(self, body: dict): - url = API_INTEGRATIONS + "/jira/issueTypes/schema/search" + url = API_INTEGRATIONS + "/jira/issueTypesV2/schema/search" r = self.post(url, params={"customerGUID": self.customer_guid}, json=body) if not 200 <= r.status_code < 300: @@ -2941,7 +2958,7 @@ def search_jira_issue_field(self, body: dict): return r.json() def create_jira_issue(self, body: dict): - url = API_INTEGRATIONS + "/jira/issue" + url = API_INTEGRATIONS + "/jira/issueV2" r = self.post(url, params={"customerGUID": self.customer_guid}, json=body) if not 200 <= r.status_code < 300: diff --git a/tests_scripts/helm/jira_integration.py b/tests_scripts/helm/jira_integration.py index 940ca1df..44cc1388 100644 --- a/tests_scripts/helm/jira_integration.py +++ b/tests_scripts/helm/jira_integration.py @@ -30,6 +30,7 @@ def __init__( self.helm_kwargs.update(test_helm_kwargs) self.wait_for_agg_to_end = False + self.site_name = "cyberarmor-io" def cleanup(self, **kwargs): super().cleanup(**kwargs) @@ -64,15 +65,16 @@ def setup_jira_config(self): jiraStatus = next((status for status in connectionStatus if status['provider'] == 'jira'), None) assert jiraStatus, "Jira is missing form connection status" assert jiraStatus['status'] == "connected", "Jira is not connected" + jiraCollaborationGUID = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name) Logger.logger.info('get cyberarmor-io site') - projectsResp = self.backend.search_jira_projects({}) + projectsResp = self.backend.search_jira_projects(body={'innerFilters': [{'jiraCollabGUID': jiraCollaborationGUID}]}) assert projectsResp, "Jira projects response is empty" site = next((site for site in projectsResp['availableSites'] if site['name'] == 'cyberarmor-io'), None) assert site, "cyberarmor-io is missing from available sites" Logger.logger.info('get Jira System Tests project') - projectsResp = projectsResp = self.backend.search_jira_projects({'innerFilters': [{'siteId': site['id'], 'name': 'Jira System Tests'}]}) + projectsResp = projectsResp = self.backend.search_jira_projects({'innerFilters': [{'jiraCollabGUID': jiraCollaborationGUID, 'siteId': site['id'], 'name': 'Jira System Tests'}]}) assert projectsResp, "Jira projects response is empty" project = next((project for project in projectsResp['projects'] if project['name'] == 'Jira System Tests'), None) assert project, "Jira System Tests is missing from projects" @@ -83,18 +85,24 @@ def setup_jira_config(self): Logger.logger.info('verify Jira configuration') config = self.backend.get_jira_config() assert config, "Jira configuration is empty" - assert config['selectedSite']['name'] == 'cyberarmor-io', "Jira site is not cyberarmor-io" - assert config['projects'][0]['name'] == 'Jira System Tests', "Jira project is not Jira System Tests" + assert 'jiraConnections' in config and isinstance(config['jiraConnections'], list) and config['jiraConnections'], "No Jira connections found in the configuration" + connection = next( + (conn for conn in config['jiraConnections'] if conn.get('selectedSite', {}).get('name') == 'cyberarmor-io'), + None + ) + assert connection, "No Jira connection found for site 'cyberarmor-io'" + assert 'projects' in connection and isinstance(connection['projects'], list) and connection['projects'][0]['name'] == 'Jira System Tests', "Jira project is not Jira System Tests" + Logger.logger.info('get jira test issue type') - issueTypesRes = self.backend.search_jira_issue_types({'innerFilters': [{'siteId': site['id'], 'projectId': project['id'], 'name': 'System Test Issue Type'}]}) + issueTypesRes = self.backend.search_jira_issue_types({'innerFilters': [{'jiraCollabGUID': jiraCollaborationGUID, 'siteId': site['id'], 'projectId': project['id'], 'name': 'System Test Issue Type'}]}) assert issueTypesRes, "Jira issue types response is empty" issueType = next((issueType for issueType in issueTypesRes['response'] if issueType['name'] == 'System Test Issue Type'), None) assert issueType, "System Test Issue Type is missing from issue types" Logger.logger.info('verify issue type schema') - schema = self.backend.search_jira_schema({'innerFilters': [{ + schema = self.backend.search_jira_schema({'innerFilters': [{'jiraCollabGUID': jiraCollaborationGUID, 'siteId': site['id'], 'projectId': project['id'], 'issueTypeId': issueType['id'], 'includeFields': 'summary,description,reporter,labels,assignee,users,user'}]}) assert schema, "Jira schema response is empty" @@ -110,6 +118,7 @@ def setup_jira_config(self): self.project = project self.issueType = issueType + def setup_cluster_and_run_posture_scan(self): cluster, namespace = self.setup(apply_services=False) print("Debug: cluster: ", cluster) @@ -145,6 +154,7 @@ def create_jira_issue_for_posture(self): Logger.logger.info(f"Create Jira issue for resource {resourceHash} and control {controlId}") issue = self.test_obj["issueTemplate"].copy() + issue["collaborationGUID"] = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name) issue['siteId'] = self.site['id'] issue['projectId'] = self.project['id'] issue['issueTypeId'] = self.issueType['id'] @@ -188,6 +198,7 @@ def create_jira_issue_for_security_risks(self): Logger.logger.info(f"Create Jira issue for resource {resourceHash} and security_risk_id {security_risk_id}") issue = self.test_obj["issueTemplate"].copy() + issue["collaborationGUID"] = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name) issue['issueType'] = "securityIssue" issue['siteId'] = self.site['id'] issue['projectId'] = self.project['id'] @@ -278,6 +289,7 @@ def wait_for_vuln_results(self): def create_vuln_tickets(self): Logger.logger.info('create global ticket for CVE') issue = self.test_obj["issueTemplate"].copy() + issue["collaborationGUID"] = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name) issue['issueType'] = "vulnerability" issue['siteId'] = self.site['id'] issue['projectId'] = self.project['id'] @@ -288,6 +300,7 @@ def create_vuln_tickets(self): assert globalCVEicket, "Jira ticket is empty" Logger.logger.info('create ticket for workload CVE') + issue["collaborationGUID"] = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name) issue['owner'] = {"cluster": self.vulnWL['cluster'], "namespace": self.vulnWL['namespace'], "kind": self.vulnWL['kind'], "name": self.vulnWL['name']} issue['fields']['summary'] = f"Jira System Test CVE Issue for workload cluster:{self.cluster} namespace:{self.namespace} image:{self.vulnImage['repository']}" workloadCVEicket = self.backend.create_jira_issue(issue) @@ -298,6 +311,7 @@ def create_vuln_tickets(self): Logger.logger.info('create global ticket for image') del issue['owner'] + issue["collaborationGUID"] = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name) issue['issueType'] = "image" issue['subjects'] = [{"imageRepository": self.vulnImage['repository']}] issue['fields']['summary'] = f"Jira System Test global Issue image:{self.vulnImage['repository']}" @@ -305,6 +319,7 @@ def create_vuln_tickets(self): assert globalImageTicket, "Jira ticket is empty" Logger.logger.info('create ticket for image in workload') + issue["collaborationGUID"] = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name) issue['owner'] = {"cluster": self.vulnWL['cluster'], "namespace": self.vulnWL['namespace'], "kind": self.vulnWL['kind'], "name": self.vulnWL['name']} issue['fields']['summary'] = f"Jira System Test image Issue for workload cluster:{self.cluster} namespace:{self.namespace} image:{self.vulnImage['repository']}" workloadImageTicket = self.backend.create_jira_issue(issue) diff --git a/tests_scripts/workflows/jira_workflows.py b/tests_scripts/workflows/jira_workflows.py index 8f0fd1a9..f8ceb92d 100644 --- a/tests_scripts/workflows/jira_workflows.py +++ b/tests_scripts/workflows/jira_workflows.py @@ -1,13 +1,11 @@ from tests_scripts.workflows.workflows import Workflows from tests_scripts.workflows.utils import ( get_env, - NOTIFICATIONS_SVC_DELAY_FIRST_SCAN, EXPECTED_CREATE_RESPONSE, JIRA_PROVIDER_NAME, SECURITY_RISKS, SECURITY_RISKS_ID, VULNERABILITIES, - SEVERITIES_CRITICAL, SEVERITIES_HIGH, SEVERITIES_MEDIUM, VULNERABILITIES_WORKFLOW_NAME_JIRA, @@ -30,6 +28,7 @@ def __init__(self, test_obj=None, backend=None, kubernetes_obj=None, test_driver self.fw_name = None self.cluster = None self.wait_for_agg_to_end = False + self.site_name = "cyberarmor-io" def start(self): @@ -47,11 +46,13 @@ def start(self): assert self.backend is not None, f'the test {self.test_driver.test_name} must run with backend' self.cluster, self.namespace = self.setup(apply_services=False) + Logger.logger.info("Stage 1: Create new workflows") - workflow_body = self.build_securityRisk_workflow_body(name=SECURITY_RISKS_WORKFLOW_NAME_JIRA + self.cluster, severities=SEVERITIES_MEDIUM, jiraCollaborationGUID=get_env("JIRA_COLLABORATION_GUID"), siteId=get_env("JIRA_SITE_ID"), projectId=get_env("JIRA_PROJECT_ID"), cluster=self.cluster, namespace=self.namespace, category=SECURITY_RISKS, securityRiskIDs=SECURITY_RISKS_ID, issueTypeId=get_env("JIRA_ISSUE_TYPE_ID")) + jiraCollaborationGUID = self.backend.get_jira_collaboration_guid_by_site_name(self.site_name) + workflow_body = self.build_securityRisk_workflow_body(name=SECURITY_RISKS_WORKFLOW_NAME_JIRA + self.cluster, severities=SEVERITIES_MEDIUM, jiraCollaborationGUID=jiraCollaborationGUID, siteId=get_env("JIRA_SITE_ID"), projectId=get_env("JIRA_PROJECT_ID"), cluster=self.cluster, namespace=self.namespace, category=SECURITY_RISKS, securityRiskIDs=SECURITY_RISKS_ID, issueTypeId=get_env("JIRA_ISSUE_TYPE_ID")) self.create_and_assert_workflow(workflow_body, EXPECTED_CREATE_RESPONSE, update=False) - workflow_body = self.build_vulnerabilities_workflow_body(name=VULNERABILITIES_WORKFLOW_NAME_JIRA + self.cluster, severities=SEVERITIES_HIGH, jiraCollaborationGUID=get_env("JIRA_COLLABORATION_GUID"), siteId=get_env("JIRA_SITE_ID"), projectId=get_env("JIRA_PROJECT_ID"), cluster=self.cluster, namespace=self.namespace, category=VULNERABILITIES, cvss=6, issueTypeId=get_env("JIRA_ISSUE_TYPE_ID")) + workflow_body = self.build_vulnerabilities_workflow_body(name=VULNERABILITIES_WORKFLOW_NAME_JIRA + self.cluster, severities=SEVERITIES_HIGH, jiraCollaborationGUID=jiraCollaborationGUID, siteId=get_env("JIRA_SITE_ID"), projectId=get_env("JIRA_PROJECT_ID"), cluster=self.cluster, namespace=self.namespace, category=VULNERABILITIES, cvss=6, issueTypeId=get_env("JIRA_ISSUE_TYPE_ID")) self.create_and_assert_workflow(workflow_body, EXPECTED_CREATE_RESPONSE, update=False) before_test_message_ts = time.time() @@ -82,6 +83,7 @@ def cleanup(self, **kwargs): self.delete_and_assert_workflow(self.return_workflow_guid(VULNERABILITIES_WORKFLOW_NAME_JIRA + self.cluster)) return super().cleanup(**kwargs) + def assert_jira_tickets_was_created(self, begin_time, cluster_name, attempts=20, sleep_time=20): vuln_body = {