diff --git a/.apigentools-info b/.apigentools-info index 32e5e8f28a4..a746c2a8056 100644 --- a/.apigentools-info +++ b/.apigentools-info @@ -4,13 +4,13 @@ "spec_versions": { "v1": { "apigentools_version": "1.6.6", - "regenerated": "2024-03-26 15:17:41.018538", - "spec_repo_commit": "46383d02" + "regenerated": "2024-03-27 22:12:45.580153", + "spec_repo_commit": "85625198" }, "v2": { "apigentools_version": "1.6.6", - "regenerated": "2024-03-26 15:17:41.036052", - "spec_repo_commit": "46383d02" + "regenerated": "2024-03-27 22:12:45.599497", + "spec_repo_commit": "85625198" } } } \ No newline at end of file diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index 5f027286d07..37402f1155e 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -32287,6 +32287,34 @@ paths: tags: - Security Monitoring x-codegen-request-body-name: body + /api/v2/security_monitoring/rules/validation: + post: + description: Validate a detection rule. + operationId: ValidateSecurityMonitoringRule + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SecurityMonitoringRuleCreatePayload' + required: true + responses: + '204': + description: OK + '400': + $ref: '#/components/responses/BadRequestResponse' + '403': + $ref: '#/components/responses/NotAuthorizedResponse' + '429': + $ref: '#/components/responses/TooManyRequestsResponse' + security: + - apiKeyAuth: [] + appKeyAuth: [] + - AuthZ: + - security_monitoring_rules_write + summary: Validate a detection rule + tags: + - Security Monitoring + x-codegen-request-body-name: body /api/v2/security_monitoring/rules/{rule_id}: delete: description: Delete an existing rule. Default rules cannot be deleted. diff --git a/examples/v2/security-monitoring/ValidateSecurityMonitoringRule.java b/examples/v2/security-monitoring/ValidateSecurityMonitoringRule.java new file mode 100644 index 00000000000..4465129c5e7 --- /dev/null +++ b/examples/v2/security-monitoring/ValidateSecurityMonitoringRule.java @@ -0,0 +1,66 @@ +// Validate a detection rule returns "OK" response + +import com.datadog.api.client.ApiClient; +import com.datadog.api.client.ApiException; +import com.datadog.api.client.v2.api.SecurityMonitoringApi; +import com.datadog.api.client.v2.model.SecurityMonitoringRuleCaseCreate; +import com.datadog.api.client.v2.model.SecurityMonitoringRuleCreatePayload; +import com.datadog.api.client.v2.model.SecurityMonitoringRuleDetectionMethod; +import com.datadog.api.client.v2.model.SecurityMonitoringRuleEvaluationWindow; +import com.datadog.api.client.v2.model.SecurityMonitoringRuleKeepAlive; +import com.datadog.api.client.v2.model.SecurityMonitoringRuleMaxSignalDuration; +import com.datadog.api.client.v2.model.SecurityMonitoringRuleOptions; +import com.datadog.api.client.v2.model.SecurityMonitoringRuleQueryAggregation; +import com.datadog.api.client.v2.model.SecurityMonitoringRuleSeverity; +import com.datadog.api.client.v2.model.SecurityMonitoringRuleTypeCreate; +import com.datadog.api.client.v2.model.SecurityMonitoringStandardRuleCreatePayload; +import com.datadog.api.client.v2.model.SecurityMonitoringStandardRuleQuery; +import java.util.Arrays; +import java.util.Collections; + +public class Example { + public static void main(String[] args) { + ApiClient defaultClient = ApiClient.getDefaultApiClient(); + SecurityMonitoringApi apiInstance = new SecurityMonitoringApi(defaultClient); + + SecurityMonitoringRuleCreatePayload body = + new SecurityMonitoringRuleCreatePayload( + new SecurityMonitoringStandardRuleCreatePayload() + .cases( + Collections.singletonList( + new SecurityMonitoringRuleCaseCreate() + .name("") + .status(SecurityMonitoringRuleSeverity.INFO) + .condition("a > 0"))) + .hasExtendedTitle(true) + .isEnabled(true) + .message("My security monitoring rule") + .name("My security monitoring rule") + .options( + new SecurityMonitoringRuleOptions() + .evaluationWindow(SecurityMonitoringRuleEvaluationWindow.THIRTY_MINUTES) + .keepAlive(SecurityMonitoringRuleKeepAlive.THIRTY_MINUTES) + .maxSignalDuration(SecurityMonitoringRuleMaxSignalDuration.THIRTY_MINUTES) + .detectionMethod(SecurityMonitoringRuleDetectionMethod.THRESHOLD)) + .queries( + Collections.singletonList( + new SecurityMonitoringStandardRuleQuery() + .query("source:source_here") + .groupByFields(Collections.singletonList("@userIdentity.assumed_role")) + .aggregation(SecurityMonitoringRuleQueryAggregation.COUNT) + .name(""))) + .tags(Arrays.asList("env:prod", "team:security")) + .type(SecurityMonitoringRuleTypeCreate.LOG_DETECTION)); + + try { + apiInstance.validateSecurityMonitoringRule(body); + } catch (ApiException e) { + System.err.println( + "Exception when calling SecurityMonitoringApi#validateSecurityMonitoringRule"); + System.err.println("Status code: " + e.getCode()); + System.err.println("Reason: " + e.getResponseBody()); + System.err.println("Response headers: " + e.getResponseHeaders()); + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/datadog/api/client/v2/api/SecurityMonitoringApi.java b/src/main/java/com/datadog/api/client/v2/api/SecurityMonitoringApi.java index 5ecdf113a97..71ad712c39e 100644 --- a/src/main/java/com/datadog/api/client/v2/api/SecurityMonitoringApi.java +++ b/src/main/java/com/datadog/api/client/v2/api/SecurityMonitoringApi.java @@ -4344,4 +4344,137 @@ public SecurityMonitoringSuppressionResponse updateSecurityMonitoringSuppression false, new GenericType() {}); } + + /** + * Validate a detection rule. + * + *

