-
-
Notifications
You must be signed in to change notification settings - Fork 8.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[JENKINS-60866][JENKINS-71513] Apply Stapler update for CSP-compliant…
… st:bind and renderOnDemand (#6865) * [JENKINS-60866] Apply Stapler update for CSP-compliant st:bind * [JENKINS-60866] Make renderOnDemand CSP-compliant * Thanks Spotless * Make Stapler incrementals work * Update Stapler to new incremental * Fixup bad merge * Update Stapler, add test demonstrating st:bind working * Address review feedback * Add test for null bind, update Stapler * Checkstyle * More tests * Use released Stapler --------- Co-authored-by: Daniel Beck <daniel-beck@users.noreply.github.com> Co-authored-by: Basil Crow <me@basilcrow.com>
- Loading branch information
1 parent
885978d
commit 6460778
Showing
12 changed files
with
253 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
package org.kohsuke.stapler; | ||
|
||
import static org.hamcrest.CoreMatchers.containsString; | ||
import static org.hamcrest.CoreMatchers.endsWith; | ||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.hamcrest.CoreMatchers.startsWith; | ||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.junit.Assert.assertThrows; | ||
|
||
import hudson.ExtensionList; | ||
import hudson.model.InvisibleAction; | ||
import hudson.model.RootAction; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import org.apache.commons.lang.StringUtils; | ||
import org.htmlunit.Page; | ||
import org.htmlunit.ScriptException; | ||
import org.htmlunit.html.HtmlPage; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.junit.runners.Parameterized; | ||
import org.jvnet.hudson.test.JenkinsRule; | ||
import org.jvnet.hudson.test.TestExtension; | ||
import org.kohsuke.stapler.bind.JavaScriptMethod; | ||
import org.kohsuke.stapler.bind.WithWellKnownURL; | ||
|
||
@RunWith(Parameterized.class) | ||
public class BindTest { | ||
@Rule | ||
public JenkinsRule j = new JenkinsRule(); | ||
|
||
@Parameterized.Parameters | ||
public static List<String> contexts() { | ||
return Arrays.asList("/jenkins", ""); | ||
} | ||
|
||
public BindTest(String contextPath) { | ||
j.contextPath = contextPath; | ||
} | ||
|
||
@Test | ||
public void bindNormal() throws Exception { | ||
final RootActionImpl root = ExtensionList.lookupSingleton(RootActionImpl.class); | ||
try (JenkinsRule.WebClient wc = j.createWebClient()) { | ||
final HtmlPage htmlPage = wc.goTo(root.getUrlName()); | ||
final String scriptUrl = htmlPage | ||
.getElementsByTagName("script") | ||
.stream() | ||
.filter(it -> it.getAttribute("src").startsWith(j.contextPath + "/$stapler/bound/script" + j.contextPath + "/$stapler/bound/")) | ||
.findFirst() | ||
.orElseThrow() | ||
.getAttribute("src"); | ||
|
||
final Page script = wc.goTo(StringUtils.removeStart(scriptUrl, j.contextPath + "/"), "application/javascript"); | ||
final String content = script.getWebResponse().getContentAsString(); | ||
assertThat(content, startsWith("varname = makeStaplerProxy('" + j.contextPath + "/$stapler/bound/")); | ||
assertThat(content, endsWith("','test',['annotatedJsMethod1','byName1']);")); | ||
} | ||
assertThat(root.invocations, is(1)); | ||
} | ||
|
||
@Test | ||
public void bindWithWellKnownURL() throws Exception { | ||
final RootActionWithWellKnownURL root = ExtensionList.lookupSingleton(RootActionWithWellKnownURL.class); | ||
try (JenkinsRule.WebClient wc = j.createWebClient()) { | ||
final HtmlPage htmlPage = wc.goTo(root.getUrlName()); | ||
final String scriptUrl = htmlPage | ||
.getElementsByTagName("script") | ||
.stream() | ||
.filter(it -> it.getAttribute("src").startsWith(j.contextPath + "/$stapler/bound/script" + j.contextPath + "/theWellKnownRoot?")) | ||
.findFirst() | ||
.orElseThrow() | ||
.getAttribute("src"); | ||
|
||
final Page script = wc.goTo(StringUtils.removeStart(scriptUrl, j.contextPath + "/"), "application/javascript"); | ||
assertThat(script.getWebResponse().getContentAsString(), is("varname = makeStaplerProxy('" + j.contextPath + "/theWellKnownRoot','test',['annotatedJsMethod2','byName2']);")); | ||
} | ||
assertThat(root.invocations, is(1)); | ||
} | ||
|
||
@Test | ||
public void bindNull() throws Exception { | ||
final RootActionImpl root = ExtensionList.lookupSingleton(RootActionImpl.class); | ||
try (JenkinsRule.WebClient wc = j.createWebClient()) { | ||
final ScriptException exception = assertThrows(ScriptException.class, () -> wc.goTo(root.getUrlName() + "/null")); | ||
assertThat(exception.getFailingLineNumber(), is(2)); | ||
assertThat(exception.getFailingColumnNumber(), is(0)); | ||
assertThat(exception.getMessage(), containsString("TypeError: Cannot call method \"byName1\" of null")); | ||
|
||
final HtmlPage htmlPage = exception.getPage(); | ||
final String scriptUrl = htmlPage.getElementsByTagName("script").stream().filter(it -> it.getAttribute("src").equals(j.contextPath + "/$stapler/bound/script/null?var=varname")).findFirst().orElseThrow().getAttribute("src"); | ||
|
||
final Page script = wc.goTo(StringUtils.removeStart(scriptUrl, j.contextPath + "/"), "application/javascript"); | ||
final String content = script.getWebResponse().getContentAsString(); | ||
assertThat(content, is("varname = null;")); | ||
} | ||
assertThat(root.invocations, is(0)); | ||
} | ||
|
||
@Test | ||
public void bindUnsafe() throws Exception { | ||
final RootActionImpl root = ExtensionList.lookupSingleton(RootActionImpl.class); | ||
try (JenkinsRule.WebClient wc = j.createWebClient()) { | ||
final HtmlPage htmlPage = wc.goTo(root.getUrlName() + "/unsafe-var"); | ||
final String content = htmlPage | ||
.getElementsByTagName("script") | ||
.stream() | ||
.filter(it -> it.getTextContent().contains("makeStaplerProxy")) | ||
.findFirst() | ||
.orElseThrow() | ||
.getTextContent(); | ||
|
||
assertThat(content, startsWith("window['varname']=makeStaplerProxy('" + j.contextPath + "/$stapler/bound/")); | ||
assertThat(content, endsWith("','test',['annotatedJsMethod1','byName1']);")); | ||
} | ||
assertThat(root.invocations, is(1)); | ||
} | ||
|
||
@Test | ||
public void bindInlineNull() throws Exception { | ||
final RootActionImpl root = ExtensionList.lookupSingleton(RootActionImpl.class); | ||
try (JenkinsRule.WebClient wc = j.createWebClient()) { | ||
final HtmlPage htmlPage = wc.goTo(root.getUrlName() + "/inline-null"); | ||
final String content = htmlPage | ||
.getElementsByTagName("script") | ||
.stream() | ||
.filter(it -> it.getTextContent().contains("var inline")) | ||
.findFirst() | ||
.orElseThrow() | ||
.getTextContent(); | ||
|
||
assertThat(content, containsString("var inline = null")); | ||
} | ||
assertThat(root.invocations, is(0)); | ||
} | ||
|
||
@TestExtension | ||
public static class RootActionImpl extends InvisibleAction implements RootAction { | ||
private int invocations; | ||
|
||
@Override | ||
public String getUrlName() { | ||
return "theRoot"; | ||
} | ||
|
||
@JavaScriptMethod | ||
public void annotatedJsMethod1(String foo) {} | ||
|
||
public void jsByName1() { | ||
invocations++; | ||
} | ||
} | ||
|
||
@TestExtension | ||
public static class RootActionWithWellKnownURL extends InvisibleAction implements RootAction, WithWellKnownURL { | ||
private int invocations; | ||
|
||
@Override | ||
public String getUrlName() { | ||
return "theWellKnownRoot"; | ||
} | ||
|
||
@Override | ||
public String getWellKnownUrl() { | ||
return "/" + getUrlName(); | ||
} | ||
|
||
@JavaScriptMethod | ||
public void annotatedJsMethod2(String foo) {} | ||
|
||
public void jsByName2() { | ||
invocations++; | ||
} | ||
} | ||
} |
2 changes: 2 additions & 0 deletions
2
test/src/test/resources/org/kohsuke/stapler/BindTest/RootActionImpl/adjunct.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// eslint-disable-next-line no-undef | ||
varname.byName1(); |
10 changes: 10 additions & 0 deletions
10
test/src/test/resources/org/kohsuke/stapler/BindTest/RootActionImpl/index.jelly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?jelly escape-by-default='true'?> | ||
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout" xmlns:st="jelly:stapler"> | ||
<l:layout title="The Root"> | ||
<l:main-panel> | ||
<h1>Root Action</h1> | ||
<st:bind var="varname" value="${it}"/> | ||
<st:adjunct includes="org.kohsuke.stapler.BindTest.RootActionImpl.adjunct"/> | ||
</l:main-panel> | ||
</l:layout> | ||
</j:jelly> |
11 changes: 11 additions & 0 deletions
11
test/src/test/resources/org/kohsuke/stapler/BindTest/RootActionImpl/inline-null.jelly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?jelly escape-by-default='true'?> | ||
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout" xmlns:st="jelly:stapler"> | ||
<l:layout title="The Root"> | ||
<l:main-panel> | ||
<h1>Root Action</h1> | ||
<script> | ||
var inline = <st:bind value="${null}"/> | ||
</script> | ||
</l:main-panel> | ||
</l:layout> | ||
</j:jelly> |
10 changes: 10 additions & 0 deletions
10
test/src/test/resources/org/kohsuke/stapler/BindTest/RootActionImpl/null.jelly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?jelly escape-by-default='true'?> | ||
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout" xmlns:st="jelly:stapler"> | ||
<l:layout title="The Root"> | ||
<l:main-panel> | ||
<h1>Root Action with null</h1> | ||
<st:bind var="varname" value="${null}"/> | ||
<st:adjunct includes="org.kohsuke.stapler.BindTest.RootActionImpl.adjunct"/> | ||
</l:main-panel> | ||
</l:layout> | ||
</j:jelly> |
10 changes: 10 additions & 0 deletions
10
test/src/test/resources/org/kohsuke/stapler/BindTest/RootActionImpl/unsafe-var.jelly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?jelly escape-by-default='true'?> | ||
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout" xmlns:st="jelly:stapler"> | ||
<l:layout title="The Root"> | ||
<l:main-panel> | ||
<h1>Root Action</h1> | ||
<st:bind var="window['varname']" value="${it}"/> | ||
<st:adjunct includes="org.kohsuke.stapler.BindTest.RootActionImpl.adjunct"/> | ||
</l:main-panel> | ||
</l:layout> | ||
</j:jelly> |
2 changes: 2 additions & 0 deletions
2
test/src/test/resources/org/kohsuke/stapler/BindTest/RootActionWithWellKnownURL/adjunct.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// eslint-disable-next-line no-undef | ||
varname.byName2(); |
10 changes: 10 additions & 0 deletions
10
test/src/test/resources/org/kohsuke/stapler/BindTest/RootActionWithWellKnownURL/index.jelly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?jelly escape-by-default='true'?> | ||
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout" xmlns:st="jelly:stapler"> | ||
<l:layout title="The Root"> | ||
<l:main-panel> | ||
<h1>Root Action</h1> | ||
<st:bind var="varname" value="${it}"/> | ||
<st:adjunct includes="org.kohsuke.stapler.BindTest.RootActionWithWellKnownURL.adjunct"/> | ||
</l:main-panel> | ||
</l:layout> | ||
</j:jelly> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters