diff --git a/.changelog/1422.txt b/.changelog/1422.txt new file mode 100644 index 00000000000..20d26bcc199 --- /dev/null +++ b/.changelog/1422.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +api_shield_schema: Add support for Get/Update API Shield Operation Schema Validation Settings +``` diff --git a/api_shield_schemas.go b/api_shield_schemas.go index 1c4508fdafd..804181d8665 100644 --- a/api_shield_schemas.go +++ b/api_shield_schemas.go @@ -414,3 +414,92 @@ func (api *API) UpdateAPIShieldSchemaValidationSettings(ctx context.Context, rc return &asResponse.Result, nil } + +// APIShieldOperationSchemaValidationSettings represents operation level schema validation settings for +// API Shield Schema Validation 2.0. +type APIShieldOperationSchemaValidationSettings struct { + // MitigationAction is the mitigation to apply to the operation + MitigationAction *string `json:"mitigation_action" url:"-"` +} + +// GetAPIShieldOperationSchemaValidationSettingsParams represents the parameters to pass to retrieve +// the schema validation settings set on the operation. +// +// API documentation: https://developers.cloudflare.com/api/operations/api-shield-schema-validation-retrieve-operation-level-settings +type GetAPIShieldOperationSchemaValidationSettingsParams struct { + // The Operation ID to apply the mitigation action to + OperationID string `url:"-"` +} + +// UpdateAPIShieldOperationSchemaValidationSettings maps operation IDs to APIShieldOperationSchemaValidationSettings +// +// # This can be used to bulk update operations in one call +// +// Example: +// +// UpdateAPIShieldOperationSchemaValidationSettings{ +// "99522293-a505-45e5-bbad-bbc339f5dc40": APIShieldOperationSchemaValidationSettings{ MitigationAction: nil }, +// } +// +// API documentation: https://developers.cloudflare.com/api/operations/api-shield-schema-validation-update-multiple-operation-level-settings +type UpdateAPIShieldOperationSchemaValidationSettings map[string]APIShieldOperationSchemaValidationSettings + +// APIShieldOperationSchemaValidationSettingsResponse represents the response from the GET api_gateway/operation/{operationID}/schema_validation endpoint. +type APIShieldOperationSchemaValidationSettingsResponse struct { + Result APIShieldOperationSchemaValidationSettings `json:"result"` + Response +} + +// UpdateAPIShieldOperationSchemaValidationSettingsResponse represents the response from the PATCH api_gateway/operations/schema_validation endpoint. +type UpdateAPIShieldOperationSchemaValidationSettingsResponse struct { + Result UpdateAPIShieldOperationSchemaValidationSettings `json:"result"` + Response +} + +// GetAPIShieldOperationSchemaValidationSettings retrieves operation level schema validation settings +// +// API documentation: https://developers.cloudflare.com/api/operations/api-shield-schema-validation-retrieve-operation-level-settings +func (api *API) GetAPIShieldOperationSchemaValidationSettings(ctx context.Context, rc *ResourceContainer, params GetAPIShieldOperationSchemaValidationSettingsParams) (*APIShieldOperationSchemaValidationSettings, error) { + if params.OperationID == "" { + return nil, fmt.Errorf("operation ID must be provided") + } + + path := fmt.Sprintf("/zones/%s/api_gateway/operations/%s/schema_validation", rc.Identifier, params.OperationID) + + uri := buildURI(path, nil) + + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, params) + if err != nil { + return nil, err + } + + var asResponse APIShieldOperationSchemaValidationSettingsResponse + err = json.Unmarshal(res, &asResponse) + if err != nil { + return nil, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + return &asResponse.Result, nil +} + +// UpdateAPIShieldOperationSchemaValidationSettings update multiple operation level schema validation settings +// +// API documentation: https://developers.cloudflare.com/api/operations/api-shield-schema-validation-update-multiple-operation-level-settings +func (api *API) UpdateAPIShieldOperationSchemaValidationSettings(ctx context.Context, rc *ResourceContainer, params UpdateAPIShieldOperationSchemaValidationSettings) (*UpdateAPIShieldOperationSchemaValidationSettings, error) { + path := fmt.Sprintf("/zones/%s/api_gateway/operations/schema_validation", rc.Identifier) + + uri := buildURI(path, nil) + + res, err := api.makeRequestContext(ctx, http.MethodPatch, uri, params) + if err != nil { + return nil, err + } + + var asResponse UpdateAPIShieldOperationSchemaValidationSettingsResponse + err = json.Unmarshal(res, &asResponse) + if err != nil { + return nil, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + return &asResponse.Result, nil +} diff --git a/api_shield_schemas_test.go b/api_shield_schemas_test.go index 2cde17e593d..00514eaa60f 100644 --- a/api_shield_schemas_test.go +++ b/api_shield_schemas_test.go @@ -580,3 +580,90 @@ func TestUpdateAPIShieldSchemaValidationSettings(t *testing.T) { assert.Equal(t, expected, actual) } } + +func TestGetAPIShieldOperationSchemaValidationSettings(t *testing.T) { + endpoint := fmt.Sprintf("/zones/%s/api_gateway/operations/%s/schema_validation", testZoneID, testAPIShieldOperationId) + response := `{ + "success" : true, + "errors": [], + "messages": [], + "result": { + "mitigation_action": "log" + } + }` + + setup() + t.Cleanup(teardown) + handler := func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + require.Empty(t, r.URL.Query()) + w.Header().Set("content-type", "application/json") + fmt.Fprint(w, response) + } + + mux.HandleFunc(endpoint, handler) + + actual, err := client.GetAPIShieldOperationSchemaValidationSettings( + context.Background(), + ZoneIdentifier(testZoneID), + GetAPIShieldOperationSchemaValidationSettingsParams{OperationID: testAPIShieldOperationId}, + ) + + log := "log" + expected := &APIShieldOperationSchemaValidationSettings{ + MitigationAction: &log, + } + + if assert.NoError(t, err) { + assert.Equal(t, expected, actual) + } +} + +func TestUpdateAPIShieldOperationSchemaValidationSettings(t *testing.T) { + endpoint := fmt.Sprintf("/zones/%s/api_gateway/operations/schema_validation", testZoneID) + response := fmt.Sprintf(`{ + "success" : true, + "errors": [], + "messages": [], + "result": { + "%s": null + } + }`, testAPIShieldOperationId) + + setup() + t.Cleanup(teardown) + handler := func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, http.MethodPatch, r.Method, "Expected method 'PATCH', got %s", r.Method) + require.Empty(t, r.URL.Query()) + + body, err := io.ReadAll(r.Body) + require.NoError(t, err) + expected := fmt.Sprintf(`{"%s":{"mitigation_action":null}}`, testAPIShieldOperationId) + require.Equal(t, expected, string(body)) + + w.Header().Set("content-type", "application/json") + fmt.Fprint(w, response) + } + + mux.HandleFunc(endpoint, handler) + + actual, err := client.UpdateAPIShieldOperationSchemaValidationSettings( + context.Background(), + ZoneIdentifier(testZoneID), + UpdateAPIShieldOperationSchemaValidationSettings{ + testAPIShieldOperationId: APIShieldOperationSchemaValidationSettings{ + MitigationAction: nil, + }, + }, + ) + + expected := &UpdateAPIShieldOperationSchemaValidationSettings{ + testAPIShieldOperationId: APIShieldOperationSchemaValidationSettings{ + MitigationAction: nil, + }, + } + + if assert.NoError(t, err) { + assert.Equal(t, expected, actual) + } +}