jira integration does not work

34 views
Skip to first unread message

Jaime

unread,
Nov 12, 2025, 3:43:29 AM (11 days ago) Nov 12
to Wazuh | Mailing List
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

The thing is when I execute it manually it works. I have it deployed on docker single node

The servers integration config block on ossec.conf:
```
<integration>
    <name>custom-jira</name>
    <hook_url>https://myorg.atlassian.net/rest/api/3/issue</hook_url>
    <api_key>user:api_key</api_key>
    <alert_format>json</alert_format>    <rule_id>19001,19002,19003,19004,19005,19007,19008,19009,19010,19011,19013,19014</rule_id>
    <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)
```

Stuti Gupta

unread,
Nov 12, 2025, 5:08:05 AM (11 days ago) Nov 12
to Wazuh | Mailing List
Hi @Jaime

Can you please check the ownership and permission of the file, the output should be:
-rwxr-x--- 1 root wazuh

Please make sure to follow these to edit ossec.conf
1. Stop the containers 
docker compose down
2. Edit the file on the host: wazuh-docker/single-node/config/wazuh_cluster/wazuh_manager.conf
3. Bring everything back up:
docker compose up -d

If issue stil is there the please share teh
Please share the manager logs and integration logs,located at:/
var/ossec/logs 

Jaime

unread,
Nov 14, 2025, 5:59:58 AM (9 days ago) Nov 14
to Wazuh | Mailing List
bash-5.2# ls -lh /var/ossec/integrations/ | grep jira
-rwxr-x--- 1 root wazuh 3.3K Nov 11 08:15 custom-jira
-rw-r--r-- 1 root root     0 Oct 30 10:35 custom-jira.py

Jaime

unread,
Nov 14, 2025, 6:03:51 AM (9 days ago) Nov 14
to Wazuh | Mailing List
The /var/ossec/logs/integration.log logfile it's empty

but on ossec.log I see this:

2025/11/14 08:21:02 wazuh-integratord: ERROR: Unable to run integration for custom-jira -> integrations
2025/11/14 08:21:02 wazuh-integratord: ERROR: While running custom-jira -> integrations. Output: json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
 
2025/11/14 08:21:02 wazuh-integratord: ERROR: Exit status was: 1
2025/11/14 08:22:05 wazuh-integratord: ERROR: Unable to run integration for custom-jira -> integrations
2025/11/14 08:22:05 wazuh-integratord: ERROR: While running custom-jira -> integrations. Output: json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
 

Stuti Gupta

unread,
Nov 20, 2025, 6:56:20 AM (3 days ago) Nov 20
to Wazuh | Mailing List
Hi Jaine

The incorrect API key or URL can cause this exact error. If the Jira request returns an empty body or anything that is not valid JSON, the script will fail with “JSONDecodeError: Expecting value: line 1 column 1 (char 0)”. This happens because the script tries to decode the response as JSON, but Jira is not returning JSON when the credentials or the endpoint are wrong. Please verify that the API key, user format, and Jira URL are correct and that the request returns valid JSON.  

To know more about the error, you can refer to https://www.techstaunch.com/blogs/json-decoder-jsondecodeerror-expecting-value-line-1-column-1-char-0-how-to-solve

Also, I'm assuming this is a typo error 

<alert_format>json</alert_format>    <rule_id>19001,19002,19003,19004,19005,19007,19008,19009,19010,19011,19013,19014</rule_id>
If not, then please correct this as well, like 

<alert_format>json</alert_format>   
<rule_id>19001,19002,19003,19004,19005,19007,19008,19009,19010,19011,19013,19014</rule_id>

Additionally, you can also refer to this blog related to Jira integration https://wazuh.com/blog/how-to-integrate-external-software-using-integrator/

Jaime

unread,
Nov 21, 2025, 6:33:23 AM (2 days ago) Nov 21
to Wazuh | Mailing List

I managed to correct the script it works just fine now thanks

```

```
Reply all
Reply to author
Forward
0 new messages