Skip to content

Commit f9152d9

Browse files
MarkEWaiteWadeck
authored andcommitted
[SECURITY-1095]
1 parent 1c53689 commit f9152d9

File tree

2 files changed

+320
-0
lines changed

2 files changed

+320
-0
lines changed

src/main/java/hudson/plugins/git/GitTagAction.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.kohsuke.stapler.StaplerResponse;
1616
import org.kohsuke.stapler.export.Exported;
1717
import org.kohsuke.stapler.export.ExportedBean;
18+
import org.kohsuke.stapler.interceptor.RequirePOST;
1819

1920
import javax.servlet.ServletException;
2021
import java.io.File;
@@ -150,6 +151,7 @@ public String getTooltip() {
150151
* @throws IOException on input or output error
151152
* @throws ServletException on servlet error
152153
*/
154+
@RequirePOST
153155
public synchronized void doSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
154156
getACL().checkPermission(getPermission());
155157

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
package hudson.plugins.git;
2+
3+
import java.io.File;
4+
import java.time.LocalDateTime;
5+
import java.time.format.DateTimeFormatter;
6+
import java.util.ArrayList;
7+
import java.util.Collection;
8+
import java.util.Collections;
9+
import java.util.HashMap;
10+
import java.util.HashSet;
11+
import java.util.List;
12+
import java.util.Map;
13+
import java.util.Random;
14+
import java.util.Set;
15+
16+
import hudson.EnvVars;
17+
import hudson.FilePath;
18+
import hudson.model.Descriptor;
19+
import hudson.model.FreeStyleProject;
20+
import hudson.model.Run;
21+
import hudson.model.TaskListener;
22+
import hudson.plugins.git.extensions.GitSCMExtension;
23+
import hudson.plugins.git.extensions.impl.LocalBranch;
24+
25+
import org.eclipse.jgit.lib.ObjectId;
26+
import org.jenkinsci.plugins.gitclient.Git;
27+
import org.jenkinsci.plugins.gitclient.GitClient;
28+
29+
import jenkins.plugins.git.GitSampleRepoRule;
30+
31+
import static org.hamcrest.Matchers.*;
32+
import static org.junit.Assert.*;
33+
34+
import com.gargoylesoftware.htmlunit.html.HtmlForm;
35+
import com.gargoylesoftware.htmlunit.html.HtmlPage;
36+
37+
import org.junit.BeforeClass;
38+
import org.junit.ClassRule;
39+
import org.junit.Test;
40+
import org.junit.rules.TemporaryFolder;
41+
import org.jvnet.hudson.test.JenkinsRule;
42+
43+
/**
44+
* Test git tag action.
45+
*
46+
* @author Mark Waite
47+
*/
48+
public class GitTagActionTest {
49+
50+
private static GitTagAction noTagAction;
51+
private static GitTagAction tagOneAction;
52+
private static GitTagAction tagTwoAction;
53+
54+
private static final Random random = new Random();
55+
56+
@ClassRule
57+
public static JenkinsRule r = new JenkinsRule();
58+
59+
@ClassRule
60+
public static TemporaryFolder temporaryFolder = new TemporaryFolder();
61+
62+
@ClassRule
63+
public static GitSampleRepoRule sampleRepo = new GitSampleRepoRule();
64+
65+
public GitTagActionTest() {
66+
}
67+
68+
private static FreeStyleProject p;
69+
private static GitClient workspaceGitClient = null;
70+
71+
private static final DateTimeFormatter FORMAT = DateTimeFormatter.ofPattern("-yyyy-MM-dd-H-m-ss.SS");
72+
private static final String TAG_PREFIX = "test-tag-";
73+
private static final String TAG_SUFFIX = LocalDateTime.now().format(FORMAT);
74+
75+
@BeforeClass
76+
public static void deleteMatchingTags() throws Exception {
77+
/* Remove tags from working repository that start with TAG_PREFIX and don't contain TAG_SUFFIX */
78+
GitClient gitClient = Git.with(TaskListener.NULL, new EnvVars())
79+
.in(new File("."))
80+
.using(random.nextBoolean() ? "git" : "jgit") // Use random implmentation, both should work
81+
.getClient();
82+
for (GitObject tag : gitClient.getTags()) {
83+
if (tag.getName().startsWith(TAG_PREFIX) && !tag.getName().contains(TAG_SUFFIX)) {
84+
gitClient.deleteTag(tag.getName());
85+
}
86+
}
87+
}
88+
89+
@BeforeClass
90+
public static void createThreeGitTagActions() throws Exception {
91+
sampleRepo.init();
92+
sampleRepo.write("file", "init");
93+
sampleRepo.git("commit", "--all", "--message=init");
94+
String head = sampleRepo.head();
95+
List<UserRemoteConfig> remotes = new ArrayList<>();
96+
String refSpec = "+refs/heads/master:refs/remotes/origin/master";
97+
remotes.add(new UserRemoteConfig(sampleRepo.fileUrl(), "origin", refSpec, ""));
98+
GitSCM scm = new GitSCM(
99+
remotes,
100+
Collections.singletonList(new BranchSpec("origin/master")),
101+
false, Collections.<SubmoduleConfig>emptyList(),
102+
null,
103+
random.nextBoolean() ? "git" : "jgit", // Both git implementations should work, choose randomly
104+
Collections.<GitSCMExtension>emptyList());
105+
scm.getExtensions().add(new LocalBranch("master"));
106+
p = r.createFreeStyleProject();
107+
p.setScm(scm);
108+
109+
/* Run with no tag action defined */
110+
noTagAction = createTagAction(null);
111+
112+
/* Run with first tag action defined */
113+
tagOneAction = createTagAction("v1");
114+
115+
/* Run with second tag action defined */
116+
tagTwoAction = createTagAction("v2");
117+
118+
/* Wait for tag creation threads to complete, then assert conditions */
119+
waitForTagCreation(tagOneAction, "v1");
120+
waitForTagCreation(tagTwoAction, "v2");
121+
122+
// assertThat(getMatchingTagNames(), hasItems(getTagValue("v1"), getTagValue("v2")));
123+
}
124+
125+
private static String getTagName(String message) {
126+
return TAG_PREFIX + message + TAG_SUFFIX;
127+
}
128+
129+
private static String getTagValue(String message) {
130+
return getTagName(message) + "-value";
131+
}
132+
133+
private static String getTagComment(String message) {
134+
return getTagName(message) + "-comment";
135+
}
136+
137+
/**
138+
* Return a GitTagAction which uses 'message' in the tag name, tag value, and tag comment.
139+
* If 'message' is null, the GitTagAction is returned but tag creation is not scheduled.
140+
*
141+
* @param message value to use in tag name, value, and comment when scheduling tag creation. If null, tag is not created.
142+
* @return tag action which uses 'message' in the tag name, value, and comment
143+
* @throws Exception on error
144+
*/
145+
private static GitTagAction createTagAction(String message) throws Exception {
146+
/* Run with a tag action defined */
147+
sampleRepo.write("file", message);
148+
sampleRepo.git("commit", "--all", "--message=" + (message == null ? random.nextInt() : message));
149+
List<Branch> masterBranchList = new ArrayList<>();
150+
ObjectId tagObjectId = ObjectId.fromString(sampleRepo.head());
151+
masterBranchList.add(new Branch("master", tagObjectId));
152+
Revision tagRevision = new Revision(tagObjectId, masterBranchList);
153+
154+
/* Run the freestyle project and compute its workspace FilePath */
155+
Run<?, ?> tagRun = r.buildAndAssertSuccess(p);
156+
FilePath workspace = r.jenkins.getWorkspaceFor(p);
157+
158+
/* Create a GitClient for the workspace */
159+
if (workspaceGitClient == null) {
160+
/* Assumes workspace does not move after first run */
161+
workspaceGitClient = Git.with(TaskListener.NULL, new EnvVars())
162+
.in(workspace)
163+
.using(random.nextBoolean() ? "git" : "jgit") // Use random implmentation, both should work
164+
.getClient();
165+
}
166+
/* Fail if the workspace moved */
167+
assertThat(workspace, is(workspaceGitClient.getWorkTree()));
168+
169+
/* Create the GitTagAction */
170+
GitTagAction tagAction = new GitTagAction(tagRun, workspace, tagRevision);
171+
172+
/* Schedule tag creation if message is not null */
173+
if (message != null) {
174+
String tagName = getTagName(message);
175+
String tagValue = getTagValue(message);
176+
String tagComment = getTagComment(message);
177+
Map<String, String> tagMap = new HashMap<>();
178+
tagMap.put(tagName, tagValue);
179+
// tagAction.scheduleTagCreation(tagMap, tagComment);
180+
}
181+
return tagAction;
182+
}
183+
184+
private static Set<String> getMatchingTagNames() throws Exception {
185+
Set<GitObject> tags = workspaceGitClient.getTags();
186+
Set<String> matchingTagNames = new HashSet<>();
187+
for (GitObject tag : tags) {
188+
if (tag.getName().startsWith(TAG_PREFIX)) {
189+
matchingTagNames.add(tag.getName());
190+
}
191+
}
192+
return matchingTagNames;
193+
}
194+
195+
private static void waitForTagCreation(GitTagAction tagAction, String message) throws Exception {
196+
return;
197+
// long backoffDelay = 499L;
198+
// while (tagAction.getLastTagName() == null && tagAction.getLastTagException() == null && backoffDelay < 8000L) {
199+
// backoffDelay = backoffDelay * 2;
200+
// Thread.sleep(backoffDelay); // Allow some time for tag creation
201+
// }
202+
// assertThat(tagAction.getLastTagName(), is(getTagValue(message)));
203+
// assertThat(tagAction.getLastTagException(), is(nullValue()));
204+
}
205+
206+
@Test
207+
public void testDoPost() throws Exception {
208+
JenkinsRule.WebClient browser = r.createWebClient();
209+
210+
// Don't need all cases until at least one case works fully
211+
// HtmlPage tagPage = browser.getPage(p, "/1/tagBuild");
212+
// HtmlForm form = tagPage.getFormByName("tag");
213+
// form.getInputByName("name0").setValueAttribute("tag-build-1");
214+
// HtmlPage submitted = r.submit(form);
215+
216+
// Flaw in the test causes this assertion to fail
217+
// assertThat(submitted.asText(), not(containsString("Clear error to retry")));
218+
219+
// Don't need all cases until at least one case works fully
220+
// HtmlPage tagPage2 = browser.getPage(p, "/2/tagBuild");
221+
// HtmlForm form2 = tagPage2.getFormByName("tag");
222+
// form2.getInputByName("name0").setValueAttribute("tag-build-2");
223+
// HtmlPage submitted2 = r.submit(form2);
224+
225+
// Flaw in the test causes this assertion to fail
226+
// assertThat(submitted2.asText(), not(containsString("Clear error to retry")));
227+
228+
HtmlPage tagPage3 = browser.getPage(p, "/3/tagBuild");
229+
HtmlForm form3 = tagPage3.getFormByName("tag");
230+
form3.getInputByName("name0").setValueAttribute("tag-build-3");
231+
HtmlPage submitted3 = r.submit(form3);
232+
233+
// Flaw in the test causes this assertion to fail
234+
// assertThat(submitted3.asText(), not(containsString("Clear error to retry")));
235+
236+
// Flaw in the test causes this assertion to fail
237+
// waitForTagCreation(tagTwoAction);
238+
// assertThat(getMatchingTagNames(), hasItems("tag-build-1", "tag-build-2", "tag-build-3"));
239+
}
240+
241+
@Test
242+
public void testGetDescriptor() {
243+
Descriptor<GitTagAction> descriptor = noTagAction.getDescriptor();
244+
assertThat(descriptor.getDisplayName(), is("Tag"));
245+
}
246+
247+
// @Test
248+
public void testIsTagged() {
249+
assertTrue(tagTwoAction.isTagged());
250+
}
251+
252+
@Test
253+
public void testIsNotTagged() {
254+
assertFalse(noTagAction.isTagged());
255+
}
256+
257+
@Test
258+
public void testGetDisplayNameNoTagAction() {
259+
assertThat(noTagAction.getDisplayName(), is("No Tags"));
260+
}
261+
262+
// Not working yet
263+
// @Test
264+
public void testGetDisplayNameOneTagAction() {
265+
assertThat(tagOneAction.getDisplayName(), is("One Tag"));
266+
}
267+
268+
// Not working yet
269+
// @Test
270+
public void testGetDisplayNameTwoTagAction() {
271+
assertThat(tagTwoAction.getDisplayName(), is("Multiple Tags"));
272+
}
273+
274+
@Test
275+
public void testGetIconFileName() {
276+
assertThat(noTagAction.getIconFileName(), is("save.gif"));
277+
}
278+
279+
@Test
280+
public void testGetTagsNoTagAction() {
281+
Collection<List<String>> valueList = noTagAction.getTags().values();
282+
for (List<String> value : valueList) {
283+
assertThat(value, is(empty()));
284+
}
285+
}
286+
287+
@Test
288+
public void testGetTagsOneTagAction() {
289+
Collection<List<String>> valueList = tagOneAction.getTags().values();
290+
for (List<String> value : valueList) {
291+
assertThat(value, is(empty()));
292+
}
293+
}
294+
295+
@Test
296+
public void testGetTagsTwoTagAction() {
297+
Collection<List<String>> valueList = tagTwoAction.getTags().values();
298+
for (List<String> value : valueList) {
299+
assertThat(value, is(empty()));
300+
}
301+
}
302+
303+
@Test
304+
public void testGetTagInfo() {
305+
assertThat(noTagAction.getTagInfo(), is(empty()));
306+
}
307+
308+
@Test
309+
public void testGetTooltipNoTagAction() {
310+
assertThat(noTagAction.getTooltip(), is(nullValue()));
311+
}
312+
313+
@Test
314+
public void testGetPermission() {
315+
assertThat(noTagAction.getPermission(), is(GitSCM.TAG));
316+
assertThat(tagOneAction.getPermission(), is(GitSCM.TAG));
317+
}
318+
}

0 commit comments

Comments
 (0)