Skip to content

Commit 2e1ee9f

Browse files
author
Dan Hertz
committed
Add enums
1 parent 7b270cf commit 2e1ee9f

File tree

3 files changed

+46
-22
lines changed

3 files changed

+46
-22
lines changed

nightfall/detection_rules.py

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from enum import Enum
2+
13
from nightfall.exceptions import NightfallUserError
24

35

@@ -33,12 +35,21 @@ def as_dict(self):
3335
return {"wordList": self.word_list, "isCaseSensitive": self.is_case_sensitive}
3436

3537

38+
class Confidence(Enum):
39+
"""Confidence describes the certainty that a piece of content matches a detector."""
40+
VERY_UNLIKELY = "VERY_UNLIKELY"
41+
UNLIKELY = "UNLIKELY"
42+
POSSIBLE = "POSSIBLE"
43+
LIKELY = "LIKELY"
44+
VERY_LIKELY = "VERY_LIKELY"
45+
46+
3647
class ContextRule:
3748
"""An object that describes how a regular expression may be used to adjust the confidence of a candidate finding.
3849
This context rule will be applied within the provided byte proximity, and if the regular expression matches, then
3950
the confidence associated with the finding will be adjusted to the value prescribed.
4051
"""
41-
def __init__(self, regex: Regex, window_before: int, window_after: int, fixed_confidence: str):
52+
def __init__(self, regex: Regex, window_before: int, window_after: int, fixed_confidence: Confidence):
4253
"""Instantiate a ContextRule object
4354
:param regex: The regular expression configuration to run within the context of a candidate finding.
4455
:type regex: Regex
@@ -47,8 +58,7 @@ def __init__(self, regex: Regex, window_before: int, window_after: int, fixed_co
4758
:param window_after: The number of trailing characters to consider as context.
4859
:type window_after: int
4960
:param fixed_confidence: How to adjust the result of the match if the context rule matches.
50-
One of "VERY_UNLIKELY", "UNLIKELY", "POSSIBLE", "LIKELY", "VERY_LIKELY".
51-
:type fixed_confidence: str
61+
:type fixed_confidence: Confidence
5262
"""
5363
self.regex = regex
5464
self.window_before = window_before
@@ -59,7 +69,7 @@ def as_dict(self):
5969
return {
6070
"regex": self.regex,
6171
"proximity": {"windowBefore": self.window_before, "windowAfter": self.window_after},
62-
"confidenceAdjustment": {"fixedConfidence": self.fixed_confidence}
72+
"confidenceAdjustment": {"fixedConfidence": self.fixed_confidence.value}
6373
}
6474

6575

