DependencyTrack / dependency-track

Dependency-Track is an intelligent Component Analysis platform that allows organizations to identify and reduce risk in the software supply chain.
https://dependencytrack.org/
Apache License 2.0
2.69k stars 578 forks source link

Allow PUT /v1/notification/rule to supply notifyOn and publisherConfig parameters #2940

Open schlenk opened 1 year ago

schlenk commented 1 year ago

Current Behavior

The PUT call on /v1/notification/rule seems to be unable to use any supplied providerConfig or notifyOn values. A second POST call is needed to add those properties after the rule is created with a PUT.

I do not get a HTTP 400 Bad Request, when i try to include providerConfig or notifyOn in the PUT request, those are silently ignored and do not show up in the result.

The only hint at this strange behaviour is the documentation for Notifications, which states:

Once the alert is created it can be configured. Start with selecting from the list of available notification groups to notify on.

This looks like a hint about the UI flow, but actually describes the backend API behaviour, which is surprising.

This python code demonstrates the behaviour, the first PUT fails to set the notifyOn and providerConfig values.


import json
import pprint
import sys
import uuid

from urllib.parse import urljoin

import requests

DEPTRACK = 'https://deptrack.example.org'

def get_auth_header():
    return {'X-Api-Key': 'verysecret' }

def add_email_channel(project, addresses, publisher, groups):
    url = urljoin(DEPTRACK, '/api/v1/notification/rule')

    emails = ",".join(addresses)
    publisher_config = json.dumps({'destination': emails})
    rule_name = '%s_Email' % project
    rule_id = str(uuid.uuid4())

    req = {
        'name': rule_name,
        'enabled': True,
        'notifyChildren': True,
        'scope': 'PORTFOLIO',
        'notification_level': 'INFORMATIONAL',
        'notifyOn': groups,
        'publisher': publisher,
        'publisherConfig': publisher_config
        'uuid': rule_id,
    }

    headers = get_auth_header()
    headers['Content-Type'] = 'application/json'
    resp = requests.put(url, headers=get_auth_header(), json=req)
    resp.raise_for_status()
    result = resp.json()
    print("Created Rule via PUT")
    print(result)

    result['publisherConfig'] = publisher_config
    result['notifyOn'] = groups
    resp = requests.post(url, headers=get_auth_header(), json=result)
    resp.raise_for_status()
    result = resp.json()
    print("Updated Rule via POST")
    print(result)
    return result['uuid']

class Publishers(object):

    def __init__(self):
        self.url = urljoin(DEPTRACK, "/api/v1/notification/publisher")
        self.load()

    def load(self):
        self.available = self.find_available_publishers()

    def get_publisher(self, name):
        return self.available[name]

    def find_available_publishers(self):
        resp = requests.get(self.url, headers=get_auth_header())
        resp.raise_for_status()
        data = resp.json()
        publishers = {}
        for pub in data:
            publishers[pub['name']] = pub
        return publishers

def find_notification_rules():
    url = urljoin(DEPTRACK, '/api/v1/notification/rule')
    resp = requests.get(url, headers=get_auth_header())
    resp.raise_for_status()
    data = resp.json()
    pprint.pprint(data)
    return data

def main():
    pubs = Publishers()
    email = pubs.get_publisher('Email')
    add_email_channel('example', ['user@example.org'], email, groups=['NEW_VULNERABILITY'])
    find_notification_rules()

if __name__ == '__main__':
    main()

Proposed Behavior

The PUT call should accept AND process all parameters of the provided NotificationRule. It should not silently ignore parameters given in the NotificationRule object.

This should at least work for:

which are always necessary for a useful NotificationRule.

Checklist

jovanz-getbgd commented 1 year ago

It seems to me like the same is true for the projects parameter, perhaps this should be added to this issue as well.