Skip to content

Commit 67c220f

Browse files
committed
af: Scripts support chaining
Signed-off-by: kingthorin <kingthorin@users.noreply.github.com>
1 parent b818cb1 commit 67c220f

13 files changed

Lines changed: 1721 additions & 70 deletions

File tree

addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/automation/ScriptJobParameters.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020
package org.zaproxy.zap.extension.scripts.automation;
2121

22+
import java.util.List;
2223
import lombok.AllArgsConstructor;
2324
import lombok.Getter;
2425
import lombok.NoArgsConstructor;
@@ -39,6 +40,7 @@ public class ScriptJobParameters extends AutomationData {
3940
private String inline = "";
4041
private String context = "";
4142
private String user = "";
43+
private List<String> chain;
4244

4345
public ScriptJobParameters(String action) {
4446
this.action = action;

addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/automation/actions/RunScriptAction.java

Lines changed: 290 additions & 44 deletions
Large diffs are not rendered by default.

addOns/scripts/src/main/java/org/zaproxy/zap/extension/scripts/automation/ui/ScriptJobDialog.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,8 @@ public String validateFields() {
301301
this.getStringValue(SCRIPT_TARGET_PARAM),
302302
this.getStringValue(SCRIPT_INLINE_PARAM),
303303
this.getStringValue(SCRIPT_CONTEXT_PARAM),
304-
this.getStringValue(SCRIPT_USER_PARAM));
304+
this.getStringValue(SCRIPT_USER_PARAM),
305+
null); // chain parameter - not currently supported in UI dialog
305306
sa = ScriptJob.createScriptAction(params, null);
306307
List<String> issues = sa.verifyParameters(this.getStringValue(NAME_PARAM), params, null);
307308
if (issues.isEmpty()) {

addOns/scripts/src/main/javahelp/org/zaproxy/zap/extension/scripts/resources/help/contents/automation.html

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,63 @@ <H2>Action: remove</H2>
3636

3737
<H2>Action: run</H2>
3838

39-
Runs the specified script to ZAP. The script must already be available in ZAP, for example added using the 'add' action.
39+
Runs the specified script in ZAP. The script must already be available in ZAP, for example added using the 'add' action.
4040

4141
<ul>
4242
<li>type: mandatory, can be 'standalone' or 'targeted'
43-
<li>name: mandatory, the name of the script in ZAP
43+
<li>name: mandatory for single script run, the name of the script in ZAP (if both 'name' and 'chain' are specified, 'name' is ignored)
44+
<li>chain: optional for running multiple scripts in sequence, a list of script names (takes precedence over 'name' if both are specified)
4445
<li>engine: optional, can be used to override the default engine for the file extension
4546
<li>target: mandatory, if type is 'targeted', the target URL to be invoked for 'targeted' script
4647
<li>context: optional, the name of the context to use when running the script
47-
<li>user: optional, the name of the user to use when running the standalone script. Currently only supported for Zest scripts, if the context has browser-based or client-script authentication configured, the user will be authenticated before the script executes.
48+
<li>user: optional, the name of the user when running the Zest standalone script or chain (requires context). See Script Chaining for authentication with chains.
49+
</ul>
50+
51+
<H3>Script Chaining</H3>
52+
<p>
53+
The run action can execute one or more Zest standalone scripts in sequence using the <code>chain</code> parameter.
54+
This is useful for workflows that require several scripts to run in order.
55+
</p>
56+
<p>
57+
Chaining requires the Zest add-on to be installed. If it is not loaded or chain preparation fails, the job reports an error and the chain does not run.
58+
</p>
59+
60+
<H4>Requirements:</H4>
61+
<ul>
62+
<li>All scripts in the chain must be Zest standalone scripts</li>
63+
<li>All scripts must be added via "add" actions in the same plan (or already loaded in ZAP)</li>
64+
<li>Script existence and type are validated at runtime, not during plan validation</li>
65+
<li>If both <code>chain</code> and <code>name</code> are specified, <code>chain</code> is used and <code>name</code> is ignored (a warning is issued)</li>
66+
<li>The first script must contain at least one browser launch (<code>ZestClientLaunch</code>)</li>
67+
<li>Subsequent scripts reuse that browser (extra launch statements are disabled)</li>
68+
<li>At the end of the chain, all browser windows opened by the scripts are closed automatically</li>
4869
</ul>
4970

71+
<H4>Authentication:</H4>
72+
<p>
73+
If <code>user</code> is specified, the user is authenticated when the context has browser-based or client-script authentication configured (Zest only).
74+
For chains, authentication is performed once before the first script runs; all scripts in the chain share the same authenticated session.
75+
</p>
76+
77+
<H4>Error Handling:</H4>
78+
<p>
79+
If chain preparation fails (e.g. Zest not loaded) or any script in the chain fails during execution, the job reports an error and stops. Later scripts in the chain are not run.
80+
</p>
81+
82+
<H4>Example:</H4>
83+
<pre>
84+
- type: script
85+
parameters:
86+
action: run
87+
type: standalone
88+
chain:
89+
- access-script
90+
- navigate-script
91+
- perform-action-script
92+
context: mycontext
93+
user: testuser
94+
</pre>
95+
5096
<H2>Action: loaddir</H2>
5197

5298
Loads all of the scripts in the subdirectories under the specified source path to ZAP.
@@ -84,12 +130,13 @@ <H2>YAML definition</H2>
84130
action: # String: The executed action - available actions: add, remove, run, enable, disable
85131
type: # String: The type of the script
86132
engine: # String: The script engine to use - can be used to override the default engine for the file extension
87-
name: # String: The name of the script, defaults to the file name
133+
name: # String: The name of the script, defaults to the file name (for single script run; ignored if 'chain' is specified)
134+
chain: # List: optional; script names to run in sequence (takes precedence over name if both specified)
88135
source: # String: The full or relative file path, must be readable
89136
inline: # String: The full script (may be multi-line) - supply this or 'source' not both
90137
target: # String: The URL to be invoked for "targeted" script type
91138
context: # String: The name of the context to use when running the script (optional)
92-
user: # String: The name of the user to use when running the standalone script (optional, requires context) [Currently only supported for Zest scripts]
139+
user: # String: The name of the user to use when running the Zest standalone script or chain (optional, requires context)
93140
</pre>
94141

95142
The <code>source</code> parameter was previously called <code>file</code>, both will work.

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ scripts.automation.dialog.user = User:
7979
scripts.automation.error.actionNotDefined = Specified action ''{0}'' not defined. Only following actions are valid: {1}
8080
scripts.automation.error.actionNull = Action is required, but not specified. Following actions are valid: {0}
8181
scripts.automation.error.add.failed = Job {0} Failed to add script: {1}
82+
scripts.automation.error.chainExecutionFailed = Job {0}: Chain execution failed: {1}
83+
scripts.automation.error.chainPreparationFailed = Job: {0} Chain preparation failed: {1}
84+
scripts.automation.error.chainReflectionFailed = Job: {0} Failed to prepare chain for execution (Zest may not be loaded or reflection error). First script: ''{1}''
85+
scripts.automation.error.chainRequiresStandalone = Job {0}: Chain can only be used with standalone scripts
86+
scripts.automation.error.chainScriptMissingMethods = Job {0}: Script ''{1}'' does not support chaining (missing required methods)
87+
scripts.automation.error.chainScriptNotFound = Job {0}: Script ''{1}'' in chain not found
88+
scripts.automation.error.chainScriptNotZestScript = Job {0}: Script ''{1}'' in chain is not a Zest script
89+
scripts.automation.error.chainScriptNotZestStandalone = Job {0}: Script ''{1}'' in chain is not a Zest standalone script
8290
scripts.automation.error.file.cannotRead = Job {0} Cannot access Script path: {1}
8391
scripts.automation.error.file.missing = Job {0} Neither Script path nor Inline specified - one of them must be supplied
8492
scripts.automation.error.file.notDir = Job {0} Script path: {1} is not a directory
@@ -98,11 +106,14 @@ scripts.automation.error.scriptTypeIsNull = Job: {0} Script type is required, bu
98106
scripts.automation.error.scriptTypeNotEnableable = Job: {0} Script with name: {1} is not enableable
99107
scripts.automation.error.scriptTypeNotSupported = Job: {0} Script type: {1} can not be used with action: {2}. Following script types are valid: {3}
100108
scripts.automation.info.add.replace = Job: {0} Replaced existing script: {1}
109+
scripts.automation.info.chainCompleted = Script chain completed successfully
110+
scripts.automation.info.chainExecuting = Executing chain of {0} scripts
101111
scripts.automation.info.loadDir.added = Job: {0} Added script {1}
102112
scripts.automation.info.loadDir.loaded = Job: {0} Loaded {2} script(s) from directory {1}
103113
scripts.automation.info.script.output = Job: {0} Script output: {1}
104114
scripts.automation.info.startAction = Job: {0} Start action: {1}
105115
scripts.automation.name = Scripts Automation Framework Integration
116+
scripts.automation.warn.chainAndNameBothSpecified = Job {0}: Both 'name' and 'chain' parameters specified, 'name' will be ignored and chain will be processed
106117
scripts.automation.warn.fileNotNeeded = Job: {0} Source specified but not needed so will be ignored
107118
scripts.automation.warn.userParameterSetButActionNotRun = Job: {0} User parameter is set but action is not run
108119

addOns/scripts/src/main/resources/org/zaproxy/zap/extension/scripts/resources/script-max.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
action: # String: The executed action - available actions: add, remove, run, loaddir, enable, disable
44
type: # String: The type of the script
55
engine: # String: The script engine to use - can be used to override the default engine for the file extension
6-
name: # String: The name of the script, defaults to the file name
6+
name: # String: The name of the script, defaults to the file name (for single script run; ignored if 'chain' is specified)
7+
chain: # List: optional; script names to run in sequence (takes precedence over name if both specified)
78
source: # String: The full or relative path, must be readable
89
inline: # String: The full script (may be multi-line) - supply this or 'source' not both
910
target: # String: The URL to be invoked for "targeted" script type
1011
context: # String: The name of the context to use when running the script (optional)
11-
user: # String: The name of the user to use when running the standalone script (optional, requires context) [Currently only supported for Zest scripts]
12+
user: # String: The name of the user to use when running the Zest standalone script or chain (optional, requires context)

addOns/scripts/src/test/java/org/zaproxy/zap/extension/scripts/automation/actions/AddScriptActionUnitTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ void setup() {
7676
env = plan.getEnv();
7777
progress = mock(AutomationProgress.class);
7878
parameters =
79-
new ScriptJobParameters(AddScriptAction.NAME, null, null, "", "", "", "", "", "");
79+
new ScriptJobParameters(
80+
AddScriptAction.NAME, null, null, "", "", "", "", "", "", null);
8081

8182
action = new AddScriptAction(parameters);
8283
}

0 commit comments

Comments
 (0)