-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathSimpleCodaClientTest.java
More file actions
332 lines (281 loc) · 10.1 KB
/
SimpleCodaClientTest.java
File metadata and controls
332 lines (281 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
/*
* Copyright (c) 2022, iland Internet Solutions, Corp
*
* This software is licensed under the Terms and Conditions contained within the
* "LICENSE.txt" file that accompanied this software. Any inquiries concerning
* the scope or enforceability of the license should be addressed to:
*
* iland Internet Solutions, Corp
* 1235 North Loop West, Suite 800
* Houston, TX 77008
* USA
*
* http://www.iland.com
*/
package com.iland.coda.footprint;
import static com.iland.coda.footprint.TestValues.TEST_DESCRIPTION;
import static com.iland.coda.footprint.TestValues.TEST_LABEL;
import static org.junit.jupiter.api.Assertions.*;
import java.io.File;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import net.codacloud.ApiException;
import net.codacloud.model.Account;
import net.codacloud.model.AdminUser;
import net.codacloud.model.AgentlessScannerSrz;
import net.codacloud.model.CVR;
import net.codacloud.model.CVRMostVulnServer;
import net.codacloud.model.CVRVulnerability;
import net.codacloud.model.RegistrationLight;
import net.codacloud.model.ScanStatus;
import net.codacloud.model.ScanSurfaceEntry;
import net.codacloud.model.ScanUuidScannerId;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class SimpleCodaClientTest {
private static final Logger logger =
LoggerFactory.getLogger(SimpleCodaClientTest.class);
private static CodaClient client;
@BeforeAll
static void createClient() throws ApiException {
client = Clients.simpleCodaClient.login();
Clients.deleteTestRegistrations(client);
}
@AfterAll
static void afterAll() throws ApiException {
Clients.deleteTestRegistrations(client);
}
@Test
void testThatRegistrationsAreNotDuplicated() throws Throwable {
final RegistrationLight registrationA =
client.findOrCreateRegistration(TEST_LABEL, TEST_DESCRIPTION);
final RegistrationLight registrationB =
client.findOrCreateRegistration(TEST_LABEL, TEST_DESCRIPTION);
assertEquals(registrationA.getId(), registrationB.getId(),
"registration was duplicated");
}
@Test
void testGetDefaultCloudScanner() throws ApiException {
final RegistrationLight registration =
client.createRegistration(TEST_LABEL, TEST_DESCRIPTION);
final Integer accountId = client.registrationToAccountId(registration);
final AgentlessScannerSrz defaultCloudScanner =
client.getDefaultCloudScanner(accountId);
assertNotNull(defaultCloudScanner,
"defaultCloudScanner must not be null");
}
@Test
void testGetScannerIdByLabel() throws ApiException {
final RegistrationLight registration =
client.createRegistration(TEST_LABEL, TEST_DESCRIPTION);
final Integer accountId = client.registrationToAccountId(registration);
final Map<String, Integer> scannerIdByLabel =
client.getScannerIdByLabel(accountId);
assertFalse(scannerIdByLabel.isEmpty(), "scannerIdByLabel is empty");
}
@Test
void testLabelToAccountId() throws ApiException {
final RegistrationLight registration =
client.createRegistration(TEST_LABEL, TEST_DESCRIPTION);
final Integer expectedAccountId =
client.registrationToAccountId(registration);
final Integer actualAccountId = client.labelToAccountId(TEST_LABEL);
assertEquals(expectedAccountId, actualAccountId,
"accountId must not be null");
}
@Test
void testFindAccountWithEmptyName() throws ApiException {
final Optional<Account> accountWithName =
client.findAccountWithName("");
assertTrue(accountWithName.isEmpty(),
"accountWithName must be empty");
}
@Test
void testFindAccountWithShortName() throws ApiException {
final Optional<Account> accountWithName =
client.findAccountWithName("foo");
assertTrue(accountWithName.isEmpty(),
"accountWithName must be empty");
}
@Test
void testScanSurfaceAndRescan() throws ApiException, UnknownHostException {
final RegistrationLight registration =
client.createRegistration(TEST_LABEL, TEST_DESCRIPTION);
final Integer accountId = client.registrationToAccountId(registration);
final InetAddress[] addresses = InetAddress.getAllByName("iland.com");
final List<String> targets = Arrays.stream(addresses)
.filter(Inet4Address.class::isInstance)
.map(InetAddress::getHostAddress)
.collect(Collectors.toList());
final int targetsSize = targets.size();
final String internalIp = "192.168.1.1";
targets.add(internalIp);
final Integer scannerId =
client.getDefaultCloudScanner(accountId).getId();
final List<Integer> scannerIds = Collections.singletonList(scannerId);
// force multiple batches to check the behavior of `updateScanSurface`
ScanSurfaceBatcher.MAX_IPS_PER_SCAN_SURFACE_UPDATE = 1;
final List<ScanUuidScannerId> scanIds =
client.updateScanSurface(targets, scannerIds, accountId);
assertEquals(targetsSize, scanIds.size());
final int expectedSize = targetsSize * scannerIds.size();
final Set<ScanSurfaceEntry> scanSurface =
client.getScanSurface(accountId);
assertEquals(expectedSize, scanSurface.size(), "invalid scan surface");
assertFalse(scanSurface.stream()
.map(ScanSurfaceEntry::getInput)
.anyMatch(internalIp::equals),
"internal IP addresses were not filtered out");
final ScanSurfaceEntry scanSurfaceEntry =
scanSurface.stream().findAny().orElseThrow();
client.deleteScanSurfaceEntry(scanSurfaceEntry, true, accountId);
final Set<ScanSurfaceEntry> newScanSurface =
client.getScanSurface(accountId);
assertEquals(scanSurface.size() - 1, newScanSurface.size(),
"scan surface entry deletion failed");
client.rescan(accountId);
}
@Test
void testScanStatus() throws ApiException {
final Optional<ScanStatus> anyScanStatus = client.listAccounts(null)
.stream()
.map(Account::getId)
.map(accountId -> {
try {
return client.getScanStatus(accountId);
} catch (ApiException e) {
throw new RuntimeException(e);
}
})
.findAny();
assertTrue(anyScanStatus.isPresent(),
"at least one scan status must be present");
}
@Test
void testGetLatestReport() throws ApiException {
final int accountId = findAnAccountWithAtLeastOneReport();
final Optional<CVR> latestReport = client.getLatestReport(accountId);
assertTrue(latestReport.isPresent(), "latest report must be present");
}
private int findAnAccountWithAtLeastOneReport() throws ApiException {
final AtomicInteger atomicAccountId = new AtomicInteger();
client.listAccounts(null)
.stream()
.map(Account::getId)
.map(accountId -> {
atomicAccountId.set(accountId);
return getReportTimestamps(accountId);
})
.flatMap(List::stream)
.findFirst()
.orElseThrow();
return atomicAccountId.get();
}
@Test
void testReportsJson() throws ApiException {
final AtomicInteger atomicAccountId = new AtomicInteger();
final LocalDateTime generationDate = client.listAccounts(null)
.stream()
.map(Account::getId)
.map(accountId -> {
atomicAccountId.set(accountId);
return getReportTimestamps(accountId);
})
.flatMap(List::stream)
.findFirst()
.map(GenerationDate::parse)
.orElseThrow();
final Map<LocalDateTime, CodaClient.LazyCvrJson> reportsJson =
client.getReportsJson(CodaClient.ReportType.SNAPSHOT,
atomicAccountId.get());
assertTrue(reportsJson.containsKey(generationDate),
"JSON reports map must contain generation date");
final String json = reportsJson.get(generationDate).retrieveJson();
assertNotNull(json, "json must not be null");
}
private List<String> getReportTimestamps(final Integer accountId) {
try {
return client.getReportTimestamps(CodaClient.ReportType.SNAPSHOT,
accountId);
} catch (ApiException e) {
throw new RuntimeException(e);
}
}
@Test
void testThatTechnicalReportIsPopulated() throws Throwable {
final List<CVRMostVulnServer> technicalReport =
client.listAccounts(null)
.stream()
.map(Account::getId)
.map(this::getReports)
.map(Map::values)
.flatMap(Collection::stream)
.map(CodaClient.LazyCVR::retrieveUnchecked)
.filter(Objects::nonNull)
.map(CVR::getTechnicalReport)
.findFirst()
.orElse(null);
assertFalse(technicalReport == null || technicalReport.isEmpty(),
"technical reports must not be empty");
technicalReport.forEach(techReport -> {
assertNotNullOrEmpty(techReport.getHostname(), "hostname");
assertNotNullOrEmpty(techReport.getIp(), "IP");
final List<CVRVulnerability> vulnerabilities =
techReport.getVulnerabilities();
assertFalse(vulnerabilities.isEmpty());
vulnerabilities.stream()
.map(CVRVulnerability::getSummary)
.forEach(summary -> assertNotNullOrEmpty(summary, "summary"));
});
}
private static void assertNotNullOrEmpty(final String value,
final String name) {
assertNotNull(value, "%s must not be null".formatted(name));
assertNotEquals("", value, "%s must not be empty".formatted(name));
}
private Map<LocalDateTime, CodaClient.LazyCVR> getReports(
final Integer accountId) {
try {
return client.getReports(CodaClient.ReportType.SNAPSHOT, accountId);
} catch (ApiException e) {
throw new RuntimeException(e);
}
}
@Test
void testCyberRiskReport() throws ApiException {
final File cyberRiskReport = client.getCyberRiskReport(1);
assertTrue(cyberRiskReport.canRead());
assertTrue(cyberRiskReport.length() > 0, "PDF is empty");
assertTrue(cyberRiskReport.length() < 5000000,
"PDF is too large; it should be ~4MiB");
if (System.getProperty("user.name").equals("jenkins")) {
if (!cyberRiskReport.delete()) {
logger.error("Failed to delete {}", cyberRiskReport);
}
} else {
logger.info(cyberRiskReport.getPath());
}
}
@Test
void testListUsers() throws Throwable {
final List<AdminUser> users = client.listUsers();
assertNotNull(users, "users list must not be null");
assertFalse(users.isEmpty(), "users list must not be empty");
}
}