Skip to content

Commit 0c8a6ce

Browse files
committed
Add support for AlertConfig
Callers may provide an alertConfig object as part of either a synchronous plaintext scan, or an asynchronous file scan to fan alerts out to any of { slack, email, and webhook}.
1 parent d0b18d9 commit 0c8a6ce

File tree

2 files changed

+80
-2
lines changed

2 files changed

+80
-2
lines changed

nightfall/alerts.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from dataclasses import dataclass
2+
3+
from typing import List, Tuple, Optional
4+
5+
@dataclass
6+
class SlackAlert:
7+
"""SlackAlert contains the configuration required to allow clients to send asynchronous alerts to a Slack
8+
workspace when findings are detected. Note that in order for Slack alerts to be delivered to your workspace,
9+
you must use authenticate Nightfall to your Slack workspace under the Settings menu on the Nightfall Dashboard.
10+
11+
Currently, Nightfall supports delivering alerts to public channels, formatted like "#general".
12+
Alerts are only sent if findings are detected.
13+
Attributes:
14+
target (str): the channel name, formatted like "#general".
15+
"""
16+
target: str
17+
18+
def as_dict(self):
19+
return {"target": self.target}
20+
21+
@dataclass
22+
class EmailAlert:
23+
"""EmailAlert contains the configuration required to allow clients to send an asynchronous email message
24+
when findings are detected. The findings themselves will be delivered as a file attachment on the email.
25+
Alerts are only sent if findings are detected.
26+
Attributes:
27+
address (str): the email address to which alerts should be sent.
28+
"""
29+
address: str
30+
31+
def as_dict(self):
32+
return {"address": self.address}
33+
34+
@dataclass
35+
class WebhookAlert:
36+
"""WebhookAlert contains the configuration required to allow clients to send a webhook event to an
37+
external URL when findings are detected. The URL provided must (1) use the HTTPS scheme, (2) have a
38+
route defined on the HTTP POST method, and (3) return a 200 status code upon receipt of the event.
39+
40+
In contrast to other platforms, when using the file scanning APIs, an alert is also sent to this webhook
41+
*even when there are no findings*.
42+
Attributes:
43+
address (str): the URL to which alerts should be sent.
44+
"""
45+
address: str
46+
47+
def as_dict(self):
48+
return {"address": self.address}
49+
50+
@dataclass
51+
class AlertConfig:
52+
"""AlertConfig allows clients to specify where alerts should be delivered when findings are discovered as
53+
part of a scan. These alerts are delivered asynchronously to all destinations specified in the object instance.
54+
Attributes:
55+
slack (SlackAlert): Send alerts to a Slack workspace when findings are detected.
56+
email (EmailAlert): Send alerts to an email address when findings are detected.
57+
url (WebhookAlert): Send an HTTP webhook event to a URL when findings are detected.
58+
"""
59+
slack: Optional[SlackAlert] = None
60+
email: Optional[EmailAlert] = None
61+
url: Optional[WebhookAlert] = None
62+
63+
def as_dict(self):
64+
result = {}
65+
if self.slack:
66+
result["slack"] = {"target": self.slack.target}
67+
if self.email:
68+
result["email"] = {"address": self.email.address}
69+
if self.url:
70+
result["url"] = {"address": self.url.address}
71+
return result
72+

nightfall/api.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from requests.adapters import HTTPAdapter
1616
from urllib3 import Retry
1717

18+
from nightfall.alerts import AlertConfig
1819
from nightfall.detection_rules import DetectionRule, RedactionConfig
1920
from nightfall.exceptions import NightfallUserError, NightfallSystemError
2021
from nightfall.findings import Finding
@@ -57,7 +58,7 @@ def __init__(self, key: Optional[str] = None, signing_secret: Optional[str] = No
5758

5859
def scan_text(self, texts: List[str], policy_uuids: List[str] = None, detection_rules: Optional[List[DetectionRule]] = None,
5960
detection_rule_uuids: Optional[List[str]] = None, context_bytes: Optional[int] = None,
60-
default_redaction_config: Optional[RedactionConfig] = None) ->\
61+
default_redaction_config: Optional[RedactionConfig] = None, alert_config: Optional[AlertConfig] = None) ->\
6162
Tuple[List[List[Finding]], List[str]]:
6263
"""Scan text with Nightfall.
6364
@@ -83,6 +84,8 @@ def scan_text(self, texts: List[str], policy_uuids: List[str] = None, detection_
8384
:param default_redaction_config: The default redaction configuration to apply to all detection rules, unless
8485
there is a more specific config within a detector.
8586
:type default_redaction_config: RedactionConfig or None
87+
:param alert_config: Configures external destinations to fan out alerts to in the event that findings are detected.
88+
:type alert_config: AlertConfig or None
8689
:returns: list of findings, list of redacted input texts
8790
"""
8891

@@ -132,7 +135,8 @@ def _scan_text_v3(self, data: dict):
132135
def scan_file(self, location: str, webhook_url: Optional[str] = None, policy_uuid: Optional[str] = None,
133136
detection_rules: Optional[List[DetectionRule]] = None,
134137
detection_rule_uuids: Optional[List[str]] = None,
135-
request_metadata: Optional[str] = None) -> Tuple[str, str]:
138+
request_metadata: Optional[str] = None,
139+
alert_config: Optional[AlertConfig] = None) -> Tuple[str, str]:
136140
"""Scan file with Nightfall.
137141
At least one of policy_uuid, detection_rule_uuids or detection_rules is required.
138142
@@ -146,6 +150,8 @@ def scan_file(self, location: str, webhook_url: Optional[str] = None, policy_uui
146150
:type detection_rule_uuids: List[str] or None
147151
:param request_metadata: additional metadata that will be returned with the webhook response
148152
:type request_metadata: str or None
153+
:param alert_config: Configures external destinations to fan out alerts to in the event that findings are detected.
154+
:type alert_config: AlertConfig or None
149155
:returns: (scan_id, message)
150156
"""
151157

0 commit comments

Comments
 (0)