From b5e678af9d036d6bc51c1dbbb697cf7764353e98 Mon Sep 17 00:00:00 2001 From: ikedam Date: Sat, 8 Jun 2019 13:58:10 +0900 Subject: [PATCH] [JENKINS-57917] Add `AddHtmlBadge` feature --- pom.xml | 2 +- .../GroovyPostbuildRecorder.java | 15 ++- .../GroovyPostbuildRecorderTest.java | 122 ++++++++++++++++++ 3 files changed, 134 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 5f43e8b..de25c5c 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ 2.121.1 8 - 1.2 + 1.5 2.20 2.69 diff --git a/src/main/java/org/jvnet/hudson/plugins/groovypostbuild/GroovyPostbuildRecorder.java b/src/main/java/org/jvnet/hudson/plugins/groovypostbuild/GroovyPostbuildRecorder.java index a5e2579..6ac7078 100644 --- a/src/main/java/org/jvnet/hudson/plugins/groovypostbuild/GroovyPostbuildRecorder.java +++ b/src/main/java/org/jvnet/hudson/plugins/groovypostbuild/GroovyPostbuildRecorder.java @@ -56,8 +56,10 @@ import org.jenkinsci.plugins.scriptsecurity.scripts.ApprovalContext; import org.jenkinsci.plugins.scriptsecurity.scripts.ClasspathEntry; +import com.jenkinsci.plugins.badge.action.AbstractBadgeAction; import com.jenkinsci.plugins.badge.action.BadgeAction; import com.jenkinsci.plugins.badge.action.BadgeSummaryAction; +import com.jenkinsci.plugins.badge.action.HtmlBadgeAction; /** This class associates {@link BadgeAction}s to a build. */ @SuppressWarnings("unchecked") @@ -169,6 +171,11 @@ public void addErrorBadge(String text) { build.addAction(BadgeAction.createErrorBadge(text)); } + @Whitelisted + public void addHtmlBadge(String html) { + build.addAction(HtmlBadgeAction.createHtmlBadge(html)); + } + @Whitelisted public String getResult() { Result r = build.getResult(); @@ -177,18 +184,18 @@ public String getResult() { @Whitelisted public void removeBadges() { - List badgeActions = build.getActions(BadgeAction.class); - for (BadgeAction a : badgeActions) { + List badgeActions = build.getActions(AbstractBadgeAction.class); + for (AbstractBadgeAction a : badgeActions) { build.removeAction(a); } } @Whitelisted public void removeBadge(int index) { - List badgeActions = build.getActions(BadgeAction.class); + List badgeActions = build.getActions(AbstractBadgeAction.class); if(index < 0 || index >= badgeActions.size()) { listener.error("Invalid badge index: " + index + ". Allowed values: 0 .. " + (badgeActions.size()-1)); } else { - BadgeAction action = badgeActions.get(index); + AbstractBadgeAction action = badgeActions.get(index); build.removeAction(action); } } diff --git a/src/test/java/org/jvnet/hudson/plugins/groovypostbuild/GroovyPostbuildRecorderTest.java b/src/test/java/org/jvnet/hudson/plugins/groovypostbuild/GroovyPostbuildRecorderTest.java index 12bd9e2..0795e76 100644 --- a/src/test/java/org/jvnet/hudson/plugins/groovypostbuild/GroovyPostbuildRecorderTest.java +++ b/src/test/java/org/jvnet/hudson/plugins/groovypostbuild/GroovyPostbuildRecorderTest.java @@ -47,6 +47,7 @@ import org.acegisecurity.Authentication; import org.apache.commons.lang.StringUtils; +import org.hamcrest.Matchers; import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript; import org.jenkinsci.plugins.scriptsecurity.scripts.ClasspathEntry; import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval; @@ -501,6 +502,95 @@ public void testBadgeMigration() throws Exception { } } + @Test + public void testAddShortText() throws Exception { + FreeStyleProject p = j.createFreeStyleProject(); + + p.getPublishersList().add(new GroovyPostbuildRecorder( + new SecureGroovyScript( + "manager.addShortText('some-badge-text');", + true, // sandbox + Collections.emptyList() + ), + 2, // behavior + false // runForMatrixParent + )); + + j.assertBuildStatusSuccess(p.scheduleBuild2(0)); + + assertThat( + j.createWebClient().getPage(p).asText(), + Matchers.containsString("some-badge-text") + ); + } + + @Test + public void testAddShortTextHtmlIsEscaped() throws Exception { + // This test is to make it clear that + // addShortText() doesn't allow HTMLs + // even though that implementation is + // in badge-plugin. + FreeStyleProject p = j.createFreeStyleProject(); + + p.getPublishersList().add(new GroovyPostbuildRecorder( + new SecureGroovyScript( + "manager.addShortText('
foobar
');", + true, // sandbox + Collections.emptyList() + ), + 2, // behavior + false // runForMatrixParent + )); + + assertNull(j.createWebClient().getPage(p).getElementById("should-be-escaped")); + } + + @Test + public void testAddHtmlBadge() throws Exception { + FreeStyleProject p = j.createFreeStyleProject(); + + p.getPublishersList().add(new GroovyPostbuildRecorder( + new SecureGroovyScript( + "manager.addHtmlBadge('
foobar
');", + true, // sandbox + Collections.emptyList() + ), + 2, // behavior + false // runForMatrixParent + )); + + j.assertBuildStatusSuccess(p.scheduleBuild2(0)); + + assertEquals( + "foobar", + j.createWebClient().getPage(p).getElementById("added-as-badge").getTextContent() + ); + } + + + @Test + public void testAddHtmlBadgeForUnsafeHtml() throws Exception { + // This test is to make it sure that + // addHtmlBadge() doesn't allow danger HTMLs + // even though that implementation is + // in badge-plugin. + FreeStyleProject p = j.createFreeStyleProject(); + + p.getPublishersList().add(new GroovyPostbuildRecorder( + new SecureGroovyScript( + "manager.addHtmlBadge('');", + true, // sandbox + Collections.emptyList() + ), + 2, // behavior + false // runForMatrixParent + )); + + j.assertBuildStatusSuccess(p.scheduleBuild2(0)); + + assertNull(j.createWebClient().getPage(p).getElementById("should-be-untainted")); + } + @Test public void testRemoveBadge() throws Exception { FreeStyleProject p = j.createFreeStyleProject(); @@ -555,6 +645,38 @@ public void testRemoveBadges() throws Exception { ); } + @Test + public void testRemoveBadgeForHtmlBadge() throws Exception { + // removeBadge() also removes HtmlBadges + FreeStyleProject p = j.createFreeStyleProject(); + + p.getPublishersList().add(new GroovyPostbuildRecorder( + new SecureGroovyScript( + "manager.addHtmlBadge('test1');\n" + + "manager.addShortText('test2');\n" + + "manager.removeBadge(0);", + true, // sandbox + Collections.emptyList() + ), + 2, // behavior + false // runForMatrixParent + )); + + FreeStyleBuild b = j.assertBuildStatusSuccess(p.scheduleBuild2(0)); + assertEquals( + Arrays.asList("test2"), + Lists.transform( + b.getActions(BadgeAction.class), + new Function() { + @Override + public String apply(BadgeAction badge) { + return badge.getText(); + } + } + ) + ); + } + @Test public void testRemoveSummary() throws Exception { String template = "method org.jvnet.hudson.plugins.groovypostbuild.GroovyPostbuildRecorder$BadgeManager %s";