See {@link #validateSecurityMonitoringRuleWithHttpInfo}. + * + * @param body (required) + * @throws ApiException if fails to make API call + */ + public void validateSecurityMonitoringRule(SecurityMonitoringRuleCreatePayload body) + throws ApiException { + validateSecurityMonitoringRuleWithHttpInfo(body); + } + + /** + * Validate a detection rule. + * + *

See {@link #validateSecurityMonitoringRuleWithHttpInfoAsync}. + * + * @param body (required) + * @return CompletableFuture + */ + public CompletableFuture validateSecurityMonitoringRuleAsync( + SecurityMonitoringRuleCreatePayload body) { + return validateSecurityMonitoringRuleWithHttpInfoAsync(body) + .thenApply( + response -> { + return response.getData(); + }); + } + + /** + * Validate a detection rule. + * + * @param body (required) + * @return ApiResponse<Void> + * @throws ApiException if fails to make API call + * @http.response.details + * + * + * + * + * + * + * + *
Response details
Status Code Description Response Headers
204 OK -
400 Bad Request -
403 Not Authorized -
429 Too many requests -
+ */ + public ApiResponse validateSecurityMonitoringRuleWithHttpInfo( + SecurityMonitoringRuleCreatePayload body) throws ApiException { + Object localVarPostBody = body; + + // verify the required parameter 'body' is set + if (body == null) { + throw new ApiException( + 400, "Missing the required parameter 'body' when calling validateSecurityMonitoringRule"); + } + // create path and map variables + String localVarPath = "/api/v2/security_monitoring/rules/validation"; + + Map localVarHeaderParams = new HashMap(); + + Invocation.Builder builder = + apiClient.createBuilder( + "v2.SecurityMonitoringApi.validateSecurityMonitoringRule", + localVarPath, + new ArrayList(), + localVarHeaderParams, + new HashMap(), + new String[] {"*/*"}, + new String[] {"AuthZ", "apiKeyAuth", "appKeyAuth"}); + return apiClient.invokeAPI( + "POST", + builder, + localVarHeaderParams, + new String[] {"application/json"}, + localVarPostBody, + new HashMap(), + false, + null); + } + + /** + * Validate a detection rule. + * + *

See {@link #validateSecurityMonitoringRuleWithHttpInfo}. + * + * @param body (required) + * @return CompletableFuture<ApiResponse<Void>> + */ + public CompletableFuture> validateSecurityMonitoringRuleWithHttpInfoAsync( + SecurityMonitoringRuleCreatePayload body) { + Object localVarPostBody = body; + + // verify the required parameter 'body' is set + if (body == null) { + CompletableFuture> result = new CompletableFuture<>(); + result.completeExceptionally( + new ApiException( + 400, + "Missing the required parameter 'body' when calling validateSecurityMonitoringRule")); + return result; + } + // create path and map variables + String localVarPath = "/api/v2/security_monitoring/rules/validation"; + + Map localVarHeaderParams = new HashMap(); + + Invocation.Builder builder; + try { + builder = + apiClient.createBuilder( + "v2.SecurityMonitoringApi.validateSecurityMonitoringRule", + localVarPath, + new ArrayList(), + localVarHeaderParams, + new HashMap(), + new String[] {"*/*"}, + new String[] {"AuthZ", "apiKeyAuth", "appKeyAuth"}); + } catch (ApiException ex) { + CompletableFuture> result = new CompletableFuture<>(); + result.completeExceptionally(ex); + return result; + } + return apiClient.invokeAPIAsync( + "POST", + builder, + localVarHeaderParams, + new String[] {"application/json"}, + localVarPostBody, + new HashMap(), + false, + null); + } } diff --git a/src/test/resources/cassettes/features/v2/Validate_a_detection_rule_returns_Bad_Request_response.freeze b/src/test/resources/cassettes/features/v2/Validate_a_detection_rule_returns_Bad_Request_response.freeze new file mode 100644 index 00000000000..3275c21e8bf --- /dev/null +++ b/src/test/resources/cassettes/features/v2/Validate_a_detection_rule_returns_Bad_Request_response.freeze @@ -0,0 +1 @@ +2024-03-27T16:23:09.814Z \ No newline at end of file diff --git a/src/test/resources/cassettes/features/v2/Validate_a_detection_rule_returns_Bad_Request_response.json b/src/test/resources/cassettes/features/v2/Validate_a_detection_rule_returns_Bad_Request_response.json new file mode 100644 index 00000000000..31bce9aa282 --- /dev/null +++ b/src/test/resources/cassettes/features/v2/Validate_a_detection_rule_returns_Bad_Request_response.json @@ -0,0 +1,32 @@ +[ + { + "httpRequest": { + "body": { + "type": "JSON", + "json": "{\"cases\":[{\"condition\":\"a > 0\",\"name\":\"\",\"notifications\":[],\"status\":\"info\"}],\"hasExtendedTitle\":true,\"isEnabled\":true,\"message\":\"My security monitoring rule\",\"name\":\"My security monitoring rule\",\"options\":{\"detectionMethod\":\"threshold\",\"evaluationWindow\":1800,\"keepAlive\":999999,\"maxSignalDuration\":1800},\"queries\":[{\"aggregation\":\"count\",\"distinctFields\":[],\"groupByFields\":[\"@userIdentity.assumed_role\"],\"name\":\"\",\"query\":\"source:source_here\"}],\"tags\":[\"env:prod\",\"team:security\"],\"type\":\"log_detection\"}" + }, + "headers": {}, + "method": "POST", + "path": "/api/v2/security_monitoring/rules/validation", + "keepAlive": false, + "secure": true + }, + "httpResponse": { + "body": "{\"error\":{\"code\":\"InvalidArgument\",\"message\":\"Invalid rule configuration\",\"details\":[{\"code\":\"InvalidArgument\",\"message\":\"Max signal duration must be greater than or equal to keep alive\",\"target\":\"maxSignalDuration\"},{\"code\":\"InvalidArgument\",\"message\":\"Keep alive is not in allowed durations: 0, 1, 5, 10, 15, 30, 60, 120, 180, 360 (in minutes)\",\"target\":\"keepAlive\"}]}}\n", + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "statusCode": 400, + "reasonPhrase": "Bad Request" + }, + "times": { + "remainingTimes": 1 + }, + "timeToLive": { + "unlimited": true + }, + "id": "195f214f-cab0-861b-1336-ce2aa07b9cf5" + } +] \ No newline at end of file diff --git a/src/test/resources/cassettes/features/v2/Validate_a_detection_rule_returns_OK_response.freeze b/src/test/resources/cassettes/features/v2/Validate_a_detection_rule_returns_OK_response.freeze new file mode 100644 index 00000000000..f502e40803a --- /dev/null +++ b/src/test/resources/cassettes/features/v2/Validate_a_detection_rule_returns_OK_response.freeze @@ -0,0 +1 @@ +2024-03-27T16:23:10.157Z \ No newline at end of file diff --git a/src/test/resources/cassettes/features/v2/Validate_a_detection_rule_returns_OK_response.json b/src/test/resources/cassettes/features/v2/Validate_a_detection_rule_returns_OK_response.json new file mode 100644 index 00000000000..8070d7281b9 --- /dev/null +++ b/src/test/resources/cassettes/features/v2/Validate_a_detection_rule_returns_OK_response.json @@ -0,0 +1,31 @@ +[ + { + "httpRequest": { + "body": { + "type": "JSON", + "json": "{\"cases\":[{\"condition\":\"a > 0\",\"name\":\"\",\"notifications\":[],\"status\":\"info\"}],\"hasExtendedTitle\":true,\"isEnabled\":true,\"message\":\"My security monitoring rule\",\"name\":\"My security monitoring rule\",\"options\":{\"detectionMethod\":\"threshold\",\"evaluationWindow\":1800,\"keepAlive\":1800,\"maxSignalDuration\":1800},\"queries\":[{\"aggregation\":\"count\",\"distinctFields\":[],\"groupByFields\":[\"@userIdentity.assumed_role\"],\"name\":\"\",\"query\":\"source:source_here\"}],\"tags\":[\"env:prod\",\"team:security\"],\"type\":\"log_detection\"}" + }, + "headers": {}, + "method": "POST", + "path": "/api/v2/security_monitoring/rules/validation", + "keepAlive": false, + "secure": true + }, + "httpResponse": { + "headers": { + "Content-Type": [ + "text/html; charset=utf-8" + ] + }, + "statusCode": 204, + "reasonPhrase": "No Content" + }, + "times": { + "remainingTimes": 1 + }, + "timeToLive": { + "unlimited": true + }, + "id": "eff24aa1-fc7c-d68e-5815-6e52bbac0e73" + } +] \ No newline at end of file diff --git a/src/test/resources/com/datadog/api/client/v2/api/security_monitoring.feature b/src/test/resources/com/datadog/api/client/v2/api/security_monitoring.feature index 19a88c9b51e..b505f2a4fcb 100644 --- a/src/test/resources/com/datadog/api/client/v2/api/security_monitoring.feature +++ b/src/test/resources/com/datadog/api/client/v2/api/security_monitoring.feature @@ -606,3 +606,17 @@ Feature: Security Monitoring Then the response status is 200 OK And the response "name" is equal to "{{ unique }}-Updated" And the response "id" has the same value as "security_rule.id" + + @skip-go @skip-java @skip-python @skip-ruby @skip-rust @skip-typescript @skip-validation @team:DataDog/k9-cloud-security-platform + Scenario: Validate a detection rule returns "Bad Request" response + Given new "ValidateSecurityMonitoringRule" request + And body with value {"cases":[{"name":"","status":"info","notifications":[],"condition":"a > 0"}],"hasExtendedTitle":true,"isEnabled":true,"message":"My security monitoring rule","name":"My security monitoring rule","options":{"evaluationWindow":1800,"keepAlive":999999,"maxSignalDuration":1800,"detectionMethod":"threshold"},"queries":[{"query":"source:source_here","groupByFields":["@userIdentity.assumed_role"],"distinctFields":[],"aggregation":"count","name":""}],"tags":["env:prod","team:security"],"type":"log_detection"} + When the request is sent + Then the response status is 400 Bad Request + + @team:DataDog/k9-cloud-security-platform + Scenario: Validate a detection rule returns "OK" response + Given new "ValidateSecurityMonitoringRule" request + And body with value {"cases":[{"name":"","status":"info","notifications":[],"condition":"a > 0"}],"hasExtendedTitle":true,"isEnabled":true,"message":"My security monitoring rule","name":"My security monitoring rule","options":{"evaluationWindow":1800,"keepAlive":1800,"maxSignalDuration":1800,"detectionMethod":"threshold"},"queries":[{"query":"source:source_here","groupByFields":["@userIdentity.assumed_role"],"distinctFields":[],"aggregation":"count","name":""}],"tags":["env:prod","team:security"],"type":"log_detection"} + When the request is sent + Then the response status is 204 OK diff --git a/src/test/resources/com/datadog/api/client/v2/api/undo.json b/src/test/resources/com/datadog/api/client/v2/api/undo.json index f1ce400479c..8fdb1cd7bec 100644 --- a/src/test/resources/com/datadog/api/client/v2/api/undo.json +++ b/src/test/resources/com/datadog/api/client/v2/api/undo.json @@ -1751,6 +1751,12 @@ "type": "unsafe" } }, + "ValidateSecurityMonitoringRule": { + "tag": "Security Monitoring", + "undo": { + "type": "idempotent" + } + }, "DeleteSecurityMonitoringRule": { "tag": "Security Monitoring", "undo": {