From 66f11559ab0662dc585f17b97b0854d5151e53a5 Mon Sep 17 00:00:00 2001 From: Joanne Wang Date: Wed, 4 Sep 2024 12:02:59 -0700 Subject: [PATCH] Update threat intel job mapping to new version (#1272) * update mapping Signed-off-by: Joanne Wang * fix integ tests Signed-off-by: Joanne Wang * remove debug in case of null and return listener on failure for lock Signed-off-by: Joanne Wang * remove stash context and change to local.root Signed-off-by: Joanne Wang * rename releaseLock Signed-off-by: Joanne Wang * check for concurrent modification exception Signed-off-by: Joanne Wang * remove exception check Signed-off-by: Joanne Wang --------- Signed-off-by: Joanne Wang --- .../threatIntel/common/TIFLockService.java | 21 +-- .../jobscheduler/TIFJobRunner.java | 4 +- .../jobscheduler/TIFSourceConfigRunner.java | 4 +- .../service/SATIFSourceConfigService.java | 94 +++++++--- .../TransportIndexTIFSourceConfigAction.java | 8 +- .../transport/TransportPutTIFJobAction.java | 8 +- .../securityanalytics/util/IndexUtils.java | 6 +- .../mappings/threat_intel_job_mapping.json | 1 + .../securityanalytics/TestHelpers.java | 63 ++++++- .../SourceConfigWithoutS3RestApiIT.java | 111 +++++++++++- .../ThreatIntelMonitorRestApiIT.java | 160 ++++++------------ .../common/ThreatIntelLockServiceTests.java | 2 +- 12 files changed, 312 insertions(+), 170 deletions(-) diff --git a/src/main/java/org/opensearch/securityanalytics/threatIntel/common/TIFLockService.java b/src/main/java/org/opensearch/securityanalytics/threatIntel/common/TIFLockService.java index f88aebd9b..eb467c55e 100644 --- a/src/main/java/org/opensearch/securityanalytics/threatIntel/common/TIFLockService.java +++ b/src/main/java/org/opensearch/securityanalytics/threatIntel/common/TIFLockService.java @@ -73,24 +73,13 @@ public void onFailure(final Exception e) { * * @param lockModel the lock model */ - public void releaseLock(final LockModel lockModel) { - log.debug("Releasing lock with id [{}]", lockModel.getLockId()); + public void releaseLock(final LockModel lockModel, final ActionListener listener) { lockService.release( lockModel, - ActionListener.wrap(released -> {}, exception -> log.error("Failed to release the lock", exception)) - ); - } - - /** - * Wrapper method of LockService#release - * - * @param lockModel the lock model - */ - public void releaseLockEventDriven(final LockModel lockModel, final ActionListener listener) { - log.debug("Releasing lock with id [{}]", lockModel.getLockId()); - lockService.release( - lockModel, - ActionListener.wrap(listener::onResponse, exception -> log.error("Failed to release the lock", exception)) + ActionListener.wrap(listener::onResponse, exception -> { + log.error("Failed to release the lock", exception); + listener.onFailure(exception); + }) ); } diff --git a/src/main/java/org/opensearch/securityanalytics/threatIntel/jobscheduler/TIFJobRunner.java b/src/main/java/org/opensearch/securityanalytics/threatIntel/jobscheduler/TIFJobRunner.java index 9e9022294..89dc729b4 100644 --- a/src/main/java/org/opensearch/securityanalytics/threatIntel/jobscheduler/TIFJobRunner.java +++ b/src/main/java/org/opensearch/securityanalytics/threatIntel/jobscheduler/TIFJobRunner.java @@ -115,7 +115,7 @@ protected Runnable updateJobRunner(final ScheduledJobParameter jobParameter) { ActionListener.wrap(lock -> { updateJobParameter(jobParameter, lockService.getRenewLockRunnable(new AtomicReference<>(lock)), ActionListener.wrap( - r -> lockService.releaseLockEventDriven(lock, ActionListener.wrap( + r -> lockService.releaseLock(lock, ActionListener.wrap( response -> { log.debug("Released tif job parameter lock with id [{}]", lock.getLockId()); }, @@ -125,7 +125,7 @@ protected Runnable updateJobRunner(final ScheduledJobParameter jobParameter) { )), e -> { log.error("Failed to update job parameter " + jobParameter.getName(), e); - lockService.releaseLockEventDriven(lock, ActionListener.wrap( + lockService.releaseLock(lock, ActionListener.wrap( response -> { log.debug("Released tif job parameter lock with id [{}]", lock.getLockId()); }, diff --git a/src/main/java/org/opensearch/securityanalytics/threatIntel/jobscheduler/TIFSourceConfigRunner.java b/src/main/java/org/opensearch/securityanalytics/threatIntel/jobscheduler/TIFSourceConfigRunner.java index fc01bbad7..1c098cfc9 100644 --- a/src/main/java/org/opensearch/securityanalytics/threatIntel/jobscheduler/TIFSourceConfigRunner.java +++ b/src/main/java/org/opensearch/securityanalytics/threatIntel/jobscheduler/TIFSourceConfigRunner.java @@ -108,7 +108,7 @@ protected Runnable retrieveLockAndUpdateConfig(final SATIFSourceConfig saTifSour updateSourceConfigAndIOCs(saTifSourceConfig, lockService.getRenewLockRunnable(new AtomicReference<>(lock)), ActionListener.wrap( r -> { - lockService.releaseLockEventDriven(lock, ActionListener.wrap( + lockService.releaseLock(lock, ActionListener.wrap( response -> { log.debug("Released threat intel source config lock with id [{}]", lock.getLockId()); }, @@ -119,7 +119,7 @@ protected Runnable retrieveLockAndUpdateConfig(final SATIFSourceConfig saTifSour }, e -> { log.error("Failed to update threat intel source config " + saTifSourceConfig.getName(), e); - lockService.releaseLockEventDriven(lock, ActionListener.wrap( + lockService.releaseLock(lock, ActionListener.wrap( response -> { log.debug("Released threat intel source config lock with id [{}]", lock.getLockId()); }, diff --git a/src/main/java/org/opensearch/securityanalytics/threatIntel/service/SATIFSourceConfigService.java b/src/main/java/org/opensearch/securityanalytics/threatIntel/service/SATIFSourceConfigService.java index c8e9bd12b..dee9ae013 100644 --- a/src/main/java/org/opensearch/securityanalytics/threatIntel/service/SATIFSourceConfigService.java +++ b/src/main/java/org/opensearch/securityanalytics/threatIntel/service/SATIFSourceConfigService.java @@ -50,10 +50,10 @@ import org.opensearch.securityanalytics.commons.model.IOCType; import org.opensearch.securityanalytics.threatIntel.action.monitor.SearchThreatIntelMonitorAction; import org.opensearch.securityanalytics.threatIntel.action.monitor.request.SearchThreatIntelMonitorRequest; -import org.opensearch.securityanalytics.threatIntel.common.StashedThreadContext; import org.opensearch.securityanalytics.threatIntel.common.TIFLockService; import org.opensearch.securityanalytics.threatIntel.model.DefaultIocStoreConfig; import org.opensearch.securityanalytics.threatIntel.model.SATIFSourceConfig; +import org.opensearch.securityanalytics.util.IndexUtils; import org.opensearch.securityanalytics.util.SecurityAnalyticsException; import org.opensearch.threadpool.ThreadPool; @@ -80,6 +80,7 @@ import static org.opensearch.securityanalytics.threatIntel.model.SATIFSourceConfig.SOURCE_CONFIG_FIELD; import static org.opensearch.securityanalytics.threatIntel.model.SATIFSourceConfig.STATE_FIELD; import static org.opensearch.securityanalytics.transport.TransportIndexDetectorAction.PLUGIN_OWNER_FIELD; +import static org.opensearch.securityanalytics.util.IndexUtils.shouldUpdateIndex; /** * CRUD for threat intel feeds source config object @@ -93,7 +94,6 @@ public class SATIFSourceConfigService { private final NamedXContentRegistry xContentRegistry; private final TIFLockService lockService; - public SATIFSourceConfigService(final Client client, final ClusterService clusterService, ThreadPool threadPool, @@ -139,7 +139,7 @@ public void indexTIFSourceConfig(SATIFSourceConfig saTifSourceConfig, } }, exception -> { log.error("Failed to create threat intel source config index", exception); - lockService.releaseLockEventDriven(lock, ActionListener.wrap( + lockService.releaseLock(lock, ActionListener.wrap( r -> { log.debug("Released threat intel source config lock with id [{}]", lock.getLockId()); actionListener.onFailure(exception); @@ -197,33 +197,75 @@ private String getIndexMapping() { /** * Index name: .opensearch-sap--job * Mapping: /mappings/threat_intel_job_mapping.json + * Updates the job index mapping if currently on a previous version * * @param stepListener setup listener */ public void createJobIndexIfNotExists(final StepListener stepListener) { // check if job index exists if (clusterService.state().metadata().hasIndex(SecurityAnalyticsPlugin.JOB_INDEX_NAME) == true) { - stepListener.onResponse(null); - return; - } - final CreateIndexRequest createIndexRequest = new CreateIndexRequest(SecurityAnalyticsPlugin.JOB_INDEX_NAME).mapping(getIndexMapping()) - .settings(SecurityAnalyticsPlugin.TIF_JOB_INDEX_SETTING); - StashedThreadContext.run(client, () -> client.admin().indices().create(createIndexRequest, ActionListener.wrap( - r -> { - log.debug("[{}] index created", SecurityAnalyticsPlugin.JOB_INDEX_NAME); - stepListener.onResponse(null); - }, e -> { - if (e instanceof ResourceAlreadyExistsException) { - log.info("Index [{}] already exists", SecurityAnalyticsPlugin.JOB_INDEX_NAME); + checkAndUpdateJobIndexMapping(stepListener); + } else { + final CreateIndexRequest createIndexRequest = new CreateIndexRequest(SecurityAnalyticsPlugin.JOB_INDEX_NAME).mapping(getIndexMapping()) + .settings(SecurityAnalyticsPlugin.TIF_JOB_INDEX_SETTING); + client.admin().indices().create(createIndexRequest, ActionListener.wrap( + r -> { + log.debug("[{}] index created", SecurityAnalyticsPlugin.JOB_INDEX_NAME); stepListener.onResponse(null); - return; + }, e -> { + if (e instanceof ResourceAlreadyExistsException) { + log.info("Index [{}] already exists", SecurityAnalyticsPlugin.JOB_INDEX_NAME); + stepListener.onResponse(null); + return; + } + log.error("Failed to create [{}] index", SecurityAnalyticsPlugin.JOB_INDEX_NAME, e); + stepListener.onFailure(e); } - log.error("Failed to create [{}] index", SecurityAnalyticsPlugin.JOB_INDEX_NAME, e); - stepListener.onFailure(e); - } - ))); + )); + } } + private void checkAndUpdateJobIndexMapping(StepListener stepListener) { + try { + // Check if job index contains old mapping, if so update index mapping (current version = 2) + if (shouldUpdateIndex(clusterService.state().metadata().index(SecurityAnalyticsPlugin.JOB_INDEX_NAME), getIndexMapping())) { + log.info("Old schema version found for [{}] index, updating the index mapping", SecurityAnalyticsPlugin.JOB_INDEX_NAME); + IndexUtils.updateIndexMapping( + SecurityAnalyticsPlugin.JOB_INDEX_NAME, + getIndexMapping(), clusterService.state(), client.admin().indices(), + ActionListener.wrap( + r -> { + log.info("Successfully updated index mapping for [{}] index", SecurityAnalyticsPlugin.JOB_INDEX_NAME); + stepListener.onResponse(null); + }, e -> { + // Check if version is updated despite failure + try { + // Check if job index still contains older mapping + if (shouldUpdateIndex(clusterService.state().metadata().index(SecurityAnalyticsPlugin.JOB_INDEX_NAME), getIndexMapping())) { + log.error("Job index still contains older mapping, failed to update job index mapping", e); + stepListener.onFailure(e); + } else { + // If job index contains newest mapping, then return success + log.info("Successfully updated index mapping for [{}] index", SecurityAnalyticsPlugin.JOB_INDEX_NAME); + stepListener.onResponse(null); + } + } catch (IOException exception) { + log.error("Failed to check if job index contains older mapping. Failed to update job index mapping", e); + stepListener.onFailure(e); + } + } + ), + false + ); + } else { + // If job index contains newest mapping, then do nothing + stepListener.onResponse(null); + } + } catch (IOException e) { + log.error("Failed to check and update job index mapping", e); + stepListener.onFailure(e); + } + } // Get TIF source config public void getTIFSourceConfig( @@ -234,7 +276,7 @@ public void getTIFSourceConfig( client.get(getRequest, ActionListener.wrap( getResponse -> { if (!getResponse.isExists()) { - actionListener.onFailure(SecurityAnalyticsException.wrap(new OpenSearchStatusException(String.format(Locale.getDefault(),"Threat intel source config [%s] not found.", tifSourceConfigId), RestStatus.NOT_FOUND))); + actionListener.onFailure(SecurityAnalyticsException.wrap(new OpenSearchStatusException(String.format(Locale.ROOT, "Threat intel source config [%s] not found.", tifSourceConfigId), RestStatus.NOT_FOUND))); return; } SATIFSourceConfig saTifSourceConfig = null; @@ -246,7 +288,7 @@ public void getTIFSourceConfig( saTifSourceConfig = SATIFSourceConfig.docParse(xcp, getResponse.getId(), getResponse.getVersion()); } if (saTifSourceConfig == null) { - actionListener.onFailure(SecurityAnalyticsException.wrap(new OpenSearchStatusException(String.format(Locale.getDefault(),"No threat intel source config exists [%s]", tifSourceConfigId), RestStatus.BAD_REQUEST))); + actionListener.onFailure(SecurityAnalyticsException.wrap(new OpenSearchStatusException(String.format(Locale.ROOT, "No threat intel source config exists [%s]", tifSourceConfigId), RestStatus.BAD_REQUEST))); } else { log.debug("Threat intel source config with id [{}] fetched", getResponse.getId()); actionListener.onResponse(saTifSourceConfig); @@ -366,9 +408,9 @@ public void deleteTIFSourceConfig( log.info("Deleted threat intel source config [{}] successfully", saTifSourceConfig.getId()); actionListener.onResponse(deleteResponse); } else if (deleteResponse.status().equals(RestStatus.NOT_FOUND)) { - actionListener.onFailure(SecurityAnalyticsException.wrap(new OpenSearchStatusException(String.format(Locale.getDefault(), "Threat intel source config with id [{%s}] not found", saTifSourceConfig.getId()), RestStatus.NOT_FOUND))); + actionListener.onFailure(SecurityAnalyticsException.wrap(new OpenSearchStatusException(String.format(Locale.ROOT, "Threat intel source config with id [{%s}] not found", saTifSourceConfig.getId()), RestStatus.NOT_FOUND))); } else { - actionListener.onFailure(SecurityAnalyticsException.wrap(new OpenSearchStatusException(String.format(Locale.getDefault(), "Failed to delete threat intel source config [{%s}]", saTifSourceConfig.getId()), deleteResponse.status()))); + actionListener.onFailure(SecurityAnalyticsException.wrap(new OpenSearchStatusException(String.format(Locale.ROOT, "Failed to delete threat intel source config [{%s}]", saTifSourceConfig.getId()), deleteResponse.status()))); } }, e -> { log.error("Failed to delete threat intel source config with id [{}]", saTifSourceConfig.getId()); @@ -407,7 +449,7 @@ public void deleteJobSchedulerLockIfJobDisabled( log.info("Threat intel job scheduler lock with id [{}] not found", id); actionListener.onResponse(deleteResponse); } else { - actionListener.onFailure(SecurityAnalyticsException.wrap(new OpenSearchStatusException(String.format(Locale.getDefault(), "Failed to delete threat intel job scheduler lock with id [{%s}]", id), deleteResponse.status()))); + actionListener.onFailure(SecurityAnalyticsException.wrap(new OpenSearchStatusException(String.format(Locale.ROOT, "Failed to delete threat intel job scheduler lock with id [{%s}]", id), deleteResponse.status()))); } }, e -> { log.error("Failed to delete threat intel job scheduler lock with id [{}]", id); @@ -453,7 +495,7 @@ private void deleteIocIndex(Set indicesToDelete, Boolean backgroundJob, if (!response.isAcknowledged()) { log.error("Could not delete one or more IOC indices: " + index); if (backgroundJob == false) { - listener.onFailure(SecurityAnalyticsException.wrap(new OpenSearchStatusException(String.format(Locale.getDefault(), "Could not delete one or more IOC indices: " + index), RestStatus.BAD_REQUEST))); + listener.onFailure(SecurityAnalyticsException.wrap(new OpenSearchStatusException(String.format(Locale.ROOT, "Could not delete one or more IOC indices: " + index), RestStatus.BAD_REQUEST))); } } else { log.debug("Successfully deleted one or more IOC indices:" + index); diff --git a/src/main/java/org/opensearch/securityanalytics/threatIntel/transport/TransportIndexTIFSourceConfigAction.java b/src/main/java/org/opensearch/securityanalytics/threatIntel/transport/TransportIndexTIFSourceConfigAction.java index ecdeaa683..afd22f799 100644 --- a/src/main/java/org/opensearch/securityanalytics/threatIntel/transport/TransportIndexTIFSourceConfigAction.java +++ b/src/main/java/org/opensearch/securityanalytics/threatIntel/transport/TransportIndexTIFSourceConfigAction.java @@ -20,10 +20,8 @@ import org.opensearch.securityanalytics.threatIntel.action.SAIndexTIFSourceConfigAction; import org.opensearch.securityanalytics.threatIntel.action.SAIndexTIFSourceConfigRequest; import org.opensearch.securityanalytics.threatIntel.action.SAIndexTIFSourceConfigResponse; -import org.opensearch.securityanalytics.threatIntel.common.SourceConfigType; import org.opensearch.securityanalytics.threatIntel.common.TIFLockService; import org.opensearch.securityanalytics.threatIntel.model.SATIFSourceConfigDto; -import org.opensearch.securityanalytics.threatIntel.model.UrlDownloadSource; import org.opensearch.securityanalytics.threatIntel.service.SATIFSourceConfigManagementService; import org.opensearch.securityanalytics.transport.SecureTransportAction; import org.opensearch.securityanalytics.util.SecurityAnalyticsException; @@ -106,7 +104,7 @@ private void retrieveLockAndCreateTIFConfig(SAIndexTIFSourceConfigRequest reques user, ActionListener.wrap( saTifSourceConfigDtoResponse -> { - lockService.releaseLockEventDriven(lock, ActionListener.wrap( + lockService.releaseLock(lock, ActionListener.wrap( r -> { log.debug("Released threat intel source config lock with id [{}]", lock.getLockId()); listener.onResponse(new SAIndexTIFSourceConfigResponse( @@ -129,7 +127,7 @@ private void retrieveLockAndCreateTIFConfig(SAIndexTIFSourceConfigRequest reques }, e -> { String action = RestRequest.Method.PUT.equals(request.getMethod()) ? "update" : "create"; log.error(String.format("Failed to %s IOCs and threat intel source config", action), e); - lockService.releaseLockEventDriven(lock, ActionListener.wrap( + lockService.releaseLock(lock, ActionListener.wrap( r -> { log.debug("Released threat intel source config lock with id [{}]", lock.getLockId()); listener.onFailure(e); @@ -146,7 +144,7 @@ private void retrieveLockAndCreateTIFConfig(SAIndexTIFSourceConfigRequest reques } catch (Exception e) { String action = RestRequest.Method.PUT.equals(request.getMethod()) ? "update" : "create"; log.error(String.format("Failed to %s IOCs and threat intel source config", action), e); - lockService.releaseLockEventDriven(lock, ActionListener.wrap( + lockService.releaseLock(lock, ActionListener.wrap( r -> { log.debug("Released threat intel source config lock with id [{}]", lock.getLockId()); listener.onFailure(e); diff --git a/src/main/java/org/opensearch/securityanalytics/threatIntel/transport/TransportPutTIFJobAction.java b/src/main/java/org/opensearch/securityanalytics/threatIntel/transport/TransportPutTIFJobAction.java index a72844e40..4c5bd5e4d 100644 --- a/src/main/java/org/opensearch/securityanalytics/threatIntel/transport/TransportPutTIFJobAction.java +++ b/src/main/java/org/opensearch/securityanalytics/threatIntel/transport/TransportPutTIFJobAction.java @@ -107,7 +107,7 @@ protected void doExecute(final Task task, final PutTIFJobRequest request, final internalDoExecute(request, lock, listener); } catch (Exception e) { log.error("Failed execution to put tif job action", e); - lockService.releaseLockEventDriven(lock, ActionListener.wrap( + lockService.releaseLock(lock, ActionListener.wrap( r -> { log.debug("Released tif job parameter lock with id [{}]", lock.getLockId()); listener.onFailure(e); @@ -147,7 +147,7 @@ protected void internalDoExecute( } }, exception -> { log.error("Failed to save tif job parameter", exception); - lockService.releaseLockEventDriven(lock, ActionListener.wrap( + lockService.releaseLock(lock, ActionListener.wrap( r -> { log.debug("Released tif job parameter lock with id [{}]", lock.getLockId()); listener.onFailure(exception); @@ -176,7 +176,7 @@ protected ActionListener postIndexingTifJobParameter( createThreatIntelFeedData(tifJobParameter, lockService.getRenewLockRunnable(lockReference), ActionListener.wrap( threatIntelIndicesResponse -> { if (threatIntelIndicesResponse.isAcknowledged()) { - lockService.releaseLockEventDriven(lockReference.get(), ActionListener.wrap( + lockService.releaseLock(lockReference.get(), ActionListener.wrap( r -> { log.debug("Released tif job parameter lock with id [{}]", lock.getLockId()); listener.onResponse(new AcknowledgedResponse(true)); @@ -200,7 +200,7 @@ protected ActionListener postIndexingTifJobParameter( log.error("Internal server error"); exception = e; } - lockService.releaseLockEventDriven(lock, ActionListener.wrap( + lockService.releaseLock(lock, ActionListener.wrap( r -> { log.debug("Released tif job parameter lock with id [{}]", lock.getLockId()); listener.onFailure(exception); diff --git a/src/main/java/org/opensearch/securityanalytics/util/IndexUtils.java b/src/main/java/org/opensearch/securityanalytics/util/IndexUtils.java index 9d5066308..c4dafed85 100644 --- a/src/main/java/org/opensearch/securityanalytics/util/IndexUtils.java +++ b/src/main/java/org/opensearch/securityanalytics/util/IndexUtils.java @@ -31,9 +31,9 @@ public class IndexUtils { - private static final String _META = "_meta"; - private static final Integer NO_SCHEMA_VERSION = 0; - private static final String SCHEMA_VERSION = "schema_version"; + public static final String _META = "_meta"; + public static final Integer NO_SCHEMA_VERSION = 0; + public static final String SCHEMA_VERSION = "schema_version"; public static Boolean detectorIndexUpdated = false; public static Boolean customRuleIndexUpdated = false; diff --git a/src/main/resources/mappings/threat_intel_job_mapping.json b/src/main/resources/mappings/threat_intel_job_mapping.json index f437efe6f..fbc1c03dc 100644 --- a/src/main/resources/mappings/threat_intel_job_mapping.json +++ b/src/main/resources/mappings/threat_intel_job_mapping.json @@ -1,4 +1,5 @@ { + "dynamic": true, "_meta" : { "schema_version": 2 }, diff --git a/src/test/java/org/opensearch/securityanalytics/TestHelpers.java b/src/test/java/org/opensearch/securityanalytics/TestHelpers.java index 44c5d9b51..563f71596 100644 --- a/src/test/java/org/opensearch/securityanalytics/TestHelpers.java +++ b/src/test/java/org/opensearch/securityanalytics/TestHelpers.java @@ -30,7 +30,6 @@ import org.opensearch.securityanalytics.model.DetectorInput; import org.opensearch.securityanalytics.model.DetectorRule; import org.opensearch.securityanalytics.model.DetectorTrigger; -import org.opensearch.securityanalytics.model.STIX2IOCDto; import org.opensearch.securityanalytics.model.ThreatIntelFeedData; import org.opensearch.securityanalytics.model.threatintel.IocFinding; import org.opensearch.securityanalytics.model.threatintel.ThreatIntelAlert; @@ -1875,6 +1874,68 @@ public static String windowsIndexMappingOnlyNumericAndText() { " }"; } + public static String oldThreatIntelJobMapping() { + return " \"dynamic\": \"strict\",\n" + + " \"_meta\": {\n" + + " \"schema_version\": 1\n" + + " },\n" + + " \"properties\": {\n" + + " \"schema_version\": {\n" + + " \"type\": \"integer\"\n" + + " },\n" + + " \"enabled_time\": {\n" + + " \"type\": \"long\"\n" + + " },\n" + + " \"indices\": {\n" + + " \"type\": \"text\"\n" + + " },\n" + + " \"last_update_time\": {\n" + + " \"type\": \"long\"\n" + + " },\n" + + " \"name\": {\n" + + " \"type\": \"text\"\n" + + " },\n" + + " \"schedule\": {\n" + + " \"properties\": {\n" + + " \"interval\": {\n" + + " \"properties\": {\n" + + " \"period\": {\n" + + " \"type\": \"long\"\n" + + " },\n" + + " \"start_time\": {\n" + + " \"type\": \"long\"\n" + + " },\n" + + " \"unit\": {\n" + + " \"type\": \"text\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " },\n" + + " \"state\": {\n" + + " \"type\": \"text\"\n" + + " },\n" + + " \"update_enabled\": {\n" + + " \"type\": \"boolean\"\n" + + " },\n" + + " \"update_stats\": {\n" + + " \"properties\": {\n" + + " \"last_failed_at_in_epoch_millis\": {\n" + + " \"type\": \"long\"\n" + + " },\n" + + " \"last_processing_time_in_millis\": {\n" + + " \"type\": \"long\"\n" + + " },\n" + + " \"last_skipped_at_in_epoch_millis\": {\n" + + " \"type\": \"long\"\n" + + " },\n" + + " \"last_succeeded_at_in_epoch_millis\": {\n" + + " \"type\": \"long\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }"; + } public static String randomDoc(int severity, int version, String opCode) { String doc = "{\n" + diff --git a/src/test/java/org/opensearch/securityanalytics/resthandler/SourceConfigWithoutS3RestApiIT.java b/src/test/java/org/opensearch/securityanalytics/resthandler/SourceConfigWithoutS3RestApiIT.java index 4e7f89904..a542e9443 100644 --- a/src/test/java/org/opensearch/securityanalytics/resthandler/SourceConfigWithoutS3RestApiIT.java +++ b/src/test/java/org/opensearch/securityanalytics/resthandler/SourceConfigWithoutS3RestApiIT.java @@ -15,6 +15,8 @@ import org.junit.Assert; import org.opensearch.client.Response; import org.opensearch.client.ResponseException; +import org.opensearch.client.WarningFailureException; +import org.opensearch.common.settings.Settings; import org.opensearch.core.rest.RestStatus; import org.opensearch.jobscheduler.spi.schedule.IntervalSchedule; import org.opensearch.search.SearchHit; @@ -42,6 +44,7 @@ import static org.opensearch.jobscheduler.spi.utils.LockService.LOCK_INDEX_NAME; import static org.opensearch.securityanalytics.SecurityAnalyticsPlugin.JOB_INDEX_NAME; +import static org.opensearch.securityanalytics.TestHelpers.oldThreatIntelJobMapping; import static org.opensearch.securityanalytics.services.STIX2IOCFeedStore.IOC_ALL_INDEX_PATTERN; import static org.opensearch.securityanalytics.services.STIX2IOCFeedStore.getAllIocIndexPatternById; @@ -208,7 +211,7 @@ public void testCreateIocUploadSourceConfigIncorrectIocTypes() throws IOExceptio } } - public void testUpdateIocUploadSourceConfig() throws IOException, InterruptedException { + public void testUpdateIocUploadSourceConfig() throws IOException { // Create source config with IPV4 IOCs String feedName = "test_update"; String feedFormat = "STIX"; @@ -365,7 +368,7 @@ public void testUpdateIocUploadSourceConfig() throws IOException, InterruptedExc assertEquals(1, iocHits.size()); } - public void testActivateDeactivateIocUploadSourceConfig() throws IOException, InterruptedException { + public void testActivateDeactivateIocUploadSourceConfig() throws IOException { // Create source config with IPV4 IOCs String feedName = "test_update"; String feedFormat = "STIX"; @@ -536,7 +539,7 @@ public void testActivateDeactivateIocUploadSourceConfig() throws IOException, In assertTrue((Boolean) scr.get("enabled_for_scan")); } - public void testActivateDeactivateUrlDownloadSourceConfig() throws IOException, InterruptedException { + public void testActivateDeactivateUrlDownloadSourceConfig() throws IOException { // Search source configs when none are created String request = "{\n" + " \"query\" : {\n" + @@ -889,7 +892,7 @@ public void testSearchAndCreateDefaultSourceConfig() throws IOException { Assert.assertEquals(1, ((Map) ((Map) responseBody.get("hits")).get("total")).get("value")); } - public void testUpdateDefaultSourceConfigThrowsError() throws IOException, InterruptedException { + public void testUpdateDefaultSourceConfigThrowsError() throws IOException { // Search source configs when none are created String request = "{\n" + " \"query\" : {\n" + @@ -951,6 +954,106 @@ public void testUpdateDefaultSourceConfigThrowsError() throws IOException, Inter } } + public void testUpdateJobIndexMapping() throws IOException { + // Create job index with old threat intel mapping + // Try catch needed because of warning when creating a system index which is needed to replicate previous tif job mapping + try { + createIndex(JOB_INDEX_NAME, Settings.EMPTY, oldThreatIntelJobMapping()); + } catch (WarningFailureException e) { + // Ensure index was created with old mappings + String request = "{\n" + + " \"query\" : {\n" + + " \"match_all\":{\n" + + " }\n" + + " }\n" + + "}"; + List hits = executeSearch(JOB_INDEX_NAME, request); + Assert.assertEquals(0, hits.size()); + + Map props = getIndexMappingsAPIFlat(JOB_INDEX_NAME); + assertTrue(props.containsKey("enabled_time")); + assertTrue(props.containsKey("schedule.interval.start_time")); + assertFalse(props.containsKey("source_config.source.ioc_upload.file_name")); + assertFalse(props.containsKey("source_config.source.s3.object_key")); + } + + // Create new threat intel source config + SATIFSourceConfigDto saTifSourceConfigDto = getSatifSourceConfigDto(); + + Response makeResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.THREAT_INTEL_SOURCE_URI, Collections.emptyMap(), toHttpEntity(saTifSourceConfigDto)); + Assert.assertEquals(RestStatus.CREATED, restStatus(makeResponse)); + Map responseBody = asMap(makeResponse); + + String createdId = responseBody.get("_id").toString(); + Assert.assertNotEquals("response is missing Id", SATIFSourceConfigDto.NO_ID, createdId); + + int createdVersion = Integer.parseInt(responseBody.get("_version").toString()); + Assert.assertTrue("incorrect version", createdVersion > 0); + + // Ensure source config document was indexed + String request = "{\n" + + " \"query\" : {\n" + + " \"match_all\":{\n" + + " }\n" + + " }\n" + + "}"; + List hits = executeSearch(JOB_INDEX_NAME, request); + Assert.assertEquals(1, hits.size()); + + // Ensure index mappings were updated + Map props = getIndexMappingsAPIFlat(JOB_INDEX_NAME); + assertTrue(props.containsKey("source_config.source.ioc_upload.file_name")); + assertTrue(props.containsKey("source_config.source.s3.object_key")); + assertTrue(props.containsKey("source_config.description")); + assertTrue(props.containsKey("source_config.last_update_time")); + assertTrue(props.containsKey("source_config.refresh_type")); + } + + private static SATIFSourceConfigDto getSatifSourceConfigDto() { + String feedName = "test_ioc_upload"; + String feedFormat = "STIX"; + SourceConfigType sourceConfigType = SourceConfigType.IOC_UPLOAD; + + List iocs = List.of(new STIX2IOCDto( + "id", + "name", + new IOCType(IOCType.IPV4_TYPE), + "value", + "severity", + null, + null, + "description", + List.of("labels"), + "specversion", + "feedId", + "feedName", + 1L)); + + IocUploadSource iocUploadSource = new IocUploadSource(null, iocs); + Boolean enabled = false; + List iocTypes = List.of(IOCType.IPV4_TYPE); + return new SATIFSourceConfigDto( + null, + null, + feedName, + feedFormat, + sourceConfigType, + null, + null, + null, + iocUploadSource, + null, + null, + null, + null, + null, + null, + null, + enabled, + iocTypes, true + ); + } + @Override protected boolean preserveIndicesUponCompletion() { return false; diff --git a/src/test/java/org/opensearch/securityanalytics/resthandler/ThreatIntelMonitorRestApiIT.java b/src/test/java/org/opensearch/securityanalytics/resthandler/ThreatIntelMonitorRestApiIT.java index 69b4b20c7..bcf424315 100644 --- a/src/test/java/org/opensearch/securityanalytics/resthandler/ThreatIntelMonitorRestApiIT.java +++ b/src/test/java/org/opensearch/securityanalytics/resthandler/ThreatIntelMonitorRestApiIT.java @@ -3,11 +3,12 @@ import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.junit.Assert; import org.opensearch.client.Request; import org.opensearch.client.Response; import org.opensearch.client.ResponseException; -import org.opensearch.common.settings.Settings; import org.opensearch.common.xcontent.XContentFactory; import org.opensearch.commons.alerting.model.IntervalSchedule; import org.opensearch.commons.alerting.model.Monitor; @@ -20,15 +21,15 @@ import org.opensearch.securityanalytics.commons.model.IOCType; import org.opensearch.securityanalytics.model.Detector; import org.opensearch.securityanalytics.model.DetectorTrigger; -import org.opensearch.securityanalytics.model.STIX2IOC; +import org.opensearch.securityanalytics.model.STIX2IOCDto; import org.opensearch.securityanalytics.threatIntel.common.RefreshType; import org.opensearch.securityanalytics.threatIntel.common.SourceConfigType; import org.opensearch.securityanalytics.threatIntel.common.TIFJobState; import org.opensearch.securityanalytics.threatIntel.iocscan.dao.ThreatIntelAlertService; import org.opensearch.securityanalytics.threatIntel.iocscan.dto.PerIocTypeScanInputDto; -import org.opensearch.securityanalytics.threatIntel.model.DefaultIocStoreConfig; -import org.opensearch.securityanalytics.threatIntel.model.S3Source; +import org.opensearch.securityanalytics.threatIntel.model.IocUploadSource; import org.opensearch.securityanalytics.threatIntel.model.SATIFSourceConfig; +import org.opensearch.securityanalytics.threatIntel.model.SATIFSourceConfigDto; import org.opensearch.securityanalytics.threatIntel.sacommons.monitor.ThreatIntelMonitorDto; import org.opensearch.securityanalytics.threatIntel.sacommons.monitor.ThreatIntelTriggerDto; @@ -49,113 +50,64 @@ import static org.opensearch.securityanalytics.threatIntel.resthandler.monitor.RestSearchThreatIntelMonitorAction.SEARCH_THREAT_INTEL_MONITOR_PATH; public class ThreatIntelMonitorRestApiIT extends SecurityAnalyticsRestTestCase { - private final String iocIndexMappings = "\"properties\": {\n" + - " \"name\": {\n" + - " \"type\": \"keyword\"\n" + - " },\n" + - " \"type\": {\n" + - " \"type\": \"keyword\"\n" + - " },\n" + - " \"value\": {\n" + - " \"type\": \"keyword\"\n" + - " },\n" + - " \"severity\": {\n" + - " \"type\": \"keyword\"\n" + - " },\n" + - " \"spec_version\": {\n" + - " \"type\": \"keyword\"\n" + - " },\n" + - " \"created\": {\n" + - " \"type\": \"date\"\n" + - " },\n" + - " \"modified\": {\n" + - " \"type\": \"date\"\n" + - " },\n" + - " \"description\": {\n" + - " \"type\": \"text\"\n" + - " },\n" + - " \"labels\": {\n" + - " \"type\": \"keyword\"\n" + - " },\n" + - " \"feed_id\": {\n" + - " \"type\": \"keyword\"\n" + - " },\n" + - " \"feed_name\": {\n" + - " \"type\": \"keyword\"\n" + - " }\n" + - " }"; - - private List testIocs = new ArrayList<>(); - - public void indexSourceConfigsAndIocs(int num, List iocVals) throws IOException { - for (int i = 0; i < num; i++) { - String configId = "id" + i; - String iocActiveIndex = ".opensearch-sap-ioc-" + configId + Instant.now().toEpochMilli(); - String indexPattern = ".opensearch-sap-ioc-" + configId; - indexTifSourceConfig(num, configId, indexPattern, iocActiveIndex, i); - - // Create the index before ingesting docs to ensure the mappings are correct - createIndex(iocActiveIndex, Settings.EMPTY, iocIndexMappings); - - // Refresh testIocs list between tests - testIocs = new ArrayList<>(); - for (int i1 = 0; i1 < iocVals.size(); i1++) { - indexIocs(iocVals, iocActiveIndex, i1, configId); - } + private final Logger log = LogManager.getLogger(ThreatIntelMonitorRestApiIT.class); + + private List testIocDtos = new ArrayList<>(); + + public String indexSourceConfigsAndIocs(List iocVals) throws IOException { + testIocDtos = new ArrayList<>(); + for (int i1 = 0; i1 < iocVals.size(); i1++) { + // create IOCs + STIX2IOCDto stix2IOCDto = new STIX2IOCDto( + "id" + i1, + "random", + new IOCType(IOCType.IPV4_TYPE), + iocVals.get(i1), + "", + Instant.now(), + Instant.now(), + "", + emptyList(), + "spec", + "configId", + "", + 1L + ); + + testIocDtos.add(stix2IOCDto); } + return indexTifSourceConfig(testIocDtos); } - private void indexIocs(List iocVals, String iocIndexName, int i1, String configId) throws IOException { - String iocId = iocIndexName + i1; - STIX2IOC stix2IOC = new STIX2IOC( - iocId, - "random", - new IOCType(IOCType.IPV4_TYPE), - iocVals.get(i1), - "", - Instant.now(), - Instant.now(), - "", - emptyList(), - "spec", - configId, - "", - STIX2IOC.NO_VERSION - ); - - // Add IOC to testIocs List for future validation - testIocs.add(stix2IOC); - - indexDoc(iocIndexName, iocId, stix2IOC.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS).toString()); - List searchHits = executeSearch(iocIndexName, getMatchAllSearchRequestString(iocVals.size())); - assertEquals(searchHits.size(), i1 + 1); - } - - private void indexTifSourceConfig(int num, String configId, String indexPattern, String iocActiveIndex, int i) throws IOException { - SATIFSourceConfig config = new SATIFSourceConfig( - configId, + private String indexTifSourceConfig(List testIocDtos) throws IOException { + SATIFSourceConfigDto saTifSourceConfigDto = new SATIFSourceConfigDto( + "configId", SATIFSourceConfig.NO_VERSION, "name1", "STIX2", - SourceConfigType.S3_CUSTOM, + SourceConfigType.IOC_UPLOAD, "description", null, Instant.now(), - new S3Source("bucketname", "key", "region", "roleArn"), + new IocUploadSource(null, testIocDtos), null, Instant.now(), - new org.opensearch.jobscheduler.spi.schedule.IntervalSchedule(Instant.now(), 1, ChronoUnit.MINUTES), + null, TIFJobState.AVAILABLE, RefreshType.FULL, null, null, false, - new DefaultIocStoreConfig(List.of(new DefaultIocStoreConfig.IocToIndexDetails(new IOCType(IOCType.IPV4_TYPE), indexPattern, iocActiveIndex))), List.of(IOCType.IPV4_TYPE), true ); - String indexName = SecurityAnalyticsPlugin.JOB_INDEX_NAME; - Response response = indexDoc(indexName, configId, config.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS).toString()); + + Response makeResponse = makeRequest(client(), "POST", SecurityAnalyticsPlugin.THREAT_INTEL_SOURCE_URI, Collections.emptyMap(), toHttpEntity(saTifSourceConfigDto)); + Assert.assertEquals(RestStatus.CREATED, restStatus(makeResponse)); + + Assert.assertEquals(201, makeResponse.getStatusLine().getStatusCode()); + Map responseBody = asMap(makeResponse); + return responseBody.get("_id").toString(); } public void testCreateThreatIntelMonitor_monitorAliases() throws IOException { @@ -164,12 +116,12 @@ public void testCreateThreatIntelMonitor_monitorAliases() throws IOException { Map responseAsMap = responseAsMap(iocFindingsResponse); Assert.assertEquals(0, ((List>) responseAsMap.get("ioc_findings")).size()); List vals = List.of("ip1", "ip2"); - indexSourceConfigsAndIocs(1, vals); + String createdId = indexSourceConfigsAndIocs(vals); + String index = "alias1"; Map> testAlias = createTestAlias(index, 1, true); String monitorName = "test_monitor_name"; - /**create monitor */ ThreatIntelMonitorDto iocScanMonitor = randomIocScanMonitorDto(index); Response response = makeRequest(client(), "POST", SecurityAnalyticsPlugin.THREAT_INTEL_MONITOR_URI, Collections.emptyMap(), toHttpEntity(iocScanMonitor)); @@ -201,7 +153,6 @@ public void testCreateThreatIntelMonitor_monitorAliases() throws IOException { Response executeResponse = executeAlertingMonitor(monitorId, Collections.emptyMap()); Map executeResults = entityAsMap(executeResponse); - assertEquals(1, 1); String matchAllRequest = getMatchAllRequest(); Response searchMonitorResponse = makeRequest(client(), "POST", SEARCH_THREAT_INTEL_MONITOR_PATH, Collections.emptyMap(), new StringEntity(matchAllRequest, ContentType.APPLICATION_JSON, false)); @@ -212,7 +163,6 @@ public void testCreateThreatIntelMonitor_monitorAliases() throws IOException { assertEquals(totalHitsVal.intValue(), 1); makeRequest(client(), "POST", SEARCH_THREAT_INTEL_MONITOR_PATH, Collections.emptyMap(), new StringEntity(matchAllRequest, ContentType.APPLICATION_JSON, false)); - iocFindingsResponse = makeRequest(client(), "GET", SecurityAnalyticsPlugin.THREAT_INTEL_BASE_URI + "/findings/_search", Map.of(), null); responseAsMap = responseAsMap(iocFindingsResponse); @@ -237,7 +187,7 @@ public void testCreateThreatIntelMonitor_monitorAliases() throws IOException { Assert.assertEquals(4, ((List>) responseAsMap.get("ioc_findings")).size()); // Use ListIOCs API to confirm expected number of findings are returned - String listIocsUri = String.format("?%s=%s", ListIOCsActionRequest.FEED_IDS_FIELD, "id0"); + String listIocsUri = String.format("?%s=%s", ListIOCsActionRequest.FEED_IDS_FIELD, createdId); Response listIocsResponse = makeRequest(client(), "GET", SecurityAnalyticsPlugin.LIST_IOCS_URI + listIocsUri, Collections.emptyMap(), null); Map listIocsResponseMap = responseAsMap(listIocsResponse); List> iocsMap = (List>) listIocsResponseMap.get("iocs"); @@ -245,7 +195,7 @@ public void testCreateThreatIntelMonitor_monitorAliases() throws IOException { iocsMap.forEach((iocDetails) -> { String iocId = (String) iocDetails.get("id"); int numFindings = (Integer) iocDetails.get("num_findings"); - assertTrue(testIocs.stream().anyMatch(ioc -> iocId.equals(ioc.getId()))); + assertTrue(testIocDtos.stream().anyMatch(ioc -> iocId.equals(ioc.getId()))); assertEquals(2, numFindings); }); @@ -302,7 +252,7 @@ public void testCreateThreatIntelMonitor() throws IOException { Map responseAsMap = responseAsMap(iocFindingsResponse); Assert.assertEquals(0, ((List>) responseAsMap.get("ioc_findings")).size()); List vals = List.of("ip1", "ip2"); - indexSourceConfigsAndIocs(1, vals); + String createdId = indexSourceConfigsAndIocs(vals); String index = createTestIndex(randomIndex(), windowsIndexMapping()); String monitorName = "test_monitor_name"; @@ -338,7 +288,6 @@ public void testCreateThreatIntelMonitor() throws IOException { Response executeResponse = executeAlertingMonitor(monitorId, Collections.emptyMap()); Map executeResults = entityAsMap(executeResponse); - assertEquals(1, 1); String matchAllRequest = getMatchAllRequest(); Response searchMonitorResponse = makeRequest(client(), "POST", SEARCH_THREAT_INTEL_MONITOR_PATH, Collections.emptyMap(), new StringEntity(matchAllRequest, ContentType.APPLICATION_JSON, false)); @@ -374,7 +323,7 @@ public void testCreateThreatIntelMonitor() throws IOException { Assert.assertEquals(4, ((List>) responseAsMap.get("ioc_findings")).size()); // Use ListIOCs API to confirm expected number of findings are returned - String listIocsUri = String.format("?%s=%s", ListIOCsActionRequest.FEED_IDS_FIELD, "id0"); + String listIocsUri = String.format("?%s=%s", ListIOCsActionRequest.FEED_IDS_FIELD, createdId); Response listIocsResponse = makeRequest(client(), "GET", SecurityAnalyticsPlugin.LIST_IOCS_URI + listIocsUri, Collections.emptyMap(), null); Map listIocsResponseMap = responseAsMap(listIocsResponse); List> iocsMap = (List>) listIocsResponseMap.get("iocs"); @@ -382,7 +331,7 @@ public void testCreateThreatIntelMonitor() throws IOException { iocsMap.forEach((iocDetails) -> { String iocId = (String) iocDetails.get("id"); int numFindings = (Integer) iocDetails.get("num_findings"); - assertTrue(testIocs.stream().anyMatch(ioc -> iocId.equals(ioc.getId()))); + assertTrue(testIocDtos.stream().anyMatch(ioc -> iocId.equals(ioc.getId()))); assertEquals(2, numFindings); }); @@ -451,7 +400,7 @@ public void testCreateThreatIntelMonitorWithExistingDetector() throws IOExceptio Map responseAsMap = responseAsMap(iocFindingsResponse); Assert.assertEquals(0, ((List>) responseAsMap.get("ioc_findings")).size()); List vals = List.of("ip1", "ip2"); - indexSourceConfigsAndIocs(1, vals); + String createdId = indexSourceConfigsAndIocs(vals); String monitorName = "test_monitor_name"; @@ -486,7 +435,6 @@ public void testCreateThreatIntelMonitorWithExistingDetector() throws IOExceptio Response executeResponse = executeAlertingMonitor(monitorId, Collections.emptyMap()); Map executeResults = entityAsMap(executeResponse); - assertEquals(1, 1); String matchAllRequest = getMatchAllRequest(); Response searchMonitorResponse = makeRequest(client(), "POST", SEARCH_THREAT_INTEL_MONITOR_PATH, Collections.emptyMap(), new StringEntity(matchAllRequest, ContentType.APPLICATION_JSON)); @@ -522,7 +470,7 @@ public void testCreateThreatIntelMonitorWithExistingDetector() throws IOExceptio Assert.assertEquals(4, ((List>) responseAsMap.get("ioc_findings")).size()); // Use ListIOCs API to confirm expected number of findings are returned - String listIocsUri = String.format("?%s=%s", ListIOCsActionRequest.FEED_IDS_FIELD, "id0"); + String listIocsUri = String.format("?%s=%s", ListIOCsActionRequest.FEED_IDS_FIELD, createdId); Response listIocsResponse = makeRequest(client(), "GET", SecurityAnalyticsPlugin.LIST_IOCS_URI + listIocsUri, Collections.emptyMap(), null); Map listIocsResponseMap = responseAsMap(listIocsResponse); List> iocsMap = (List>) listIocsResponseMap.get("iocs"); @@ -530,7 +478,7 @@ public void testCreateThreatIntelMonitorWithExistingDetector() throws IOExceptio iocsMap.forEach((iocDetails) -> { String iocId = (String) iocDetails.get("id"); int numFindings = (Integer) iocDetails.get("num_findings"); - assertTrue(testIocs.stream().anyMatch(ioc -> iocId.equals(ioc.getId()))); + assertTrue(testIocDtos.stream().anyMatch(ioc -> iocId.equals(ioc.getId()))); assertEquals(2, numFindings); }); diff --git a/src/test/java/org/opensearch/securityanalytics/threatIntel/common/ThreatIntelLockServiceTests.java b/src/test/java/org/opensearch/securityanalytics/threatIntel/common/ThreatIntelLockServiceTests.java index ec6041322..2f5aa90a3 100644 --- a/src/test/java/org/opensearch/securityanalytics/threatIntel/common/ThreatIntelLockServiceTests.java +++ b/src/test/java/org/opensearch/securityanalytics/threatIntel/common/ThreatIntelLockServiceTests.java @@ -60,7 +60,7 @@ public void testReleaseLock_whenValidInput_thenSucceed() { LOCK_DURATION_IN_SECONDS, false ); - noOpsLockService.releaseLockEventDriven(lockModel, ActionListener.wrap( + noOpsLockService.releaseLock(lockModel, ActionListener.wrap( Assert::assertFalse, e -> fail() )); }