From 773860566e2e6816a0dc282640264cbb1cf83404 Mon Sep 17 00:00:00 2001 From: James Nord Date: Fri, 14 Jul 2023 18:31:19 +0100 Subject: [PATCH] [SECURITY-3103] test adaptation --- pom.xml | 2 + .../hudson/slaves/CommandLauncher2Test.java | 41 ++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b691016..c664ac7 100644 --- a/pom.xml +++ b/pom.xml @@ -47,6 +47,7 @@ io.jenkins.tools.bom bom-2.361.x + 2025.v816d28f1e04f pom import @@ -57,6 +58,7 @@ org.jenkins-ci.plugins script-security + 1265.va_fb_290b_4b_d34 io.jenkins diff --git a/src/test/java/hudson/slaves/CommandLauncher2Test.java b/src/test/java/hudson/slaves/CommandLauncher2Test.java index 55dfd04..13d1582 100644 --- a/src/test/java/hudson/slaves/CommandLauncher2Test.java +++ b/src/test/java/hudson/slaves/CommandLauncher2Test.java @@ -41,8 +41,12 @@ import edu.umd.cs.findbugs.annotations.CheckForNull; import jenkins.model.Jenkins; import org.apache.tools.ant.filters.StringInputStream; +import org.hamcrest.CustomTypeSafeMatcher; +import org.hamcrest.Description; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval; +import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval.PendingScript; import org.jenkinsci.plugins.scriptsecurity.scripts.languages.SystemCommandLanguage; import static org.junit.Assert.*; import org.junit.Rule; @@ -54,12 +58,14 @@ import org.jvnet.hudson.test.RestartableJenkinsRule; import org.jvnet.hudson.test.recipes.LocalData; +import static hudson.slaves.CommandLauncher2Test.PendingScriptApprovalMatcher.pendingScript; + public class CommandLauncher2Test { @Rule public RestartableJenkinsRule rr = new RestartableJenkinsRule(); - @Issue("SECURITY-478") + @Issue({"SECURITY-478", "SECURITY-3103"}) @Test public void requireApproval() throws Exception { rr.addStep(new Statement() { // TODO .then, when using sufficiently new jenkins-test-harness @@ -82,6 +88,9 @@ public void evaluate() throws Throwable { s = (DumbSlave) rr.j.jenkins.getNode("s"); assertEquals("echo configured by GUI", ((CommandLauncher) s.getLauncher()).getCommand()); assertSerialForm(s, "echo configured by GUI"); + assertThat(ScriptApproval.get().getPendingScripts(), contains(pendingScript("echo configured by GUI"))); + ScriptApproval.get().getPendingScripts().clear(); // reset + // Then by REST. String configDotXml = s.toComputer().getUrl() + "config.xml"; String xml = wc.goTo(configDotXml, "application/xml").getWebResponse().getContentAsString(); @@ -93,14 +102,19 @@ public void evaluate() throws Throwable { s = (DumbSlave) rr.j.jenkins.getNode("s"); assertEquals("echo configured by REST", ((CommandLauncher) s.getLauncher()).getCommand()); assertSerialForm(s, "echo configured by REST"); + assertThat(ScriptApproval.get().getPendingScripts(), contains(pendingScript("echo configured by REST"))); + ScriptApproval.get().getPendingScripts().clear(); // reset + // Then by CLI. CLICommand cmd = new UpdateNodeCommand(); cmd.setTransportAuth(User.get("admin").impersonate()); assertThat(new CLICommandInvoker(rr.j, cmd).withStdin(new StringInputStream(xml.replace("echo configured by GUI", "echo configured by CLI"))).invokeWithArgs("s"), CLICommandInvoker.Matcher.succeededSilently()); s = (DumbSlave) rr.j.jenkins.getNode("s"); assertEquals("echo configured by CLI", ((CommandLauncher) s.getLauncher()).getCommand()); - assertEquals(Collections.emptySet(), ScriptApproval.get().getPendingScripts()); assertSerialForm(s, "echo configured by CLI"); + assertThat(ScriptApproval.get().getPendingScripts(), contains(pendingScript("echo configured by CLI"))); + ScriptApproval.get().getPendingScripts().clear(); // reset + // Now verify that all modes failed as dev. First as GUI. ScriptApproval.get().preapprove("echo configured by admin", SystemCommandLanguage.get()); s.setLauncher(new CommandLauncher("echo configured by admin")); @@ -187,4 +201,27 @@ public void evaluate() throws Throwable { }); } + static class PendingScriptApprovalMatcher extends CustomTypeSafeMatcher { + + private final String expectedScript; + + private PendingScriptApprovalMatcher(String expectedScript) { + super("PendingScript with script " + expectedScript); + this.expectedScript = expectedScript; + } + + @Override + protected boolean matchesSafely(PendingScript item) { + return expectedScript.equals(item.script); + } + + @Override + public void describeMismatchSafely(PendingScript item, Description mismatchDescription) { + mismatchDescription.appendText("has script ").appendText(item.script); + } + + public static PendingScriptApprovalMatcher pendingScript(String expectedScript) { + return new PendingScriptApprovalMatcher(expectedScript); + } + } }