Skip to content

Commit 56421d2

Browse files
authored
Merge pull request #6748 from ricekot/graaljs/scan-rule-script-tests
2 parents 74934c2 + 633576d commit 56421d2

File tree

8 files changed

+378
-27
lines changed

8 files changed

+378
-27
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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.graaljs;
21+
22+
import static org.hamcrest.MatcherAssert.assertThat;
23+
import static org.hamcrest.Matchers.emptyOrNullString;
24+
import static org.hamcrest.Matchers.equalTo;
25+
import static org.hamcrest.Matchers.hasSize;
26+
import static org.hamcrest.Matchers.is;
27+
import static org.hamcrest.Matchers.not;
28+
29+
import java.nio.file.Path;
30+
import java.util.Map;
31+
import java.util.ResourceBundle;
32+
import org.junit.jupiter.api.Test;
33+
import org.parosproxy.paros.core.scanner.Alert;
34+
35+
class ActiveDefaultTemplateGraalJsScriptTest extends GraalJsActiveScriptScanRuleTestUtils {
36+
@Override
37+
public Path getScriptPath() throws Exception {
38+
return Path.of(
39+
getClass()
40+
.getResource("/scripts/templates/active/Active default template GraalJS.js")
41+
.toURI());
42+
}
43+
44+
@Override
45+
protected boolean isIgnoreAlertsRaisedInSendReasonableNumberOfMessages() {
46+
return true;
47+
}
48+
49+
@Override
50+
public void shouldHaveI18nNonEmptyName(String name, ResourceBundle extensionResourceBundle) {
51+
assertThat(name, is(not(emptyOrNullString())));
52+
}
53+
54+
@Test
55+
void shouldRaiseAlert() throws Exception {
56+
// Given
57+
rule.init(getHttpMessage("/path?param=value"), this.parent);
58+
// When
59+
rule.scan();
60+
// Then
61+
assertThat(alertsRaised, hasSize(1));
62+
Alert alert = alertsRaised.get(0);
63+
assertThat(alert.getPluginId(), is(equalTo(12345)));
64+
assertThat(alert.getAlertRef(), is(equalTo("12345")));
65+
assertThat(alert.getName(), is(equalTo("Active Vulnerability Title")));
66+
assertThat(alert.getDescription(), is(equalTo("Full description")));
67+
assertThat(alert.getSolution(), is(equalTo("The solution")));
68+
assertThat(alert.getReference(), is(equalTo("Reference 1\nReference 2")));
69+
assertThat(alert.getOtherInfo(), is(equalTo("Any other Info")));
70+
assertThat(alert.getRisk(), is(equalTo(Alert.RISK_INFO)));
71+
assertThat(alert.getConfidence(), is(equalTo(Alert.CONFIDENCE_LOW)));
72+
assertThat(alert.getTags(), is(equalTo(Map.of("name1", "value1", "name2", "value2"))));
73+
assertThat(alert.getMsgUri().getPathQuery(), is(equalTo("/path?param=Your attack")));
74+
assertThat(alert.getParam(), is(equalTo("param")));
75+
assertThat(alert.getAttack(), is(equalTo("Your attack")));
76+
assertThat(alert.getEvidence(), is(equalTo("Evidence")));
77+
}
78+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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.graaljs;
21+
22+
import java.util.List;
23+
import org.junit.jupiter.api.BeforeEach;
24+
import org.zaproxy.addon.commonlib.scanrules.ScanRuleMetadata;
25+
import org.zaproxy.addon.commonlib.scanrules.ScanRuleMetadataProvider;
26+
import org.zaproxy.zap.extension.ascan.ExtensionActiveScan;
27+
import org.zaproxy.zap.extension.script.ScriptEngineWrapper;
28+
import org.zaproxy.zap.extension.script.ScriptType;
29+
import org.zaproxy.zap.extension.script.ScriptWrapper;
30+
import org.zaproxy.zap.extension.scripts.scanrules.ActiveScriptScanRule;
31+
import org.zaproxy.zap.testutils.ActiveScannerTestUtils;
32+
import org.zaproxy.zap.testutils.ScriptScanRuleTestUtils;
33+
34+
public abstract class GraalJsActiveScriptScanRuleTestUtils
35+
extends ActiveScannerTestUtils<ActiveScriptScanRule> implements ScriptScanRuleTestUtils {
36+
37+
private final ScriptEngineWrapper scriptEngineWrapper =
38+
new GraalJsEngineWrapper(
39+
GraalJsActiveScriptScanRuleTestUtils.class.getClassLoader(), List.of(), null);
40+
41+
@Override
42+
public ScriptEngineWrapper getScriptEngineWrapper() {
43+
return scriptEngineWrapper;
44+
}
45+
46+
@BeforeEach
47+
@Override
48+
public void setUp() throws Exception {
49+
super.setUp();
50+
setUpExtScript();
51+
}
52+
53+
@Override
54+
public void setUpMessages() {
55+
mockMessages(new ExtensionGraalJs());
56+
}
57+
58+
@Override
59+
protected ActiveScriptScanRule createScanner() {
60+
try {
61+
ScanRuleMetadata metadata =
62+
getScriptInterface(ScanRuleMetadataProvider.class).getMetadata();
63+
var scriptWrapper = new ScriptWrapper();
64+
scriptWrapper.setFile(getScriptPath().toFile());
65+
scriptWrapper.setEngine(scriptEngineWrapper);
66+
scriptWrapper.setType(
67+
new ScriptType(ExtensionActiveScan.SCRIPT_TYPE_ACTIVE, null, null, true));
68+
scriptWrapper.setEnabled(true);
69+
70+
return new ActiveScriptScanRule(scriptWrapper, metadata);
71+
} catch (Exception e) {
72+
throw new RuntimeException("Could not create active scan rule from script", e);
73+
}
74+
}
75+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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.graaljs;
21+
22+
import static org.mockito.Mockito.mock;
23+
24+
import java.util.List;
25+
import org.junit.jupiter.api.BeforeEach;
26+
import org.zaproxy.addon.commonlib.scanrules.ScanRuleMetadataProvider;
27+
import org.zaproxy.zap.extension.script.ScriptEngineWrapper;
28+
import org.zaproxy.zap.extension.script.ScriptWrapper;
29+
import org.zaproxy.zap.extension.scripts.scanrules.PassiveScriptScanRule;
30+
import org.zaproxy.zap.testutils.PassiveScannerTestUtils;
31+
import org.zaproxy.zap.testutils.ScriptScanRuleTestUtils;
32+
33+
public abstract class GraalJsPassiveScriptScanRuleTestUtils
34+
extends PassiveScannerTestUtils<PassiveScriptScanRule> implements ScriptScanRuleTestUtils {
35+
36+
private final ScriptEngineWrapper scriptEngineWrapper =
37+
new GraalJsEngineWrapper(
38+
GraalJsPassiveScriptScanRuleTestUtils.class.getClassLoader(), List.of(), null);
39+
40+
@Override
41+
public ScriptEngineWrapper getScriptEngineWrapper() {
42+
return scriptEngineWrapper;
43+
}
44+
45+
@BeforeEach
46+
@Override
47+
public void setUp() throws Exception {
48+
super.setUp();
49+
setUpExtScript();
50+
}
51+
52+
@Override
53+
public void setUpMessages() {
54+
mockMessages(new ExtensionGraalJs());
55+
}
56+
57+
@Override
58+
protected PassiveScriptScanRule createScanner() {
59+
try {
60+
return new PassiveScriptScanRule(
61+
mock(ScriptWrapper.class),
62+
getScriptInterface(ScanRuleMetadataProvider.class).getMetadata());
63+
} catch (Exception e) {
64+
throw new RuntimeException("Could not create passive scan rule from script", e);
65+
}
66+
}
67+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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.graaljs;
21+
22+
import static org.hamcrest.MatcherAssert.assertThat;
23+
import static org.hamcrest.Matchers.emptyOrNullString;
24+
import static org.hamcrest.Matchers.equalTo;
25+
import static org.hamcrest.Matchers.hasSize;
26+
import static org.hamcrest.Matchers.is;
27+
import static org.hamcrest.Matchers.not;
28+
29+
import java.nio.file.Path;
30+
import java.util.Map;
31+
import java.util.ResourceBundle;
32+
import org.apache.commons.httpclient.URI;
33+
import org.junit.jupiter.api.Test;
34+
import org.parosproxy.paros.core.scanner.Alert;
35+
import org.parosproxy.paros.network.HttpMessage;
36+
37+
class PassiveDefaultTemplateGraalJsScriptTest extends GraalJsPassiveScriptScanRuleTestUtils {
38+
@Override
39+
public Path getScriptPath() throws Exception {
40+
return Path.of(
41+
getClass()
42+
.getResource(
43+
"/scripts/templates/passive/Passive default template GraalJS.js")
44+
.toURI());
45+
}
46+
47+
@Override
48+
public void shouldHaveI18nNonEmptyName(String name, ResourceBundle extensionResourceBundle) {
49+
assertThat(name, is(not(emptyOrNullString())));
50+
}
51+
52+
@Test
53+
void shouldRaiseAlert() throws Exception {
54+
// Given
55+
HttpMessage msg = new HttpMessage(new URI("http://example.com/path?param=value", true));
56+
// When
57+
scanHttpResponseReceive(msg);
58+
// Then
59+
assertThat(alertsRaised, hasSize(1));
60+
Alert alert = alertsRaised.get(0);
61+
assertThat(alert.getPluginId(), is(equalTo(12345)));
62+
assertThat(alert.getAlertRef(), is(equalTo("12345")));
63+
assertThat(alert.getName(), is(equalTo("Passive Vulnerability Title")));
64+
assertThat(alert.getDescription(), is(equalTo("Full description")));
65+
assertThat(alert.getSolution(), is(equalTo("The solution")));
66+
assertThat(alert.getReference(), is(equalTo("Reference 1\nReference 2")));
67+
assertThat(alert.getOtherInfo(), is(equalTo("Any other info")));
68+
assertThat(alert.getRisk(), is(equalTo(Alert.RISK_INFO)));
69+
assertThat(alert.getConfidence(), is(equalTo(Alert.CONFIDENCE_LOW)));
70+
assertThat(alert.getTags(), is(equalTo(Map.of("name1", "value1", "name2", "value2"))));
71+
assertThat(alert.getMsgUri().getPathQuery(), is(equalTo("/path?param=value")));
72+
assertThat(alert.getParam(), is(equalTo("The param")));
73+
assertThat(alert.getEvidence(), is(equalTo("Evidence")));
74+
}
75+
}

testutils/src/main/java/org/zaproxy/zap/testutils/ActiveScannerTestUtils.java

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
import static org.hamcrest.MatcherAssert.assertThat;
2323
import static org.hamcrest.Matchers.empty;
24-
import static org.hamcrest.Matchers.emptyOrNullString;
2524
import static org.hamcrest.Matchers.hasSize;
2625
import static org.hamcrest.Matchers.is;
2726
import static org.hamcrest.Matchers.lessThanOrEqualTo;
@@ -210,25 +209,13 @@ private DynamicTest testScanRuleHasName() {
210209
() -> {
211210
setUp();
212211
try {
213-
shouldHaveI18nNonEmptyName();
212+
shouldHaveI18nNonEmptyName(rule.getName(), extensionResourceBundle);
214213
} finally {
215214
shutDownServer();
216215
}
217216
});
218217
}
219218

220-
private void shouldHaveI18nNonEmptyName() {
221-
// Given / When
222-
String name = rule.getName();
223-
// Then
224-
assertThat(name, is(not(emptyOrNullString())));
225-
assertThat(
226-
"Name does not seem to be i18n'ed, not found in the resource bundle:" + name,
227-
extensionResourceBundle.keySet().stream()
228-
.map(extensionResourceBundle::getString)
229-
.anyMatch(str -> str.equals(name)));
230-
}
231-
232219
private DynamicTest testExampleAlerts() {
233220
return dynamicTest(
234221
"shouldHaveExampleAlerts",

testutils/src/main/java/org/zaproxy/zap/testutils/PassiveScannerTestUtils.java

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ private DynamicTest testScanRuleHasName() {
148148
"shouldHaveI18nNonEmptyName",
149149
() -> {
150150
setUp();
151-
shouldHaveI18nNonEmptyName();
151+
shouldHaveI18nNonEmptyName(rule.getName(), extensionResourceBundle);
152152
});
153153
}
154154

@@ -161,18 +161,6 @@ private DynamicTest testExampleAlerts() {
161161
});
162162
}
163163

164-
private void shouldHaveI18nNonEmptyName() {
165-
// Given / When
166-
String name = rule.getName();
167-
// Then
168-
assertThat(name, is(not(emptyOrNullString())));
169-
assertThat(
170-
"Name does not seem to be i18n'ed, not found in the resource bundle: " + name,
171-
extensionResourceBundle.keySet().stream()
172-
.map(extensionResourceBundle::getString)
173-
.anyMatch(str -> str.equals(name)));
174-
}
175-
176164
private void shouldHaveExampleAlerts() {
177165
// Given / When
178166
List<Alert> alerts = assertDoesNotThrow(((ExampleAlertProvider) rule)::getExampleAlerts);

testutils/src/main/java/org/zaproxy/zap/testutils/ScanRuleTests.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121

2222
import static org.hamcrest.MatcherAssert.assertThat;
2323
import static org.hamcrest.Matchers.empty;
24+
import static org.hamcrest.Matchers.emptyOrNullString;
2425
import static org.hamcrest.Matchers.is;
26+
import static org.hamcrest.Matchers.not;
2527
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
2628

2729
import java.io.IOException;
@@ -30,6 +32,7 @@
3032
import java.util.Collection;
3133
import java.util.List;
3234
import java.util.Optional;
35+
import java.util.ResourceBundle;
3336
import java.util.Set;
3437
import java.util.TreeSet;
3538
import java.util.function.Function;
@@ -61,6 +64,15 @@ default Collection<DynamicTest> addScanRuleTests() {
6164
return tests;
6265
}
6366

67+
default void shouldHaveI18nNonEmptyName(String name, ResourceBundle extensionResourceBundle) {
68+
assertThat(name, is(not(emptyOrNullString())));
69+
assertThat(
70+
"Name does not seem to be i18n'ed, not found in the resource bundle:" + name,
71+
extensionResourceBundle.keySet().stream()
72+
.map(extensionResourceBundle::getString)
73+
.anyMatch(str -> str.equals(name)));
74+
}
75+
6476
default void shouldHaveExpectedAlertRefsInExampleAlerts() {
6577
// Given / When
6678
List<Alert> alerts = getExampleAlerts(getScanRule());

0 commit comments

Comments
 (0)