From e74508980dd8844165992900ec24fb4faa1c6b00 Mon Sep 17 00:00:00 2001 From: "Meiswinkel, Jan SF/HZA-ZC2S" Date: Tue, 26 Apr 2022 14:52:05 +0200 Subject: [PATCH 01/12] Set location for listener --- core/src/main/java/jenkins/model/Jenkins.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 94f4b068c362..9be53762cf99 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -4678,6 +4678,7 @@ public void run() { * Run arbitrary Groovy script. */ public void doScript(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { + _doScript(req, rsp, req.getView(this, "_script.jelly"), FilePath.localChannel, getACL()); } @@ -4706,6 +4707,9 @@ public static void _doScript(StaplerRequest req, StaplerResponse rsp, RequestDis } try { + User u = User.current(); + System.out.println(u.getDisplayName()); + //Add listener here req.setAttribute("output", RemotingDiagnostics.executeGroovy(text, channel)); } catch (InterruptedException e) { From 060fe1e17c75e58d52155a398dfdbaf6c2e73251 Mon Sep 17 00:00:00 2001 From: "Meiswinkel, Jan SF/HZA-ZC2S" Date: Wed, 4 May 2022 15:48:02 +0200 Subject: [PATCH 02/12] Add ScriptListener --- core/src/main/java/jenkins/model/Jenkins.java | 2 +- .../java/jenkins/model/ScriptListener.java | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/jenkins/model/ScriptListener.java diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 9be53762cf99..4d7227d44970 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -4709,7 +4709,7 @@ public static void _doScript(StaplerRequest req, StaplerResponse rsp, RequestDis try { User u = User.current(); System.out.println(u.getDisplayName()); - //Add listener here + ScriptListener.fireScriptEvent(req); req.setAttribute("output", RemotingDiagnostics.executeGroovy(text, channel)); } catch (InterruptedException e) { diff --git a/core/src/main/java/jenkins/model/ScriptListener.java b/core/src/main/java/jenkins/model/ScriptListener.java new file mode 100644 index 000000000000..9f5439b8a6a0 --- /dev/null +++ b/core/src/main/java/jenkins/model/ScriptListener.java @@ -0,0 +1,34 @@ +package jenkins.model; + +import hudson.ExtensionPoint; +import jenkins.util.Listeners; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.kohsuke.stapler.StaplerRequest; + +/** + * A listener to track usage of the script console. + * + * @see Jenkins#_doScript(StaplerRequest, org.kohsuke.stapler.StaplerResponse, javax.servlet.RequestDispatcher, hudson.remoting.VirtualChannel, hudson.security.ACL) + */ +public interface ScriptListener extends ExtensionPoint { + + /** + * Called when script is executed in Script console. + * + * @see Jenkins#_doScript(StaplerRequest, org.kohsuke.stapler.StaplerResponse, javax.servlet.RequestDispatcher, hudson.remoting.VirtualChannel, hudson.security.ACL) + * @param req The StaplerRequest (POST) that contains the script to be executed. + */ + void onScript(StaplerRequest req); + + /** + * Fires the {@link #onScript(StaplerRequest)} event to track the usage of the script console. + * + * @see Jenkins#_doScript(StaplerRequest, org.kohsuke.stapler.StaplerResponse, javax.servlet.RequestDispatcher, hudson.remoting.VirtualChannel, hudson.security.ACL) + * @param req The StaplerRequest (POST) that contians the script to be executed. + */ + @Restricted(NoExternalUse.class) + static void fireScriptEvent(StaplerRequest req) { + Listeners.notify(ScriptListener.class, true, listener -> listener.onScript(req)); + } +} From 89ac091063b9bc9fce8cfd4d0e1d29a98a23e848 Mon Sep 17 00:00:00 2001 From: "Meiswinkel, Jan SF/HZA-ZC2S" Date: Wed, 4 May 2022 16:07:20 +0200 Subject: [PATCH 03/12] Remove debugging statements --- core/src/main/java/jenkins/model/Jenkins.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 4d7227d44970..9214548de604 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -4707,8 +4707,6 @@ public static void _doScript(StaplerRequest req, StaplerResponse rsp, RequestDis } try { - User u = User.current(); - System.out.println(u.getDisplayName()); ScriptListener.fireScriptEvent(req); req.setAttribute("output", RemotingDiagnostics.executeGroovy(text, channel)); From 8d41ad11ca0e8774d535e2f07ee3f758edddb15a Mon Sep 17 00:00:00 2001 From: meiswjn <41284403+meiswjn@users.noreply.github.com> Date: Mon, 9 May 2022 11:49:12 +0200 Subject: [PATCH 04/12] Add listener for CLI --- .../main/java/hudson/cli/GroovyCommand.java | 5 ++- .../main/java/hudson/cli/GroovyshCommand.java | 2 + core/src/main/java/jenkins/model/Jenkins.java | 7 ++- .../java/jenkins/model/ScriptListener.java | 44 ++++++++++++++----- 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/hudson/cli/GroovyCommand.java b/core/src/main/java/hudson/cli/GroovyCommand.java index 0d7e45e6ca18..dc426a44b1a3 100644 --- a/core/src/main/java/hudson/cli/GroovyCommand.java +++ b/core/src/main/java/hudson/cli/GroovyCommand.java @@ -33,6 +33,7 @@ import java.util.ArrayList; import java.util.List; import jenkins.model.Jenkins; +import jenkins.model.ScriptListener; import org.apache.commons.io.IOUtils; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.CmdLineException; @@ -70,7 +71,9 @@ protected int run() throws Exception { binding.setProperty("stderr", stderr); GroovyShell groovy = new GroovyShell(Jenkins.get().getPluginManager().uberClassLoader, binding); - groovy.run(loadScript(), "RemoteClass", remaining.toArray(new String[0])); + String script = loadScript(); + ScriptListener.fireScriptFromCLIEvent(script); + groovy.run(script, "RemoteClass", remaining.toArray(new String[0])); return 0; } diff --git a/core/src/main/java/hudson/cli/GroovyshCommand.java b/core/src/main/java/hudson/cli/GroovyshCommand.java index 4f6c741c8a47..23d0cb58eed6 100644 --- a/core/src/main/java/hudson/cli/GroovyshCommand.java +++ b/core/src/main/java/hudson/cli/GroovyshCommand.java @@ -39,6 +39,7 @@ import java.util.ArrayList; import java.util.List; import jenkins.model.Jenkins; +import jenkins.model.ScriptListener; import jline.TerminalFactory; import jline.UnsupportedTerminal; import org.codehaus.groovy.tools.shell.Groovysh; @@ -79,6 +80,7 @@ protected int run() { } Groovysh shell = createShell(stdin, stdout, stderr); + ScriptListener.fireScriptFromCLIEvent(commandLine.toString()); return shell.run(commandLine.toString()); } diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 795b5a8b445e..bb7785cb2bd6 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -142,6 +142,7 @@ import hudson.model.listeners.SCMListener; import hudson.model.listeners.SaveableListener; import hudson.remoting.Callable; +import hudson.remoting.Channel; import hudson.remoting.LocalChannel; import hudson.remoting.VirtualChannel; import hudson.scm.RepositoryBrowser; @@ -4723,7 +4724,11 @@ public static void _doScript(StaplerRequest req, StaplerResponse rsp, RequestDis } try { - ScriptListener.fireScriptEvent(req); + String runner = "Controller"; + if (!(channel instanceof LocalChannel)) { + runner = ((Channel) channel).getName(); + } + ScriptListener.fireScriptConsoleEvent(text, runner); req.setAttribute("output", RemotingDiagnostics.executeGroovy(text, channel)); } catch (InterruptedException e) { diff --git a/core/src/main/java/jenkins/model/ScriptListener.java b/core/src/main/java/jenkins/model/ScriptListener.java index 9f5439b8a6a0..0bc639a14f03 100644 --- a/core/src/main/java/jenkins/model/ScriptListener.java +++ b/core/src/main/java/jenkins/model/ScriptListener.java @@ -2,33 +2,55 @@ import hudson.ExtensionPoint; import jenkins.util.Listeners; -import org.kohsuke.accmod.Restricted; -import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.StaplerRequest; /** - * A listener to track usage of the script console. + * A listener to track Groovy scripts from the CLI and console. * * @see Jenkins#_doScript(StaplerRequest, org.kohsuke.stapler.StaplerResponse, javax.servlet.RequestDispatcher, hudson.remoting.VirtualChannel, hudson.security.ACL) + * @see hudson.cli.GroovyCommand#run() + * @see hudson.cli.GroovyshCommand#run() */ public interface ScriptListener extends ExtensionPoint { /** - * Called when script is executed in Script console. + * Called when a groovy script is executed in Script console. * * @see Jenkins#_doScript(StaplerRequest, org.kohsuke.stapler.StaplerResponse, javax.servlet.RequestDispatcher, hudson.remoting.VirtualChannel, hudson.security.ACL) - * @param req The StaplerRequest (POST) that contains the script to be executed. + * @param script The script to be executed. + * @param runner Descriptive name of the runner executing the script. */ - void onScript(StaplerRequest req); + void onScriptFromConsole(String script, String runner); /** - * Fires the {@link #onScript(StaplerRequest)} event to track the usage of the script console. + * Called when a groovy script is executed from the CLI. + * + * @see hudson.cli.GroovyCommand#run() + * @see hudson.cli.GroovyshCommand#run() + * @param script The script to be executed. + */ + void onScriptFromCLI(String script); + + + /** + * Fires the {@link #onScriptFromConsole(String, String)} event to track the usage of the script console. * * @see Jenkins#_doScript(StaplerRequest, org.kohsuke.stapler.StaplerResponse, javax.servlet.RequestDispatcher, hudson.remoting.VirtualChannel, hudson.security.ACL) - * @param req The StaplerRequest (POST) that contians the script to be executed. + * @param script The script to be executed. + * @param runner Descriptive name of the runner executing the script. + */ + static void fireScriptConsoleEvent(String script, String runner) { + Listeners.notify(ScriptListener.class, true, listener -> listener.onScriptFromConsole(script, runner)); + } + + /** + * Fires the {@link #onScriptFromCLI(String)} event to track the usage of the script console. + * + * @see hudson.cli.GroovyCommand#run() + * @see hudson.cli.GroovyshCommand#run() + * @param script The script to be executed. */ - @Restricted(NoExternalUse.class) - static void fireScriptEvent(StaplerRequest req) { - Listeners.notify(ScriptListener.class, true, listener -> listener.onScript(req)); + static void fireScriptFromCLIEvent(String script) { + Listeners.notify(ScriptListener.class, true, listener -> listener.onScriptFromCLI(script)); } } From dc7728fbacc7f455fe571d0c9bd5e1e3d7944381 Mon Sep 17 00:00:00 2001 From: "Meiswinkel, Jan SF/HZA-ZC2S" Date: Thu, 23 Jun 2022 14:25:28 +0200 Subject: [PATCH 05/12] Add new listener for other sources --- .../main/java/hudson/cli/GroovyCommand.java | 3 +- .../main/java/hudson/cli/GroovyshCommand.java | 3 +- core/src/main/java/jenkins/model/Jenkins.java | 2 +- .../java/jenkins/model/ScriptListener.java | 43 +++++++++++++++---- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/hudson/cli/GroovyCommand.java b/core/src/main/java/hudson/cli/GroovyCommand.java index dc426a44b1a3..181e01b46141 100644 --- a/core/src/main/java/hudson/cli/GroovyCommand.java +++ b/core/src/main/java/hudson/cli/GroovyCommand.java @@ -27,6 +27,7 @@ import groovy.lang.Binding; import groovy.lang.GroovyShell; import hudson.Extension; +import hudson.model.User; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; @@ -72,7 +73,7 @@ protected int run() throws Exception { GroovyShell groovy = new GroovyShell(Jenkins.get().getPluginManager().uberClassLoader, binding); String script = loadScript(); - ScriptListener.fireScriptFromCLIEvent(script); + ScriptListener.fireScriptFromCLIEvent(script, User.current()); groovy.run(script, "RemoteClass", remaining.toArray(new String[0])); return 0; } diff --git a/core/src/main/java/hudson/cli/GroovyshCommand.java b/core/src/main/java/hudson/cli/GroovyshCommand.java index 23d0cb58eed6..a1d79e05695c 100644 --- a/core/src/main/java/hudson/cli/GroovyshCommand.java +++ b/core/src/main/java/hudson/cli/GroovyshCommand.java @@ -28,6 +28,7 @@ import groovy.lang.Binding; import groovy.lang.Closure; import hudson.Extension; +import hudson.model.User; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; @@ -80,7 +81,7 @@ protected int run() { } Groovysh shell = createShell(stdin, stdout, stderr); - ScriptListener.fireScriptFromCLIEvent(commandLine.toString()); + ScriptListener.fireScriptFromCLIEvent(commandLine.toString(), User.current()); return shell.run(commandLine.toString()); } diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index bb7785cb2bd6..e06fe050a510 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -4728,7 +4728,7 @@ public static void _doScript(StaplerRequest req, StaplerResponse rsp, RequestDis if (!(channel instanceof LocalChannel)) { runner = ((Channel) channel).getName(); } - ScriptListener.fireScriptConsoleEvent(text, runner); + ScriptListener.fireScriptConsoleEvent(text, runner, User.current()); req.setAttribute("output", RemotingDiagnostics.executeGroovy(text, channel)); } catch (InterruptedException e) { diff --git a/core/src/main/java/jenkins/model/ScriptListener.java b/core/src/main/java/jenkins/model/ScriptListener.java index 0bc639a14f03..203d87dc204b 100644 --- a/core/src/main/java/jenkins/model/ScriptListener.java +++ b/core/src/main/java/jenkins/model/ScriptListener.java @@ -1,6 +1,7 @@ package jenkins.model; import hudson.ExtensionPoint; +import hudson.model.User; import jenkins.util.Listeners; import org.kohsuke.stapler.StaplerRequest; @@ -19,8 +20,9 @@ public interface ScriptListener extends ExtensionPoint { * @see Jenkins#_doScript(StaplerRequest, org.kohsuke.stapler.StaplerResponse, javax.servlet.RequestDispatcher, hudson.remoting.VirtualChannel, hudson.security.ACL) * @param script The script to be executed. * @param runner Descriptive name of the runner executing the script. + * @param u If available, the user that executed the script. */ - void onScriptFromConsole(String script, String runner); + void onScriptFromConsole(String script, String runner, User u); /** * Called when a groovy script is executed from the CLI. @@ -28,29 +30,54 @@ public interface ScriptListener extends ExtensionPoint { * @see hudson.cli.GroovyCommand#run() * @see hudson.cli.GroovyshCommand#run() * @param script The script to be executed. + * @param u If available, the user that executed the script. */ - void onScriptFromCLI(String script); + void onScriptFromCLI(String script, User u); + + /** + * Called when a groovy script is executed from a source other than the CLI and Console. + * + * @see hudson.cli.GroovyCommand#run() + * @see hudson.cli.GroovyshCommand#run() + * @param script The script to be executed. + * @param origin An identifiable origin that executed the script (Run ID, ...) + */ + void onScriptFromOtherSource(String script, String origin); /** - * Fires the {@link #onScriptFromConsole(String, String)} event to track the usage of the script console. + * Fires the {@link #onScriptFromConsole(String, String, User)} event to track the usage of the script console. * * @see Jenkins#_doScript(StaplerRequest, org.kohsuke.stapler.StaplerResponse, javax.servlet.RequestDispatcher, hudson.remoting.VirtualChannel, hudson.security.ACL) * @param script The script to be executed. * @param runner Descriptive name of the runner executing the script. + * @param u If available, the user that executed the script. + */ + static void fireScriptConsoleEvent(String script, String runner, User u) { + Listeners.notify(ScriptListener.class, true, listener -> listener.onScriptFromConsole(script, runner, u)); + } + + /** + * Fires the {@link #onScriptFromCLI(String, User)} event to track the usage of the script console. + * + * @see hudson.cli.GroovyCommand#run() + * @see hudson.cli.GroovyshCommand#run() + * @param script The script to be executed. + * @param u If available, the user that executed the script. */ - static void fireScriptConsoleEvent(String script, String runner) { - Listeners.notify(ScriptListener.class, true, listener -> listener.onScriptFromConsole(script, runner)); + static void fireScriptFromCLIEvent(String script, User u) { + Listeners.notify(ScriptListener.class, true, listener -> listener.onScriptFromCLI(script, u)); } /** - * Fires the {@link #onScriptFromCLI(String)} event to track the usage of the script console. + * Fires the {@link #onScriptFromCLI(String, User)} event to track the usage of the script console. * * @see hudson.cli.GroovyCommand#run() * @see hudson.cli.GroovyshCommand#run() * @param script The script to be executed. + * @param origin An identifiable origin that executed the script (Run ID, ...) */ - static void fireScriptFromCLIEvent(String script) { - Listeners.notify(ScriptListener.class, true, listener -> listener.onScriptFromCLI(script)); + static void fireScriptFromOtherSourceEvent(String script, String origin) { + Listeners.notify(ScriptListener.class, true, listener -> listener.onScriptFromOtherSource(script, origin)); } } From c533407683af4ebbcbf57ce001acfec03625358a Mon Sep 17 00:00:00 2001 From: "Meiswinkel, Jan SF/HZA-ZC2S" Date: Thu, 23 Jun 2022 16:08:38 +0200 Subject: [PATCH 06/12] Simplify listener --- .../main/java/hudson/cli/GroovyCommand.java | 2 +- .../main/java/hudson/cli/GroovyshCommand.java | 2 +- core/src/main/java/jenkins/model/Jenkins.java | 9 ++- .../java/jenkins/model/ScriptListener.java | 61 +++---------------- 4 files changed, 16 insertions(+), 58 deletions(-) diff --git a/core/src/main/java/hudson/cli/GroovyCommand.java b/core/src/main/java/hudson/cli/GroovyCommand.java index 181e01b46141..423e284c507d 100644 --- a/core/src/main/java/hudson/cli/GroovyCommand.java +++ b/core/src/main/java/hudson/cli/GroovyCommand.java @@ -73,7 +73,7 @@ protected int run() throws Exception { GroovyShell groovy = new GroovyShell(Jenkins.get().getPluginManager().uberClassLoader, binding); String script = loadScript(); - ScriptListener.fireScriptFromCLIEvent(script, User.current()); + ScriptListener.fireScriptEvent(script, "CLI", User.current()); groovy.run(script, "RemoteClass", remaining.toArray(new String[0])); return 0; } diff --git a/core/src/main/java/hudson/cli/GroovyshCommand.java b/core/src/main/java/hudson/cli/GroovyshCommand.java index a1d79e05695c..5470510953be 100644 --- a/core/src/main/java/hudson/cli/GroovyshCommand.java +++ b/core/src/main/java/hudson/cli/GroovyshCommand.java @@ -81,7 +81,7 @@ protected int run() { } Groovysh shell = createShell(stdin, stdout, stderr); - ScriptListener.fireScriptFromCLIEvent(commandLine.toString(), User.current()); + ScriptListener.fireScriptEvent(commandLine.toString(), "CLI", User.current()); return shell.run(commandLine.toString()); } diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index e06fe050a510..6dab5fc3d55e 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -4724,11 +4724,14 @@ public static void _doScript(StaplerRequest req, StaplerResponse rsp, RequestDis } try { - String runner = "Controller"; + String runner = "Script Console "; + if (!(channel instanceof LocalChannel)) { - runner = ((Channel) channel).getName(); + runner += ((Channel) channel).getName(); + } else { + runner += "Controller"; } - ScriptListener.fireScriptConsoleEvent(text, runner, User.current()); + ScriptListener.fireScriptEvent(text, runner, User.current()); req.setAttribute("output", RemotingDiagnostics.executeGroovy(text, channel)); } catch (InterruptedException e) { diff --git a/core/src/main/java/jenkins/model/ScriptListener.java b/core/src/main/java/jenkins/model/ScriptListener.java index 203d87dc204b..017081c75c88 100644 --- a/core/src/main/java/jenkins/model/ScriptListener.java +++ b/core/src/main/java/jenkins/model/ScriptListener.java @@ -15,69 +15,24 @@ public interface ScriptListener extends ExtensionPoint { /** - * Called when a groovy script is executed in Script console. + * Called when a (privileged) groovy script is executed. * * @see Jenkins#_doScript(StaplerRequest, org.kohsuke.stapler.StaplerResponse, javax.servlet.RequestDispatcher, hudson.remoting.VirtualChannel, hudson.security.ACL) * @param script The script to be executed. - * @param runner Descriptive name of the runner executing the script. - * @param u If available, the user that executed the script. - */ - void onScriptFromConsole(String script, String runner, User u); - - /** - * Called when a groovy script is executed from the CLI. - * - * @see hudson.cli.GroovyCommand#run() - * @see hudson.cli.GroovyshCommand#run() - * @param script The script to be executed. - * @param u If available, the user that executed the script. + * @param origin Descriptive identifier of the origin where the script is executed (Controller, Agent ID, Run ID). + * @param u If available, the user that executed the script. Can be null. */ - void onScriptFromCLI(String script, User u); - - /** - * Called when a groovy script is executed from a source other than the CLI and Console. - * - * @see hudson.cli.GroovyCommand#run() - * @see hudson.cli.GroovyshCommand#run() - * @param script The script to be executed. - * @param origin An identifiable origin that executed the script (Run ID, ...) - */ - void onScriptFromOtherSource(String script, String origin); - + void onScript(String script, String origin, User u); /** - * Fires the {@link #onScriptFromConsole(String, String, User)} event to track the usage of the script console. + * Fires the {@link #onScript(String, String, User)} event to track the usage of the script console. * * @see Jenkins#_doScript(StaplerRequest, org.kohsuke.stapler.StaplerResponse, javax.servlet.RequestDispatcher, hudson.remoting.VirtualChannel, hudson.security.ACL) * @param script The script to be executed. - * @param runner Descriptive name of the runner executing the script. + * @param origin Descriptive identifier of the origin where the script is executed (Controller, Agent ID, Run ID). * @param u If available, the user that executed the script. */ - static void fireScriptConsoleEvent(String script, String runner, User u) { - Listeners.notify(ScriptListener.class, true, listener -> listener.onScriptFromConsole(script, runner, u)); - } - - /** - * Fires the {@link #onScriptFromCLI(String, User)} event to track the usage of the script console. - * - * @see hudson.cli.GroovyCommand#run() - * @see hudson.cli.GroovyshCommand#run() - * @param script The script to be executed. - * @param u If available, the user that executed the script. - */ - static void fireScriptFromCLIEvent(String script, User u) { - Listeners.notify(ScriptListener.class, true, listener -> listener.onScriptFromCLI(script, u)); - } - - /** - * Fires the {@link #onScriptFromCLI(String, User)} event to track the usage of the script console. - * - * @see hudson.cli.GroovyCommand#run() - * @see hudson.cli.GroovyshCommand#run() - * @param script The script to be executed. - * @param origin An identifiable origin that executed the script (Run ID, ...) - */ - static void fireScriptFromOtherSourceEvent(String script, String origin) { - Listeners.notify(ScriptListener.class, true, listener -> listener.onScriptFromOtherSource(script, origin)); + static void fireScriptEvent(String script, String origin, User u) { + Listeners.notify(ScriptListener.class, true, listener -> listener.onScript(script, origin, u)); } } From 02ffdd1e1458d00140be458314de9301d9841f60 Mon Sep 17 00:00:00 2001 From: "Meiswinkel, Jan SF/HZA-ZC2S" Date: Fri, 24 Jun 2022 10:15:09 +0200 Subject: [PATCH 07/12] Fix whitespace and comments --- core/src/main/java/jenkins/model/Jenkins.java | 1 - core/src/main/java/jenkins/model/ScriptListener.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 6dab5fc3d55e..9409f4be8d3a 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -4695,7 +4695,6 @@ public void run() { * Run arbitrary Groovy script. */ public void doScript(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { - _doScript(req, rsp, req.getView(this, "_script.jelly"), FilePath.localChannel, getACL()); } diff --git a/core/src/main/java/jenkins/model/ScriptListener.java b/core/src/main/java/jenkins/model/ScriptListener.java index 017081c75c88..0e9bcbb5fd25 100644 --- a/core/src/main/java/jenkins/model/ScriptListener.java +++ b/core/src/main/java/jenkins/model/ScriptListener.java @@ -6,7 +6,7 @@ import org.kohsuke.stapler.StaplerRequest; /** - * A listener to track Groovy scripts from the CLI and console. + * A listener to track Groovy scripts. * * @see Jenkins#_doScript(StaplerRequest, org.kohsuke.stapler.StaplerResponse, javax.servlet.RequestDispatcher, hudson.remoting.VirtualChannel, hudson.security.ACL) * @see hudson.cli.GroovyCommand#run() From 70b1334fe6b810523649ad2f102a8256b5738d0f Mon Sep 17 00:00:00 2001 From: Jan Meiswinkel Date: Thu, 11 Aug 2022 13:22:50 +0200 Subject: [PATCH 08/12] Update core/src/main/java/hudson/cli/GroovyCommand.java Co-authored-by: Wadeck Follonier --- core/src/main/java/hudson/cli/GroovyCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/cli/GroovyCommand.java b/core/src/main/java/hudson/cli/GroovyCommand.java index 423e284c507d..10324992d151 100644 --- a/core/src/main/java/hudson/cli/GroovyCommand.java +++ b/core/src/main/java/hudson/cli/GroovyCommand.java @@ -73,7 +73,7 @@ protected int run() throws Exception { GroovyShell groovy = new GroovyShell(Jenkins.get().getPluginManager().uberClassLoader, binding); String script = loadScript(); - ScriptListener.fireScriptEvent(script, "CLI", User.current()); + ScriptListener.fireScriptEvent(script, "CLI/GroovyCommand", User.current()); groovy.run(script, "RemoteClass", remaining.toArray(new String[0])); return 0; } From eadd842dd2af7e78a89631ccf27ebaa1cb6f59b3 Mon Sep 17 00:00:00 2001 From: "Meiswinkel, Jan SF/HZA-ZC2S" Date: Thu, 11 Aug 2022 13:25:54 +0200 Subject: [PATCH 09/12] Add precise origins; Correctly log CLI input --- core/src/main/java/hudson/cli/GroovyCommand.java | 2 +- core/src/main/java/hudson/cli/GroovyshCommand.java | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/hudson/cli/GroovyCommand.java b/core/src/main/java/hudson/cli/GroovyCommand.java index 423e284c507d..10324992d151 100644 --- a/core/src/main/java/hudson/cli/GroovyCommand.java +++ b/core/src/main/java/hudson/cli/GroovyCommand.java @@ -73,7 +73,7 @@ protected int run() throws Exception { GroovyShell groovy = new GroovyShell(Jenkins.get().getPluginManager().uberClassLoader, binding); String script = loadScript(); - ScriptListener.fireScriptEvent(script, "CLI", User.current()); + ScriptListener.fireScriptEvent(script, "CLI/GroovyCommand", User.current()); groovy.run(script, "RemoteClass", remaining.toArray(new String[0])); return 0; } diff --git a/core/src/main/java/hudson/cli/GroovyshCommand.java b/core/src/main/java/hudson/cli/GroovyshCommand.java index 5470510953be..007f54c4ed52 100644 --- a/core/src/main/java/hudson/cli/GroovyshCommand.java +++ b/core/src/main/java/hudson/cli/GroovyshCommand.java @@ -43,6 +43,7 @@ import jenkins.model.ScriptListener; import jline.TerminalFactory; import jline.UnsupportedTerminal; +import org.codehaus.groovy.runtime.InvokerHelper; import org.codehaus.groovy.tools.shell.Groovysh; import org.codehaus.groovy.tools.shell.IO; import org.codehaus.groovy.tools.shell.Shell; @@ -81,7 +82,6 @@ protected int run() { } Groovysh shell = createShell(stdin, stdout, stderr); - ScriptListener.fireScriptEvent(commandLine.toString(), "CLI", User.current()); return shell.run(commandLine.toString()); } @@ -122,9 +122,19 @@ public Object doCall(Object[] args) { return null; } }; - Groovysh shell = new Groovysh(cl, binding, io, registrar); + Groovysh shell = new LoggingGroovySh(cl, binding, io, registrar); shell.getImports().add("hudson.model.*"); return shell; } + private static class LoggingGroovySh extends Groovysh { + LoggingGroovySh(ClassLoader cl, Binding binding, IO io, Closure registrar) { + super(cl, binding, io, registrar); + } + @Override + protected void maybeRecordInput(String line) { + ScriptListener.fireScriptEvent(line, "CLI/GroovySh", User.current()); + super.maybeRecordInput(line); + } + } } From 301dea21a4160ed63b4da7f0561d7b159d16d86f Mon Sep 17 00:00:00 2001 From: "Meiswinkel, Jan SF/HZA-ZC2S" Date: Thu, 11 Aug 2022 14:40:10 +0200 Subject: [PATCH 10/12] Add LoggingGroovySh as suggested by @daniel-beck --- core/src/main/java/hudson/cli/GroovyshCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/cli/GroovyshCommand.java b/core/src/main/java/hudson/cli/GroovyshCommand.java index 007f54c4ed52..b682022ed167 100644 --- a/core/src/main/java/hudson/cli/GroovyshCommand.java +++ b/core/src/main/java/hudson/cli/GroovyshCommand.java @@ -43,7 +43,6 @@ import jenkins.model.ScriptListener; import jline.TerminalFactory; import jline.UnsupportedTerminal; -import org.codehaus.groovy.runtime.InvokerHelper; import org.codehaus.groovy.tools.shell.Groovysh; import org.codehaus.groovy.tools.shell.IO; import org.codehaus.groovy.tools.shell.Shell; @@ -126,6 +125,7 @@ public Object doCall(Object[] args) { shell.getImports().add("hudson.model.*"); return shell; } + private static class LoggingGroovySh extends Groovysh { LoggingGroovySh(ClassLoader cl, Binding binding, IO io, Closure registrar) { super(cl, binding, io, registrar); From f1e5b0395331ca9bfc73285123171806f821ac79 Mon Sep 17 00:00:00 2001 From: "Meiswinkel, Jan SF/HZA-ZC2S" Date: Fri, 12 Aug 2022 11:29:14 +0200 Subject: [PATCH 11/12] Add ScriptListener Tests --- .../jenkins/model/ScriptListenerTest.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 test/src/test/java/jenkins/model/ScriptListenerTest.java diff --git a/test/src/test/java/jenkins/model/ScriptListenerTest.java b/test/src/test/java/jenkins/model/ScriptListenerTest.java new file mode 100644 index 000000000000..c86f73a8e4d7 --- /dev/null +++ b/test/src/test/java/jenkins/model/ScriptListenerTest.java @@ -0,0 +1,85 @@ +package jenkins.model; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import hudson.ExtensionList; +import hudson.cli.GroovyCommand; +import hudson.cli.GroovyshCommand; +import hudson.model.User; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Locale; +import javax.servlet.RequestDispatcher; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; + +public class ScriptListenerTest { + + @Rule + public JenkinsRule j = new JenkinsRule(); + private final String testMessage = "light of the world"; + private final String script = String.format("System.out.println('%s')", testMessage); + private PrintStream ps; + private ByteArrayOutputStream altStdout; + private String expectedOutFormat = "Script: '%s' from '%s' by '%s'"; + private DummyScriptUsageListener listener = new DummyScriptUsageListener(); + + @Before + public void setUp() { + altStdout = new ByteArrayOutputStream(); + ps = new PrintStream(altStdout); + ExtensionList.lookup(ScriptListener.class).add(listener); + } + + @Test + public void consoleUsageIsLogged() throws Exception { + RequestDispatcher view = mock(RequestDispatcher.class); + StaplerRequest req = mock(StaplerRequest.class); + StaplerResponse rsp = mock(StaplerResponse.class); + + when(req.getMethod()).thenReturn("POST"); + when(req.getParameter("script")).thenReturn(script); + when(req.getView(j.jenkins, "_scriptText.jelly")).thenReturn(view); + j.jenkins.doScriptText(req, rsp); + + assertEquals(String.format(expectedOutFormat, script, "Script Console Controller", "SYSTEM"), altStdout.toString().trim()); + } + + @Test + public void groovyCliUsageIsLogged() throws Exception { + GroovyCommand cmd = new GroovyCommand(); + cmd.script = "="; + InputStream scriptStream = new ByteArrayInputStream(script.getBytes()); + cmd.main(new ArrayList<>(), Locale.ENGLISH, scriptStream, System.out, System.err); + assertEquals(String.format(expectedOutFormat, script, "CLI/GroovyCommand", "null"), altStdout.toString().trim()); + } + + @Test + public void groovyShCliUsageIsLogged() throws Exception { + GroovyshCommand cmd = new GroovyshCommand(); + InputStream scriptStream = new ByteArrayInputStream(script.getBytes()); + + cmd.main(new ArrayList<>(), Locale.ENGLISH, scriptStream, System.out, System.err); + assertEquals(String.format(expectedOutFormat, script, "CLI/GroovySh", "null"), altStdout.toString().trim()); + } + + private class DummyScriptUsageListener implements ScriptListener { + @Override + public void onScript(String script, String origin, User u) { + String username = "null"; + if (u != null) { + username = u.getFullName(); + } + ps.println(String.format(expectedOutFormat, script, origin, username)); + } + } +} From 567e03b3134eb471ef2d4e2b3d22c254c1f95e2f Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Wed, 31 Aug 2022 23:01:58 +0200 Subject: [PATCH 12/12] Add basic default listener that just logs --- .../main/java/jenkins/model/ScriptListener.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/core/src/main/java/jenkins/model/ScriptListener.java b/core/src/main/java/jenkins/model/ScriptListener.java index 0e9bcbb5fd25..e0aff3279e95 100644 --- a/core/src/main/java/jenkins/model/ScriptListener.java +++ b/core/src/main/java/jenkins/model/ScriptListener.java @@ -1,8 +1,13 @@ package jenkins.model; +import hudson.Extension; import hudson.ExtensionPoint; import hudson.model.User; +import java.util.logging.Level; +import java.util.logging.Logger; import jenkins.util.Listeners; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.StaplerRequest; /** @@ -35,4 +40,15 @@ public interface ScriptListener extends ExtensionPoint { static void fireScriptEvent(String script, String origin, User u) { Listeners.notify(ScriptListener.class, true, listener -> listener.onScript(script, origin, u)); } + + @Extension + @Restricted(NoExternalUse.class) + class LoggingListener implements ScriptListener { + public static final Logger LOGGER = Logger.getLogger(LoggingListener.class.getName()); + + @Override + public void onScript(String script, String origin, User u) { + LOGGER.log(Level.FINE, () -> "Script: '" + script + "' from origin: '" + origin + "' by user: '" + u + "'"); + } + } }