@@ -187,7 +197,7 @@ class Detector:
187197
"""
188198
def __init__(
189199
self,
190-
min_confidence: str,
200+
min_confidence: Confidence,
191201
min_num_findings: int,
192202
nightfall_detector: str = None,
193203
regex: Regex = None,
@@ -202,7 +212,7 @@ def __init__(
202212
One of nightfall_detector, regex, word_list or uuid required.
203213
204214
:param min_confidence: The minimum confidence threshold for the detector trigger a finding.
205-
:type min_confidence: str
215+
:type min_confidence: Confidence
206216
:param min_num_findings: The minimum number of occurrences of the detector required to trigger a finding.
207217
:type min_num_findings: int
208218
:param nightfall_detector: Create an instance of a detector based on a pre-built Nightfall detector.
@@ -238,7 +248,7 @@ def __init__(
238248
self.redaction_config = redaction_config
239249

240250
def as_dict(self):
241-
result = {"minConfidence": self.min_confidence, "minNumFindings": self.min_num_findings}
251+
result = {"minConfidence": self.min_confidence.value, "minNumFindings": self.min_num_findings}
242252
if self.nightfall_detector:
243253
result["nightfallDetector"] = self.nightfall_detector
244254
result["detectorType"] = "NIGHTFALL_DETECTOR"
@@ -261,20 +271,31 @@ def as_dict(self):
261271
return result
262272

263273

274+
class LogicalOp(Enum):
275+
""" A modifier that is used to decide when a finding should be surfaced in the context of a detection rule.
276+
- When ALL is specified, all detectors in a detection rule must trigger a match in order for the finding to be
277+
reported. This is the equivalent of a logical "AND" operator.
278+
- When ANY is specified, only one of the detectors in a detection rule must trigger a match in order for the finding
279+
to be reported. This is the equivalent of a logical "OR" operator.
280+
"""
281+
ANY = "ANY"
282+
ALL = "ALL"
283+
284+
264285
class DetectionRule:
265286
"""An object that contains a set of detectors to be used when scanning content."""
266-
def __init__(self, detectors: list[Detector], logical_op: str = "ANY"):
287+
def __init__(self, detectors: list[Detector], logical_op: LogicalOp = LogicalOp.ANY):
267288
"""Instantiate a DetectionRule
268289
:param detectors: A list of Detectors to scan content with.
269290
:type detectors: list[Detector]
270291
:param logical_op: The method for combining the detectors. One of:
271-
- "ANY" (logical or, i.e. a finding is emitted only if any of the provided detectors match)
272-
- "ALL" (logical and, i.e. a finding is emitted only if all provided detectors match)
273-
:type logical_op: str
292+
- LogicalOp.ANY (logical or, i.e. a finding is emitted only if any of the provided detectors match)
293+
- LogicalOp.ALL (logical and, i.e. a finding is emitted only if all provided detectors match)
294+
:type logical_op: LogicalOp
274295
"""
275296
self.detectors = detectors
276297
self.logical_op = logical_op
277298

278299
def as_dict(self):
279-
return {"detectors": [d.as_dict() for d in self.detectors], "logicalOp": self.logical_op}
300+
return {"detectors": [d.as_dict() for d in self.detectors], "logicalOp": self.logical_op.value}
280301

nightfall/findings.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
from nightfall.detection_rules import Confidence
2+
3+
14
class Range:
25
"""An object representing where a finding was discovered in content."""
36
def __init__(self, start: int, end: int):
@@ -20,7 +23,7 @@ def __init__(self,
2023
after_context: str,
2124
detector_name: str,
2225
detector_uuid: str,
23-
confidence: str,
26+
confidence: Confidence,
2427
byte_range: Range,
2528
codepoint_range: Range,
2629
matched_detection_rule_uuids: list[str],
@@ -40,7 +43,7 @@ def __init__(self,
4043
:param detector_uuid: The ID that uniquely identifies this detector.
4144
:type detector_uuid: str
4245
:param confidence: The confidence that the data contained in Finding is an instance of the matched detector.
43-
:type confidence: str
46+
:type confidence: Confidence
4447
:param byte_range: The byte range in which a finding was detected within the item.
4548
:type byte_range: Range
4649
:param codepoint_range: The codepoint range in which a finding was detected within the item. This differs
@@ -74,7 +77,7 @@ def from_dict(cls, resp: dict) -> "Finding":
7477
resp.get("afterContext"),
7578
resp["detector"].get("name"),
7679
resp["detector"].get("uuid"),
77-
resp["confidence"],
80+
Confidence[resp["confidence"]],
7881
Range(resp["location"]["byteRange"]["start"], resp["location"]["byteRange"]["end"]),
7982
Range(resp["location"]["codepointRange"]["start"], resp["location"]["codepointRange"]["end"]),
8083
resp["matchedDetectionRuleUUIDs"],

tests/test_api.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import pytest
33

44
from nightfall.api import Nightfall
5-
from nightfall.detection_rules import DetectionRule, Detector
5+
from nightfall.detection_rules import DetectionRule, Detector, LogicalOp, Confidence
66

77

88
@pytest.fixture
@@ -13,9 +13,9 @@ def nightfall():
1313
def test_scan_text_detection_rules_v3(nightfall):
1414
result, _ = nightfall.scan_text(
1515
["4916-6734-7572-5015 is my credit card number"],
16-
detection_rules=[DetectionRule([Detector(min_confidence="LIKELY", min_num_findings=1,
17-
display_name="Credit Card Number",
18-
nightfall_detector="CREDIT_CARD_NUMBER")])]
16+
detection_rules=[DetectionRule(logical_op=LogicalOp.ANY, detectors=[
17+
Detector(min_confidence=Confidence.LIKELY, min_num_findings=1,
18+
display_name="Credit Card Number", nightfall_detector="CREDIT_CARD_NUMBER")])]
1919
)
2020

2121
assert len(result) == 1
@@ -30,9 +30,9 @@ def test_scan_file_detection_rules(nightfall):
3030
id, message = nightfall.scan_file(
3131
file,
3232
os.environ['WEBHOOK_ENDPOINT'],
33-
detection_rules=[DetectionRule([Detector(min_confidence="LIKELY", min_num_findings=1,
34-
display_name="Credit Card Number",
35-
nightfall_detector="CREDIT_CARD_NUMBER")])]
33+
detection_rules=[DetectionRule(logical_op=LogicalOp.ANY, detectors=[
34+
Detector(min_confidence=Confidence.LIKELY, min_num_findings=1,
35+
display_name="Credit Card Number", nightfall_detector="CREDIT_CARD_NUMBER")])]
3636
)
3737

3838
assert id is not None

0 commit comments

Comments
 (0)