Hi, I was looking to the docs for modifying the jira integration and I have a problem. The script works, but it does not activate when alerts come to the wazuh server. This morning I recived some alerts 19001, 19002, 19003 and 19004 but the integration didn't trigger
<options>{"jira":{"project": "project","issuetype": "Task","component": "Compliance", "title": "The server
agent.name complies data.sca.score%","description": "The server
agent.name does not comply with the minimum requirements for policy data.sca.policy, fix failed checks as soon as possible"}}</options>
</integration>
```
and this is the script:
```
#!/usr/bin/env python3
import os
import sys
import json
import re
import requests
from requests.auth import HTTPBasicAuth
# ------------------------
# Auxiliar functions
# ------------------------
def resolve_field_path(data, path):
"""Navigate a nested dict using a path with dots (p.ex. data.sca.score)."""
keys = path.split('.')
for key in keys:
if isinstance(data, dict) and key in data:
data = data[key]
else:
return f"<{path}>" # If it does not exist, leaves a amark
return str(data)
def replace_placeholders(text, data):
"""Replaces fields like
agent.name o data.sca.policy with its real value."""
pattern = r'\b[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)+\b'
return re.sub(pattern, lambda m: resolve_field_path(data, m.group(0)), text)
# ------------------------
# Parameter lecture
# ------------------------
alert_file = open(sys.argv[1])
user, api_key = sys.argv[2].split(':', 1)
hook_url = sys.argv[3]
options = json.loads(sys.argv[4])
# ------------------------
# Alert reading
# ------------------------
alert_json = json.loads(alert_file.read())
alert_file.close()
# ------------------------
# relevant fields
# ------------------------
# This will be resolved with the previous functions
agent_name = alert_json['agent']['name']
# ------------------------
# Jira config and placeholders
# ------------------------
project_key = options['jira']['project']
issue_type_name = options['jira']['issuetype']
component = options['jira']['component']
jira_title_text = options['jira']['title']
jira_desc_text = options['jira']['description']
# dynamic sustitution
jira_title_text = replace_placeholders(jira_title_text, alert_json)
jira_desc_text = replace_placeholders(jira_desc_text, alert_json)
# ------------------------
# ticket building
# ------------------------
headers = {'content-type': 'application/json'}
issue_data = {
"update": {},
"fields": {
"project": {
"key": project_key
},
"issuetype": {
"name": issue_type_name
},
"summary": f"[{component}]: {jira_title_text}",
"description": {
"type": "doc",
"version": 1,
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": jira_desc_text
}
]
}
]
}
}
}
# ------------------------
# verify if there's an already open ticket
# ------------------------
search_url = "
https://myorg.atlassian.net/rest/api/3/search"
jql_query = (
f'project = "{project_key}" '
f'AND summary ~ "{agent_name}" '
'AND status IN ("To Do", "In Progress")'
)
params = {"jql": jql_query}
response = requests.get(search_url, headers=headers, params=params, auth=(user, api_key))
data = response.json()
# ------------------------
# Create ticket if it does not exist
# ------------------------
if not data.get("issues"):
response =
requests.post(hook_url, json=issue_data, headers=headers, auth=(user, api_key))
if response.status_code not in (200, 201):
print(f"Error creando ticket: {response.status_code} - {response.text}", file=sys.stderr)
else:
print(f"Ticket generado con éxito: {response.json()['key']}")
sys.exit(0)
```