Skip to content

Commit 54ed31e

Browse files
authored
Add policyUUIDs to request struct, plus fix deserialization bug (#42)
1. Migrate from deprecated config field to policy in text scan requests 2. Add policyUUIDs field to text scan request struct. Current maximum supported length is 1, support for more coming in the future. 3. Fix bug with Jackson ObjectMapper -- we should be ignoring unrecognized fields.
1 parent e1a79b9 commit 54ed31e

File tree

8 files changed

+97
-15
lines changed

8 files changed

+97
-15
lines changed

src/main/java/ai/nightfall/scan/NightfallClient.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import ai.nightfall.scan.model.ScanTextResponse;
1515
import ai.nightfall.scan.model.UploadFileChunkRequest;
1616
import com.fasterxml.jackson.core.JsonProcessingException;
17+
import com.fasterxml.jackson.databind.DeserializationFeature;
1718
import com.fasterxml.jackson.databind.ObjectMapper;
1819
import okhttp3.Call;
1920
import okhttp3.ConnectionPool;
@@ -43,7 +44,8 @@
4344
*/
4445
public class NightfallClient implements Closeable {
4546

46-
private static final ObjectMapper objectMapper = new ObjectMapper();
47+
private static final ObjectMapper objectMapper = new ObjectMapper()
48+
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
4749
private static final long wakeupDurationMillis = Duration.ofSeconds(15).toMillis();
4850
private static final int DEFAULT_RETRY_COUNT = 5;
4951
private static final String API_HOST = "https://api.nightfall.ai";

src/main/java/ai/nightfall/scan/model/DetectorMetadata.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package ai.nightfall.scan.model;
22

3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
34
import com.fasterxml.jackson.annotation.JsonProperty;
45

56
import java.util.UUID;
@@ -8,6 +9,7 @@
89
* A container for minimal information representing a detector. A detector may be uniquely identified by its UUID;
910
* the name field helps provide human-readability.
1011
*/
12+
@JsonIgnoreProperties(ignoreUnknown = true)
1113
public class DetectorMetadata {
1214

1315
@JsonProperty("name")

src/main/java/ai/nightfall/scan/model/Finding.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package ai.nightfall.scan.model;
22

3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
34
import com.fasterxml.jackson.annotation.JsonProperty;
45

56
import java.util.List;
@@ -8,6 +9,7 @@
89
/**
910
* An object representing an occurrence of a configured detector (i.e. finding) in the provided data.
1011
*/
12+
@JsonIgnoreProperties(ignoreUnknown = true)
1113
public class Finding {
1214
@JsonProperty("finding")
1315
private String finding;

src/main/java/ai/nightfall/scan/model/Location.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package ai.nightfall.scan.model;
22

3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
34
import com.fasterxml.jackson.annotation.JsonProperty;
45

56
/**
67
* An object representing where a finding was discovered in content.
78
*/
9+
@JsonIgnoreProperties(ignoreUnknown = true)
810
public class Location {
911

1012
@JsonProperty("byteRange")

src/main/java/ai/nightfall/scan/model/ScanFileResponse.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package ai.nightfall.scan.model;
22

3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
34
import com.fasterxml.jackson.annotation.JsonProperty;
45

56
import java.util.UUID;
67

78
/**
89
* The object returned by the Nightfall API when an (asynchronous) file scan request was successfully triggered.
910
*/
11+
@JsonIgnoreProperties(ignoreUnknown = true)
1012
public class ScanFileResponse {
1113

1214
@JsonProperty("id")

src/main/java/ai/nightfall/scan/model/ScanTextRequest.java

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.fasterxml.jackson.annotation.JsonProperty;
44

55
import java.util.List;
6+
import java.util.UUID;
67

78
/**
89
* An object representing a request to scan inline plaintext with the Nightfall API.
@@ -11,19 +12,34 @@ public class ScanTextRequest {
1112
@JsonProperty("payload")
1213
private List<String> payload;
1314

14-
@JsonProperty("config")
15-
private ScanTextConfig config;
15+
@JsonProperty("policy")
16+
private ScanTextConfig policy;
17+
18+
@JsonProperty("policyUUIDs")
19+
private List<UUID> policyUUIDs;
1620

1721
/**
1822
* Create a request to scan the provided <code>payload</code> against the provided scanning
19-
* configuration <code>config</code>.
23+
* <code>policy</code>.
24+
*
25+
* @param payload the content to scan
26+
* @param policy the configuration to use to scan the content
27+
*/
28+
public ScanTextRequest(List<String> payload, ScanTextConfig policy) {
29+
this.payload = payload;
30+
this.policy = policy;
31+
}
32+
33+
/**
34+
* Create a request to scan the provided <code>payload</code> against the provided
35+
* <code>policyUUIDs</code>.
2036
*
2137
* @param payload the content to scan
22-
* @param config the configuration to use to scan the content
38+
* @param policyUUIDs a list of UUIDs referring to pre-created policies to-be-used when scanning. Maximum 1.
2339
*/
24-
public ScanTextRequest(List<String> payload, ScanTextConfig config) {
40+
public ScanTextRequest(List<String> payload, List<UUID> policyUUIDs) {
2541
this.payload = payload;
26-
this.config = config;
42+
this.policyUUIDs = policyUUIDs;
2743
}
2844

2945
/**
@@ -45,20 +61,56 @@ public void setPayload(List<String> payload) {
4561
}
4662

4763
/**
48-
* Get the request scan configuration.
64+
* Get the request scan policy. Same as <code>getPolicy</code>, just provided for backwards compatibility.
4965
*
5066
* @return the configuration to use to scan the <code>payload</code> data
5167
*/
5268
public ScanTextConfig getConfig() {
53-
return config;
69+
return getPolicy();
5470
}
5571

5672
/**
57-
* Set the request scan configuration.
73+
* Get the request scan policy.
74+
*
75+
* @return the configuration to use to scan the <code>payload</code> data
76+
*/
77+
public ScanTextConfig getPolicy() {
78+
return policy;
79+
}
80+
81+
/**
82+
* Set the request scan policy. Same as <code>setPolicy</code>, just provided for backwards compatibility.
5883
*
5984
* @param config the configuration to use to scan the <code>payload</code> data
6085
*/
6186
public void setConfig(ScanTextConfig config) {
62-
this.config = config;
87+
setPolicy(config);
88+
}
89+
90+
/**
91+
* Set the request scan policy.
92+
*
93+
* @param policy the configuration to use to scan the <code>payload</code> data
94+
*/
95+
public void setPolicy(ScanTextConfig policy) {
96+
this.policy = policy;
97+
}
98+
99+
/**
100+
* Get the policy UUIDs to use when performing a scan.
101+
*
102+
* @return the policy UUIDs.
103+
*/
104+
public List<UUID> getPolicyUUIDs() {
105+
return policyUUIDs;
106+
}
107+
108+
/**
109+
* Set the policy UUIDs to use when performing a scan.
110+
*
111+
* @param policyUUIDs the policy UUIDs.
112+
*/
113+
public void setPolicyUUIDs(List<UUID> policyUUIDs) {
114+
this.policyUUIDs = policyUUIDs;
63115
}
64116
}

src/main/java/ai/nightfall/scan/model/ScanTextResponse.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package ai.nightfall.scan.model;
22

3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
34
import com.fasterxml.jackson.annotation.JsonProperty;
45

56
import java.util.List;
@@ -9,6 +10,7 @@
910
* corresponds one-to-one with the input request <code>payload</code>, so all findings stored in a given sub-list
1011
* refer to matches that occurred in the <code>i</code>th index of the request payload.
1112
*/
13+
@JsonIgnoreProperties(ignoreUnknown = true)
1214
public class ScanTextResponse {
1315
@JsonProperty("findings")
1416
private List<List<Finding>> findings;

src/test/java/ai/nightfall/scan/NightfallClientTest.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,24 @@ public void testScanText_HappyPath() {
5858
}
5959
}
6060

61+
@Test
62+
public void testScanText_IgnoresUnrecognizedProperties() {
63+
try (MockWebServer server = new MockWebServer()) {
64+
// deserializer should not throw an exception just because of the unrecognized key `foo`
65+
server.enqueue(new MockResponse().setBody("{\"findings\": [[]], \"foo\": \"bar\"}"));
66+
67+
List<List<Finding>> expectedFindings = Arrays.asList(Collections.emptyList());
68+
NightfallClient c = new NightfallClient(getRequestURL(server), "key", 1, getHttpClient());
69+
RedactionConfig defRedCfg = new RedactionConfig(new SubstitutionConfig("REDACTED"));
70+
ScanTextConfig cfg = new ScanTextConfig(Arrays.asList(UUID.fromString("c08c6c43-85ca-40e5-8f46-7d1cf1e176a3")), Collections.emptyList(), 20, defRedCfg);
71+
ScanTextRequest req = new ScanTextRequest(null, cfg);
72+
ScanTextResponse resp = c.scanText(req);
73+
assertEquals(expectedFindings, resp.getFindings());
74+
} catch (IOException e) {
75+
fail("IOException during test: " + e.getMessage());
76+
}
77+
}
78+
6179
@Test
6280
public void testScanText_NullRequestArg() {
6381
assertThrows(IllegalArgumentException.class, () -> {
@@ -80,7 +98,7 @@ public MockResponse dispatch(@NotNull RecordedRequest r) {
8098
});
8199

82100
NightfallClient c = new NightfallClient(getRequestURL(server), "key", 1, getHttpClient());
83-
ScanTextRequest req = new ScanTextRequest(null, null);
101+
ScanTextRequest req = new ScanTextRequest(null, (ScanTextConfig) null);
84102
c.scanText(req);
85103
fail("did not expect scanText to succeed");
86104
} catch (IOException e) {
@@ -109,7 +127,7 @@ public MockResponse dispatch(@NotNull RecordedRequest r) {
109127

110128
List<List<Finding>> expectedFindings = Arrays.asList(Arrays.asList());
111129
NightfallClient c = new NightfallClient(getRequestURL(server), "key", 1, getHttpClient());
112-
ScanTextRequest req = new ScanTextRequest(null, null);
130+
ScanTextRequest req = new ScanTextRequest(null, (ScanTextConfig) null);
113131
ScanTextResponse resp = c.scanText(req);
114132
assertEquals(expectedFindings, resp.getFindings());
115133
assertEquals(reqCount[0], 3); // validate that rate limit responses were actually returned
@@ -135,7 +153,7 @@ public void testScanText_InternalException() {
135153
.build().url().toString();
136154

137155
NightfallClient c = new NightfallClient(serverURL, "key", 1, getHttpClient());
138-
ScanTextRequest req = new ScanTextRequest(null, null);
156+
ScanTextRequest req = new ScanTextRequest(null, (ScanTextConfig) null);
139157
c.scanText(req);
140158
fail("did not expect scanText to succeed");
141159
} catch (IOException e) {
@@ -173,7 +191,7 @@ public MockResponse dispatch(@NotNull RecordedRequest r) {
173191
.build().url().toString();
174192

175193
NightfallClient c = new NightfallClient(serverURL, "key", 1, getHttpClient());
176-
ScanTextRequest req = new ScanTextRequest(null, null);
194+
ScanTextRequest req = new ScanTextRequest(null, (ScanTextConfig) null);
177195
c.scanText(req);
178196
fail("did not expect scanText to succeed");
179197
} catch (IOException e) {

0 commit comments

Comments
 (0)