Skip to content

Commit 09eaab9

Browse files
committed
alertFilters: Add param descriptions for Web API
Signed-off-by: kingthorin <[email protected]>
1 parent bdf2d49 commit 09eaab9

File tree

4 files changed

+246
-3
lines changed

4 files changed

+246
-3
lines changed

addOns/alertFilters/CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ All notable changes to this add-on will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
55

66
## Unreleased
7-
7+
### Added
8+
- Added parameter descriptions for the ZAP API.
89

910
## [23] - 2025-01-09
1011
### Changed

addOns/alertFilters/src/main/java/org/zaproxy/zap/extension/alertFilters/AlertFilterAPI.java

+5
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,11 @@ public String getPrefix() {
207207
return PREFIX;
208208
}
209209

210+
@Override
211+
protected String getI18nPrefix() {
212+
return ExtensionAlertFilters.PREFIX;
213+
}
214+
210215
@Override
211216
public ApiResponse handleApiView(String name, JSONObject params) throws ApiException {
212217
LOGGER.debug("handleApiView {} {}", name, params);

addOns/alertFilters/src/main/resources/org/zaproxy/zap/extension/alertFilters/resources/Messages.properties

+57-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,69 @@
1-
alertFilters.api.action.addAlertFilter = Adds a new alert filter for the context with the given ID.
2-
alertFilters.api.action.addGlobalAlertFilter = Adds a new global alert filter.
1+
alertFilter.api.desc = Test
2+
alertFilters.api.action.addAlertFilter = Adds a new alert filter for the context with the given ID.
3+
alertFilters.api.action.addAlertFilter.param.attack = The attack value for which the filter should apply (can be regex).
4+
alertFilters.api.action.addAlertFilter.param.attackIsRegex = A boolean indicating whether or not the attack value is a regex.
5+
alertFilters.api.action.addAlertFilter.param.contextId = The numeric ID of the context for which the filter should be added.
6+
alertFilters.api.action.addAlertFilter.param.enabled = A boolean indicating whether or not the filter should be enabled.
7+
alertFilters.api.action.addAlertFilter.param.evidence = The evidence value for which the filter should apply (can be regex).
8+
alertFilters.api.action.addAlertFilter.param.evidenceIsRegex = A boolean indicating whether or not the evidence value is a regex.
9+
alertFilters.api.action.addAlertFilter.param.methods = The HTTP methods (comma separated) for which the filter should apply.
10+
alertFilters.api.action.addAlertFilter.param.newLevel = The numeric risk representation ('0 - Informational' through '3 - High') ['-1 - False Positive'].
11+
alertFilters.api.action.addAlertFilter.param.parameter = The parameter name for which the filter should apply (can be regex).
12+
alertFilters.api.action.addAlertFilter.param.parameterIsRegex = A boolean indicating whether or not the parameter name is a regex.
13+
alertFilters.api.action.addAlertFilter.param.ruleId = The numeric ID of the rule for which the filter should apply.
14+
alertFilters.api.action.addAlertFilter.param.url = The URL for which the filter should apply (can be regex).
15+
alertFilters.api.action.addAlertFilter.param.urlIsRegex = A boolean indicating whether or not the URL is a regex.
16+
alertFilters.api.action.addGlobalAlertFilter = Adds a new global alert filter.
17+
alertFilters.api.action.addGlobalAlertFilter.param.attack = The attack value for which the filter should apply (can be regex).
18+
alertFilters.api.action.addGlobalAlertFilter.param.attackIsRegex = A boolean indicating whether or not the attack value is a regex.
19+
alertFilters.api.action.addGlobalAlertFilter.param.contextId = The numeric ID of the context for which the filter should be added.
20+
alertFilters.api.action.addGlobalAlertFilter.param.enabled = A boolean indicating whether or not the filter should be enabled.
21+
alertFilters.api.action.addGlobalAlertFilter.param.evidence = The evidence value for which the filter should apply (can be regex).
22+
alertFilters.api.action.addGlobalAlertFilter.param.evidenceIsRegex = A boolean indicating whether or not the evidence value is a regex.
23+
alertFilters.api.action.addGlobalAlertFilter.param.methods = The HTTP methods (comma separated) for which the filter should apply.
24+
alertFilters.api.action.addGlobalAlertFilter.param.newLevel = The numeric risk representation ('0 - Informational' through '3 - High') ['-1 - False Positive'].
25+
alertFilters.api.action.addGlobalAlertFilter.param.parameter = The parameter name for which the filter should apply (can be regex).
26+
alertFilters.api.action.addGlobalAlertFilter.param.parameterIsRegex = A boolean indicating whether or not the parameter name is a regex.
27+
alertFilters.api.action.addGlobalAlertFilter.param.ruleId = The numeric ID of the rule for which the filter should apply.
28+
alertFilters.api.action.addGlobalAlertFilter.param.url = The URL for which the filter should apply (can be regex).
29+
alertFilters.api.action.addGlobalAlertFilter.param.urlIsRegex = A boolean indicating whether or not the URL is a regex.
330
alertFilters.api.action.applyAll = Applies all currently enabled Global and Context alert filters.
431
alertFilters.api.action.applyContext = Applies all currently enabled Context alert filters.
532
alertFilters.api.action.applyGlobal = Applies all currently enabled Global alert filters.
633
alertFilters.api.action.removeAlertFilter = Removes an alert filter from the context with the given ID.
34+
alertFilters.api.action.removeAlertFilter.param.attack = The attack value for which the filter applies (can be regex).
35+
alertFilters.api.action.removeAlertFilter.param.attackIsRegex = A boolean indicating whether or not the attack value is a regex.
36+
alertFilters.api.action.removeAlertFilter.param.contextId = The numeric ID of the context for which the filter should be removed.
37+
alertFilters.api.action.removeAlertFilter.param.enabled = A boolean indicating whether or not the filter should be enabled.
38+
alertFilters.api.action.removeAlertFilter.param.evidence = The evidence value for which the filter applies (can be regex).
39+
alertFilters.api.action.removeAlertFilter.param.evidenceIsRegex = A boolean indicating whether or not the evidence value is a regex.
40+
alertFilters.api.action.removeAlertFilter.param.methods = The HTTP methods (comma separated) for which the filter applies.
41+
alertFilters.api.action.removeAlertFilter.param.newLevel = The numeric risk representation ('0 - Informational' through '3 - High') ['-1 - False Positive'].
42+
alertFilters.api.action.removeAlertFilter.param.parameter = The parameter name for which the filter should apply (can be regex).
43+
alertFilters.api.action.removeAlertFilter.param.parameterIsRegex = A boolean indicating whether or not the parameter name is a regex.
44+
alertFilters.api.action.removeAlertFilter.param.ruleId = The numeric ID of the rule for which the filter applies.
45+
alertFilters.api.action.removeAlertFilter.param.url = The URL for which the filter applies (can be regex).
46+
alertFilters.api.action.removeAlertFilter.param.urlIsRegex = A boolean indicating whether or not the URL is a regex.
747
alertFilters.api.action.removeGlobalAlertFilter = Removes a global alert filter.
48+
alertFilters.api.action.removeGlobalAlertFilter.param.attack = The attack value for which the filter applies (can be regex).
49+
alertFilters.api.action.removeGlobalAlertFilter.param.attackIsRegex = A boolean indicating whether or not the attack value is a regex.
50+
alertFilters.api.action.removeGlobalAlertFilter.param.contextId = The numeric ID of the context for which the filter should be removed.
51+
alertFilters.api.action.removeGlobalAlertFilter.param.enabled = A boolean indicating whether or not the filter should be enabled.
52+
alertFilters.api.action.removeGlobalAlertFilter.param.evidence = The evidence value for which the filter applies (can be regex).
53+
alertFilters.api.action.removeGlobalAlertFilter.param.evidenceIsRegex = A boolean indicating whether or not the evidence value is a regex.
54+
alertFilters.api.action.removeGlobalAlertFilter.param.methods = The HTTP methods (comma separated) for which the filter applies.
55+
alertFilters.api.action.removeGlobalAlertFilter.param.newLevel = The numeric risk representation ('0 - Informational' through '3 - High') ['-1 - False Positive'].
56+
alertFilters.api.action.removeGlobalAlertFilter.param.parameter = The parameter name for which the filter should apply (can be regex).
57+
alertFilters.api.action.removeGlobalAlertFilter.param.parameterIsRegex = A boolean indicating whether or not the parameter name is a regex.
58+
alertFilters.api.action.removeGlobalAlertFilter.param.ruleId = The numeric ID of the rule for which the filter applies.
59+
alertFilters.api.action.removeGlobalAlertFilter.param.url = The URL for which the filter applies (can be regex).
60+
alertFilters.api.action.removeGlobalAlertFilter.param.urlIsRegex = A boolean indicating whether or not the URL is a regex.
861
alertFilters.api.action.testAll = Tests all currently enabled Global and Context alert filters.
962
alertFilters.api.action.testContext = Tests all currently enabled Context alert filters.
1063
alertFilters.api.action.testGlobal = Tests all currently enabled Global alert filters.
64+
alertFilters.api.desc = Facilitates the configuration and use of Alert Filters functionality.
1165
alertFilters.api.view.alertFilterList = Lists the alert filters of the context with the given ID.
66+
alertFilters.api.view.alertFilterList.param.contextId = The numeric ID of the context for which the filters should be listed.
1267
alertFilters.api.view.globalAlertFilterList = Lists the global alert filters.
1368

1469
alertFilters.automation.desc = Alert Filters Automation Framework Integration
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/*
2+
* Zed Attack Proxy (ZAP) and its related class files.
3+
*
4+
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
5+
*
6+
* Copyright 2025 The ZAP Development Team
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
package org.zaproxy.zap.extension.alertFilters;
21+
22+
import static org.hamcrest.MatcherAssert.assertThat;
23+
import static org.hamcrest.Matchers.empty;
24+
import static org.hamcrest.Matchers.emptyString;
25+
import static org.hamcrest.Matchers.equalTo;
26+
import static org.hamcrest.Matchers.hasSize;
27+
import static org.hamcrest.Matchers.is;
28+
import static org.hamcrest.Matchers.not;
29+
import static org.junit.jupiter.api.Assertions.assertThrows;
30+
31+
import java.util.ArrayList;
32+
import java.util.List;
33+
import net.sf.json.JSONObject;
34+
import org.junit.jupiter.api.AfterAll;
35+
import org.junit.jupiter.api.BeforeEach;
36+
import org.junit.jupiter.api.Test;
37+
import org.junit.jupiter.params.ParameterizedTest;
38+
import org.junit.jupiter.params.provider.EmptySource;
39+
import org.junit.jupiter.params.provider.ValueSource;
40+
import org.parosproxy.paros.Constant;
41+
import org.parosproxy.paros.network.HttpMessage;
42+
import org.zaproxy.zap.extension.api.API;
43+
import org.zaproxy.zap.extension.api.API.RequestType;
44+
import org.zaproxy.zap.extension.api.ApiElement;
45+
import org.zaproxy.zap.extension.api.ApiException;
46+
import org.zaproxy.zap.extension.api.ApiImplementor;
47+
import org.zaproxy.zap.extension.api.ApiParameter;
48+
import org.zaproxy.zap.testutils.TestUtils;
49+
50+
/** Unit test for {@link AlertFilterAPI}. */
51+
class AlertFilterApiUnitTest extends TestUtils {
52+
53+
private AlertFilterAPI alertFiltersApi;
54+
55+
@BeforeEach
56+
void setUp() {
57+
mockMessages(new ExtensionAlertFilters());
58+
59+
alertFiltersApi = new AlertFilterAPI();
60+
}
61+
62+
@AfterAll
63+
static void cleanUp() {
64+
Constant.messages = null;
65+
}
66+
67+
@Test
68+
void shouldHavePrefix() {
69+
// Given / When
70+
String prefix = alertFiltersApi.getPrefix();
71+
// Then
72+
assertThat(prefix, is(equalTo("alertFilter")));
73+
}
74+
75+
@Test
76+
void shouldAddApiElements() {
77+
// Given / When
78+
alertFiltersApi = new AlertFilterAPI();
79+
// Then
80+
assertThat(alertFiltersApi.getApiActions(), hasSize(10));
81+
assertThat(alertFiltersApi.getApiViews(), hasSize(2));
82+
assertThat(alertFiltersApi.getApiOthers(), hasSize(0));
83+
}
84+
85+
@ParameterizedTest
86+
@EmptySource
87+
@ValueSource(strings = {"unknown", "something"})
88+
void shouldThrowApiExceptionForUnknownAction(String name) {
89+
// Given
90+
JSONObject params = new JSONObject();
91+
// When
92+
ApiException exception =
93+
assertThrows(
94+
ApiException.class, () -> alertFiltersApi.handleApiAction(name, params));
95+
// Then
96+
assertThat(exception.getType(), is(equalTo(ApiException.Type.BAD_ACTION)));
97+
}
98+
99+
@ParameterizedTest
100+
@EmptySource
101+
@ValueSource(strings = {"unknown", "something"})
102+
void shouldThrowApiExceptionForUnknownOther(String name) {
103+
// Given
104+
HttpMessage message = new HttpMessage();
105+
JSONObject params = new JSONObject();
106+
// When
107+
ApiException exception =
108+
assertThrows(
109+
ApiException.class,
110+
() -> alertFiltersApi.handleApiOther(message, name, params));
111+
// Then
112+
assertThat(exception.getType(), is(equalTo(ApiException.Type.BAD_OTHER)));
113+
}
114+
115+
@ParameterizedTest
116+
@EmptySource
117+
@ValueSource(strings = {"unknown", "something"})
118+
void shouldThrowApiExceptionForUnknownView(String name) {
119+
// Given
120+
JSONObject params = new JSONObject();
121+
// When
122+
ApiException exception =
123+
assertThrows(ApiException.class, () -> alertFiltersApi.handleApiView(name, params));
124+
// Then
125+
assertThat(exception.getType(), is(equalTo(ApiException.Type.BAD_VIEW)));
126+
}
127+
128+
@Test
129+
void shouldHaveDescriptionsForAllApiElements() {
130+
alertFiltersApi = new AlertFilterAPI();
131+
List<String> missingKeys = new ArrayList<>();
132+
List<String> missingDescriptions = new ArrayList<>();
133+
checkKey(alertFiltersApi.getDescriptionKey(), missingKeys, missingDescriptions);
134+
checkApiElements(
135+
alertFiltersApi,
136+
alertFiltersApi.getApiActions(),
137+
API.RequestType.action,
138+
missingKeys,
139+
missingDescriptions);
140+
checkApiElements(
141+
alertFiltersApi,
142+
alertFiltersApi.getApiOthers(),
143+
API.RequestType.other,
144+
missingKeys,
145+
missingDescriptions);
146+
checkApiElements(
147+
alertFiltersApi,
148+
alertFiltersApi.getApiViews(),
149+
API.RequestType.view,
150+
missingKeys,
151+
missingDescriptions);
152+
assertThat(missingKeys, is(empty()));
153+
assertThat(missingDescriptions, is(empty()));
154+
}
155+
156+
private static void checkKey(String key, List<String> missingKeys, List<String> missingDescs) {
157+
if (!Constant.messages.containsKey(key)) {
158+
missingKeys.add(key);
159+
} else if (Constant.messages.getString(key).isBlank()) {
160+
missingDescs.add(key);
161+
}
162+
}
163+
164+
private static void checkApiElements(
165+
ApiImplementor api,
166+
List<? extends ApiElement> elements,
167+
RequestType type,
168+
List<String> missingKeys,
169+
List<String> missingDescriptions) {
170+
elements.sort((a, b) -> a.getName().compareTo(b.getName()));
171+
for (ApiElement element : elements) {
172+
assertThat(
173+
"API " + type + " element: " + api.getPrefix() + "/" + element.getName(),
174+
element.getDescriptionTag(),
175+
is(not(emptyString())));
176+
checkKey(element.getDescriptionTag(), missingKeys, missingDescriptions);
177+
element.getParameters().stream()
178+
.map(ApiParameter::getDescriptionKey)
179+
.forEach(key -> checkKey(key, missingKeys, missingDescriptions));
180+
}
181+
}
182+
}

0 commit comments

Comments
 (0)