diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 9b5fc51..e98c397 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -12,6 +12,7 @@ jobs: - name: Set up JDK 21 uses: actions/setup-java@v4 with: + distribution: 'temurin' java-version: 21 - name: Build with Maven run: mvn -B package --file pom.xml diff --git a/README.md b/README.md index 10e6c85..9e4e6fa 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,13 @@ For more information see the [homepage]. # Change Log +##### Version 0.0.17 (February 18, 2025) +- Remove administrative monitor "reminder to configure allowed base dirs". +- Fix allowed base dirs feature: + - Remove userContent directory check for nodes +- Dependency updates + + ##### Version 0.0.16 (December 05, 2024) - Bugfix supporting jenkins cli and buildWithParameters POSTs [JENKINS-60978](https://issues.jenkins.io/browse/JENKINS-60978) diff --git a/pom.xml b/pom.xml index 5c98b76..a5ace64 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.plugins plugin - 5.3 + 5.6 @@ -68,7 +68,7 @@ io.jenkins.tools.bom bom-${jenkins.baseline}.x - 3696.vb_b_4e2d1a_0542 + 4051.v78dce3ce8b_d6 pom import diff --git a/src/main/java/alex/jenkins/plugins/AllowedBaseDirReminder.java b/src/main/java/alex/jenkins/plugins/AllowedBaseDirReminder.java deleted file mode 100644 index 2a42643..0000000 --- a/src/main/java/alex/jenkins/plugins/AllowedBaseDirReminder.java +++ /dev/null @@ -1,23 +0,0 @@ -package alex.jenkins.plugins; - -import hudson.Extension; -import hudson.model.AdministrativeMonitor; - -/** - * Displays the AllowedBaseDirsReminder that the global configuration must be done. - */ -@Extension -public class AllowedBaseDirReminder extends AdministrativeMonitor { - - - @Override - public String getDisplayName() { - return "Please configure allowed base dirs for File System List Parameter - Allowed base directories"; - } - - - @Override - public boolean isActivated() { - return true; - } -} diff --git a/src/main/java/alex/jenkins/plugins/FileSystemListParameterDefinition.java b/src/main/java/alex/jenkins/plugins/FileSystemListParameterDefinition.java index 65b4191..3490b36 100644 --- a/src/main/java/alex/jenkins/plugins/FileSystemListParameterDefinition.java +++ b/src/main/java/alex/jenkins/plugins/FileSystemListParameterDefinition.java @@ -36,10 +36,10 @@ import hudson.remoting.VirtualChannel; import hudson.util.FormValidation; import jenkins.model.Jenkins; +import jenkins.MasterToSlaveFileCallable; import net.sf.json.JSONArray; import net.sf.json.JSONObject; - /** * @author aendter * @@ -47,20 +47,24 @@ public class FileSystemListParameterDefinition extends ParameterDefinition { private static final long serialVersionUID = 9032072543915872650L; - private static final Logger LOGGER = Logger.getLogger(FileSystemListParameterDefinition.class.getName()); + public static final String MASTER = "master"; + static FileSystemListParameterGlobalConfiguration testGC = null; - public static final String MASTER = "master"; + static void addTestGC(FileSystemListParameterGlobalConfiguration testGC) { + FileSystemListParameterDefinition.testGC = testGC; + } - public static enum FsObjectTypes implements java.io.Serializable { + public static enum FsObjectTypes { ALL, DIRECTORY, FILE, SYMLINK } - public static enum FsSelectTypes implements java.io.Serializable { + public static enum FsSelectTypes { SINGLE_SELECT, MULTI_SELECT } - @Extension @Symbol("fileSystemList") + @Extension + @Symbol("fileSystemList") public static class DescriptorImpl extends ParameterDescriptor { @Override public String getDisplayName() { @@ -74,29 +78,29 @@ public FormValidation doCheckName(@QueryParameter final String name) throws IOEx return FormValidation.ok(); } - public FormValidation doCheckPath(@QueryParameter final String path, @QueryParameter final String selectedNodeName) throws IOException, InterruptedException { + public FormValidation doCheckPath(@QueryParameter final String path, @QueryParameter final String selectedNodeName) + throws IOException, InterruptedException { if (StringUtils.isBlank(path)) { return FormValidation.error(Messages.FileSystemListParameterDefinition_PathCanNotBeEmpty()); } - + // Check Path is symlink if (hudson.Util.isSymlink(new File(path))) { return FormValidation.error(Messages.FileSystemListParameterDefinition_SymlinkPathNotAllowed(), path); } - + Jenkins instance = Jenkins.getInstanceOrNull(); // Check Path allowed - if (instance != null && !isAllowedPath(path, instance.getRootDir(), null)){ + if (instance != null && !Utils.isAllowedPath(path, instance.getRootDir(), null)) { return FormValidation.error(Messages.FileSystemListParameterDefinition_PathNotAllowed(), path); } - // Check nodes Computer computer = null; VirtualChannel channel = null; - if (selectedNodeName==null || selectedNodeName.equals(MASTER)) { + if (selectedNodeName == null || selectedNodeName.equals(MASTER)) { File dir = new File(path); if (!dir.exists()) { return FormValidation.error(Messages.FileSystemListParameterDefinition_PathDoesntExist(), path); @@ -110,15 +114,13 @@ public FormValidation doCheckPath(@QueryParameter final String path, @QueryParam } else { - if (!selectedNodeName.trim().isEmpty() && instance != null) { computer = instance.getComputer(selectedNodeName); if (computer != null) { channel = computer.getChannel(); } } - - + FilePath filepath = new FilePath(channel, path); if (!filepath.exists()) { return FormValidation.error(Messages.FileSystemListParameterDefinition_PathDoesntExist(), path); @@ -156,37 +158,6 @@ private FormValidation checkRegex(String regex) { } - // TODO: Remove administrativeMonitor with next release! - //check allowedPath - static boolean isAllowedPath(final String path, final File jenkinsRootDir, FileSystemListParameterGlobalConfiguration testGC) { - FileSystemListParameterGlobalConfiguration globalConfig; - // inject testing gc - if(testGC==null) { - globalConfig = FileSystemListParameterGlobalConfiguration.get(); - } else { - globalConfig = testGC; - } - List additionalBaseDirs = globalConfig.getAdditionalBaseDirs(); - Path pathToCheck; - try { - pathToCheck = new File(path).toPath().toRealPath(); - // userContent - if (globalConfig.isEnabledUserContent()) { - String userContentPath = jenkinsRootDir.getCanonicalPath() + File.separator + "userContent" + File.separator; - if (pathToCheck.startsWith(userContentPath)) {return true;} - } - // AllowedPathList - for (AdditionalBaseDirPath baseDir : additionalBaseDirs) { - String baseDirCanonical = new File(baseDir.getAdditionalBaseDirPath()).getCanonicalPath() + File.separator; - if (pathToCheck.startsWith(baseDirCanonical)) {return true;} - } - } catch (IOException e) { - LOGGER.warning(String.format(Messages.FileSystemListParameterDefinition_PathCheckError(), path)); - } - return false; - } - - private String selectedNodeName; private String path; private String selectedType; @@ -198,21 +169,22 @@ static boolean isAllowedPath(final String path, final File jenkinsRootDir, FileS private String regexExcludePattern; private String value; private String defaultValue; - private boolean includePathInValue; + private boolean includePathInValue; /** * @param name * @param description */ @DataBoundConstructor - public FileSystemListParameterDefinition(String name, String description, String selectedNodeName, String path, String defaultValue, String selectedType, + public FileSystemListParameterDefinition(String name, String description, String selectedNodeName, String path, + String defaultValue, String selectedType, String formSelectType, String regexIncludePattern, String regexExcludePattern, boolean sortByLastModified, boolean sortReverseOrder, boolean includePathInValue) { - super(name); + super(name); this.selectedNodeName = selectedNodeName; - this.path = Util.fixNull(path); + this.path = Util.fixNull(path); this.defaultValue = defaultValue; this.selectedType = selectedType; this.formSelectType = formSelectType; @@ -221,34 +193,35 @@ public FileSystemListParameterDefinition(String name, String description, String this.sortReverseOrder = sortReverseOrder; this.regexIncludePattern = regexIncludePattern; this.regexExcludePattern = regexExcludePattern; - this.includePathInValue = includePathInValue; + this.includePathInValue = includePathInValue; } - // https://issues.jenkins.io/browse/JENKINS-74886 @Override public ParameterValue createValue(CLICommand command, String value) throws IOException, InterruptedException { - StringParameterValue parameterValue = new StringParameterValue(this.getName(), this.isIncludePathInValue() ? new File(this.path, String.valueOf(value)).getPath() : String.valueOf(value)); + StringParameterValue parameterValue = new StringParameterValue(this.getName(), + this.isIncludePathInValue() ? new File(this.path, String.valueOf(value)).getPath() : String.valueOf(value)); return checkParameterValue(parameterValue); } - + private ParameterValue checkParameterValue(StringParameterValue parameterValue) { try { List valuesPossible = getFsObjectsList(); if (valuesPossible.contains(parameterValue.getValue())) { return parameterValue; } else { - //throw new UnsupportedOperationException("Value not valid!"); - //return new StringParameterValue(this.getName(), "injected_value_not_valid__please_check_objects_list"); - LOGGER.warning(String.format(Messages.FileSystemListParameterDefinition_InjectedObjectNotFoundAtPath(), parameterValue.getValue(), path)); + // throw new UnsupportedOperationException("Value not valid!"); + // return new StringParameterValue(this.getName(), + // "injected_value_not_valid__please_check_objects_list"); + LOGGER.warning(String.format(Messages.FileSystemListParameterDefinition_InjectedObjectNotFoundAtPath(), + parameterValue.getValue(), path)); return null; } } catch (Exception e) { throw new UnsupportedOperationException("Problem checking value: " + e.getMessage()); } } - - + @Override public ParameterValue createValue(StaplerRequest2 request) { String parameterValues[] = request.getParameterValues(getName()); @@ -256,7 +229,8 @@ public ParameterValue createValue(StaplerRequest2 request) { return getDefaultParameterValue(); } String value = parameterValues[0]; - StringParameterValue stringParameterValue = new StringParameterValue(this.getName(), this.isIncludePathInValue() ? new File(this.path, String.valueOf(value)).getPath() : String.valueOf(value)); + StringParameterValue stringParameterValue = new StringParameterValue(this.getName(), + this.isIncludePathInValue() ? new File(this.path, String.valueOf(value)).getPath() : String.valueOf(value)); return checkParameterValue(stringParameterValue); } @@ -266,16 +240,16 @@ public ParameterValue createValue(StaplerRequest2 request, JSONObject jO) { Object value = jO.get("value"); String strValue = ""; if (value instanceof String) { - strValue = this.isIncludePathInValue() ? new File(this.path, String.valueOf(value)).getPath() : String.valueOf(value); + strValue = this.isIncludePathInValue() ? new File(this.path, String.valueOf(value)).getPath() + : String.valueOf(value); } else if (value instanceof JSONArray) { JSONArray jsonValues = (JSONArray) value; - strValue = StringUtils.join( - this.isIncludePathInValue() ? jsonValues.stream() - .filter(e -> !StringUtils.isBlank(String.valueOf(e))) - .map(e -> new File(this.path, String.valueOf(e)).getPath()).iterator() - : jsonValues.iterator(), - ',' - ); + strValue = StringUtils.join( + this.isIncludePathInValue() ? jsonValues.stream() + .filter(e -> !StringUtils.isBlank(String.valueOf(e))) + .map(e -> new File(this.path, String.valueOf(e)).getPath()).iterator() + : jsonValues.iterator(), + ','); } return new FileSystemListParameterValue(getName(), strValue); } @@ -291,10 +265,9 @@ public ParameterValue getDefaultParameterValue() { String.format(Messages.FileSystemListParameterDefinition_SymlinkDetectionError(), localDefaultValue)); } if (!StringUtils.isBlank(localDefaultValue)) { - return new FileSystemListParameterValue( - getName(), - this.isIncludePathInValue() ? new File(this.path, localDefaultValue).getPath() : localDefaultValue - ); + return new FileSystemListParameterValue( + getName(), + this.isIncludePathInValue() ? new File(this.path, localDefaultValue).getPath() : localDefaultValue); } return super.getDefaultParameterValue(); } @@ -308,33 +281,46 @@ private String getEffectiveDefaultValue() throws Exception { } } - public List getFsObjectsList() throws Exception { - - Computer computer = null; - VirtualChannel channel = null; - Jenkins instance = Jenkins.getInstanceOrNull(); - - if (getSelectedNodeName() != null && !getSelectedNodeName().trim().isEmpty() && instance != null) { - computer = instance.getComputer(getSelectedNodeName()); - if (computer != null) { - channel = computer.getChannel(); - } + static class FilesLister extends MasterToSlaveFileCallable> { + + private static final long serialVersionUID = 1; + private FsObjectTypes selectedEnumType; + private String regexIncludePattern; + private String regexExcludePattern; + private String path; + private boolean isSortByLastModified; + private boolean isSortReverseOrder; + + FilesLister(FsObjectTypes selectedEnumType, String regexIncludePattern, String regexExcludePattern, + String path, boolean isSortByLastModified, boolean isSortReverseOrder) { + this.selectedEnumType = selectedEnumType; + this.regexIncludePattern = regexIncludePattern; + this.regexExcludePattern = regexExcludePattern; + this.path = path; + this.isSortByLastModified = isSortByLastModified; + this.isSortReverseOrder = isSortReverseOrder; } + @Override + public List invoke(File rootDir, VirtualChannel channel) { + TreeMap map = new TreeMap<>(); + + try { + // additional check prevent symlink usage + Path realPath = rootDir.toPath().toRealPath(); + Path absolutePath = rootDir.toPath().toAbsolutePath(); + if(!realPath.equals(absolutePath)) { + List notAllowedList = new ArrayList(); + String msgNotAllowed = String.format(Messages.FileSystemListParameterDefinition_PathNotAllowed()+" Symlinks are not allowed to be used as list objects path.", this.path) + .toString(); + LOGGER.warning(msgNotAllowed); + notAllowedList.add(msgNotAllowed); + return notAllowedList; + } + File[] listFiles = rootDir.listFiles(); - FilePath rootPath = new FilePath(channel, path); - class FilesLister implements FileCallable> { - - private static final long serialVersionUID = 1; - - @Override - public List invoke(File rootDir, VirtualChannel channel) { - final TreeMap map = new TreeMap<>(); - try { - File[] listFiles = rootDir.listFiles(); - - if (listFiles != null) { - switch (getSelectedEnumType()) { + if (listFiles != null) { + switch (this.selectedEnumType) { case SYMLINK: createSymlinkMap(listFiles, map); break; @@ -347,135 +333,128 @@ public List invoke(File rootDir, VirtualChannel channel) { default: createAllObjectsMap(listFiles, map); break; - } } - } catch (IOException e) { - LOGGER.warning(String.format(Messages.FileSystemListParameterDefinition_SymlinkDetectionError(), - "Failed to obtain")); } - return sortList(map); + } catch (IOException e) { + LOGGER.warning(String.format(Messages.FileSystemListParameterDefinition_SymlinkDetectionError(), + "Failed to obtain")); } - @Override - public void checkRoles(RoleChecker rc) throws SecurityException { - throw new UnsupportedOperationException("Not supported yet."); // To change body of generated methods, - // choose Tools | Templates. + if (map.isEmpty()) { + List list = new ArrayList(); + String msg = String.format(Messages.FileSystemListParameterDefinition_NoObjectsFoundAtPath(), + this.selectedEnumType, this.regexIncludePattern, this.regexExcludePattern, this.path).toString(); + LOGGER.warning(msg); + list.add(msg); + return list; } - } - return rootPath.act(new FilesLister()); - } - - List sortList(Map map) { - List list; - Jenkins instance = Jenkins.getInstanceOrNull(); - if (instance != null && !isAllowedPath(this.path, instance.getRootDir(), null)){ - list = new ArrayList(); - String msg = String.format(Messages.FileSystemListParameterDefinition_PathNotAllowed(), - getPath()).toString(); - LOGGER.warning(msg); - list.add(msg); - } else if (map.isEmpty()) { - list = new ArrayList(); - String msg = String.format(Messages.FileSystemListParameterDefinition_NoObjectsFoundAtPath(), - getSelectedEnumType(), getRegexIncludePattern(), getRegexExcludePattern(), getPath()).toString(); - LOGGER.warning(msg); - list.add(msg); - } else { - // Sorting: - if (isSortByLastModified()) { - list = createTimeSortedList(map); - } else { - list = new ArrayList(); - list.addAll(map.keySet()); - } - if (isSortReverseOrder()) { - Collections.reverse(list); - } + return sortList(map); } - return list; - } + private boolean isPatternMatching(String name) { - static List createTimeSortedList(Map map) { - List list = new ArrayList(); - - Collection valuesC = map.values(); - List sortList = new ArrayList(valuesC); - Collections.sort(sortList); + if (this.regexIncludePattern.equals("") && this.regexExcludePattern.equals("")) { + return true; + } - // iterate over sorted values - for (Long value : sortList) { + if (!this.regexIncludePattern.equals("") && this.regexExcludePattern.equals("")) { + return name.matches(this.regexIncludePattern); + } + if (this.regexIncludePattern.equals("") && !this.regexExcludePattern.equals("")) { + return !name.matches(this.regexExcludePattern); + } - if (map.containsValue(value)) { + return name.matches(this.regexIncludePattern) && !name.matches(this.regexExcludePattern); + } - // key with lowest value will be added first - for (Map.Entry entry : map.entrySet()) { - if (value.equals(entry.getValue())) { - list.add(entry.getKey()); - } + private void createSymlinkMap(File[] listFiles, Map target) throws IOException { + for (File file : listFiles) { + if (!file.isHidden() && hudson.Util.isSymlink(file) && isPatternMatching(file.getName())) { + target.put(file.getName(), file.lastModified()); + LOGGER.finest("add " + file); } } } - return list; - } - - private boolean isPatternMatching(String name) { - - if (getRegexIncludePattern().equals("") && getRegexExcludePattern().equals("")) { - return true; + private void createDirectoryMap(File[] listFiles, Map target) throws IOException { + for (File file : listFiles) { + if (!file.isHidden() && file.isDirectory() && !hudson.Util.isSymlink(file) + && isPatternMatching(file.getName())) { + target.put(file.getName(), file.lastModified()); + LOGGER.finest("add " + file); + } + } } - if (!getRegexIncludePattern().equals("") && getRegexExcludePattern().equals("")) { - return name.matches(getRegexIncludePattern()); - } - if (getRegexIncludePattern().equals("") && !getRegexExcludePattern().equals("")) { - return !name.matches(getRegexExcludePattern()); + private void createFileMap(File[] listFiles, Map target) throws IOException { + for (File file : listFiles) { + if (!file.isHidden() && file.isFile() && !hudson.Util.isSymlink(file) && isPatternMatching(file.getName())) { + target.put(file.getName(), file.lastModified()); + LOGGER.finest("add " + file); + } + } } - return name.matches(getRegexIncludePattern()) && !name.matches(getRegexExcludePattern()); - } - - private void createSymlinkMap(File[] listFiles, Map target) throws IOException { - - for (File file : listFiles) { - if (!file.isHidden() && hudson.Util.isSymlink(file) && isPatternMatching(file.getName())) { - target.put(file.getName(), file.lastModified()); - LOGGER.finest("add " + file); + private void createAllObjectsMap(File[] listFiles, Map target) { + for (File file : listFiles) { + if (!file.isHidden() && isPatternMatching(file.getName())) { + target.put(file.getName(), file.lastModified()); + LOGGER.finest("add " + file); + } } } - } - private void createDirectoryMap(File[] listFiles, Map target) throws IOException { + List sortList(Map map) { + List list = new ArrayList(); - for (File file : listFiles) { - if (!file.isHidden() && file.isDirectory() && !hudson.Util.isSymlink(file) && isPatternMatching(file.getName())) { - target.put(file.getName(), file.lastModified()); - LOGGER.finest("add " + file); + if (this.isSortByLastModified) { + list = Utils.createTimeSortedList(map); + } else { + list.addAll(map.keySet()); + } + if (this.isSortReverseOrder) { + Collections.reverse(list); } + return list; } } - private void createFileMap(File[] listFiles, Map target) throws IOException { + public List getFsObjectsList() throws Exception { + + Computer computer = null; + VirtualChannel channel = null; + Jenkins instance = Jenkins.getInstanceOrNull(); + File jenkinsRootdir = null; - for (File file : listFiles) { - if (!file.isHidden() && file.isFile() && !hudson.Util.isSymlink(file) && isPatternMatching(file.getName())) { - target.put(file.getName(), file.lastModified()); - LOGGER.finest("add " + file); + if (getSelectedNodeName() != null && !getSelectedNodeName().trim().isEmpty() && instance != null) { + computer = instance.getComputer(getSelectedNodeName()); + if (computer != null) { + channel = computer.getChannel(); } + jenkinsRootdir = instance.getRootDir(); } - } - - private void createAllObjectsMap(File[] listFiles, Map target) { - for (File file : listFiles) { - if (!file.isHidden() && isPatternMatching(file.getName())) { - target.put(file.getName(), file.lastModified()); - LOGGER.finest("add " + file); - } + // handle not allowed + List notAllowedList = new ArrayList(); + String msgNotAllowed = String.format(Messages.FileSystemListParameterDefinition_PathNotAllowed(), this.path) + .toString(); + LOGGER.warning(msgNotAllowed); + notAllowedList.add(msgNotAllowed); + if (instance == null) { + notAllowedList.add("Jenkins instance is null! Sorry."); + return notAllowedList; } + if (!Utils.isAllowedPath(this.path, jenkinsRootdir, testGC)) { + return notAllowedList; + } + + FilePath rootPath = new FilePath(channel, this.path); + + return rootPath.act(new FilesLister(getSelectedEnumType(), getRegexIncludePattern(), getRegexExcludePattern(), + getPath(), isSortByLastModified(), isSortReverseOrder())); } + /* * Creates list to display in config.jelly */ @@ -542,20 +521,19 @@ public static List getNodeNames() { ArrayList list = new ArrayList(); final List nodes = Jenkins.get().getNodes(); - // add master - list.add(MASTER); - for (Node node : nodes) { - String tmpNodeName = node.getNodeName(); - if (StringUtils.isNotBlank(tmpNodeName)) { - LOGGER.finest("# add " + tmpNodeName); - list.add(tmpNodeName); - } + // add master + list.add(MASTER); + for (Node node : nodes) { + String tmpNodeName = node.getNodeName(); + if (StringUtils.isNotBlank(tmpNodeName)) { + LOGGER.finest("# add " + tmpNodeName); + list.add(tmpNodeName); } + } return list; } - public String getPath() { return path; } @@ -599,17 +577,16 @@ public String getSelectedNodeName() { public String setSelectedNodeName() { return selectedNodeName; } - + public String getDefaultValue() { return defaultValue; } public void setDescription(String description) { - super.setDescription(description); + super.setDescription(description); } public boolean isIncludePathInValue() { return includePathInValue; } - } diff --git a/src/main/java/alex/jenkins/plugins/Utils.java b/src/main/java/alex/jenkins/plugins/Utils.java new file mode 100644 index 0000000..a683a64 --- /dev/null +++ b/src/main/java/alex/jenkins/plugins/Utils.java @@ -0,0 +1,75 @@ +package alex.jenkins.plugins; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +public class Utils { + + private static final Logger LOGGER = Logger.getLogger(Utils.class.getName()); + + static boolean isAllowedPath(final String path, final File jenkinsRootDir, FileSystemListParameterGlobalConfiguration testGC) { + FileSystemListParameterGlobalConfiguration globalConfig; + // use testing gc + if (testGC == null) { + globalConfig = FileSystemListParameterGlobalConfiguration.get(); + } else { + globalConfig = testGC; + } + List additionalBaseDirs = globalConfig.getAdditionalBaseDirs(); + Path pathToCheck; + try { + // note: check absolute equals realpath is done in callable + pathToCheck = new File(path).toPath().toAbsolutePath(); + // userContent + if (globalConfig.isEnabledUserContent() && jenkinsRootDir != null) { + String userContentPath = jenkinsRootDir.getCanonicalPath() + File.separator + "userContent" + File.separator; + if (pathToCheck.startsWith(userContentPath)) { + return true; + } + } + + // AllowedPathList + for (AdditionalBaseDirPath baseDir : additionalBaseDirs) { + String baseDirCanonical = new File(baseDir.getAdditionalBaseDirPath()).getCanonicalPath() + File.separator; + if (pathToCheck.startsWith(baseDirCanonical)) { + return true; + } + } + } catch (IOException e) { + LOGGER.warning(String.format(Messages.FileSystemListParameterDefinition_PathCheckError(), path)); + } + return false; + } + + static List createTimeSortedList(Map map) { + List list = new ArrayList(); + + Collection valuesC = map.values(); + List sortList = new ArrayList(valuesC); + Collections.sort(sortList); + + // iterate over sorted values + for (Long value : sortList) { + + if (map.containsValue(value)) { + + // key with lowest value will be added first + for (Map.Entry entry : map.entrySet()) { + if (value.equals(entry.getValue())) { + list.add(entry.getKey()); + } + } + } + } + + return list; + } + +} diff --git a/src/main/resources/alex/jenkins/plugins/AllowedBaseDirReminder/message.jelly b/src/main/resources/alex/jenkins/plugins/AllowedBaseDirReminder/message.jelly deleted file mode 100644 index fb1d2ed..0000000 --- a/src/main/resources/alex/jenkins/plugins/AllowedBaseDirReminder/message.jelly +++ /dev/null @@ -1,7 +0,0 @@ - - -
- File System List Parameter: - ${%TodoMessage} -
-
\ No newline at end of file diff --git a/src/main/resources/alex/jenkins/plugins/AllowedBaseDirReminder/message.properties b/src/main/resources/alex/jenkins/plugins/AllowedBaseDirReminder/message.properties deleted file mode 100644 index 8ae9d92..0000000 --- a/src/main/resources/alex/jenkins/plugins/AllowedBaseDirReminder/message.properties +++ /dev/null @@ -1 +0,0 @@ -TodoMessage=With version 0.0.15 allowed base dirs feature is enabled. Without additional configuration the plugin will not be allowed to list objects outside the jenkins userContent on master or nodes. The list of allowed base dirs can be configured in manage/configure page. \ No newline at end of file diff --git a/src/main/resources/alex/jenkins/plugins/FileSystemListParameterGlobalConfiguration/config.jelly b/src/main/resources/alex/jenkins/plugins/FileSystemListParameterGlobalConfiguration/config.jelly index 4de742f..f4d75ca 100644 --- a/src/main/resources/alex/jenkins/plugins/FileSystemListParameterGlobalConfiguration/config.jelly +++ b/src/main/resources/alex/jenkins/plugins/FileSystemListParameterGlobalConfiguration/config.jelly @@ -5,7 +5,7 @@ - + diff --git a/src/main/resources/alex/jenkins/plugins/FileSystemListParameterGlobalConfiguration/help-enabledUserContent.html b/src/main/resources/alex/jenkins/plugins/FileSystemListParameterGlobalConfiguration/help-enabledUserContent.html index c478596..e43a8ab 100644 --- a/src/main/resources/alex/jenkins/plugins/FileSystemListParameterGlobalConfiguration/help-enabledUserContent.html +++ b/src/main/resources/alex/jenkins/plugins/FileSystemListParameterGlobalConfiguration/help-enabledUserContent.html @@ -1,3 +1,3 @@
- Default base dir for allowed paths for the plugin. Allows JENKINS_HOME/userContent on built-in and nodes. + Default base dir for allowed paths for the plugin. Allows JENKINS_HOME/userContent on built-in.
\ No newline at end of file diff --git a/src/test/java/alex/jenkins/plugins/ChangeSequenceTest.java b/src/test/java/alex/jenkins/plugins/ChangeSequenceTest.java index c4be7fb..2da0346 100644 --- a/src/test/java/alex/jenkins/plugins/ChangeSequenceTest.java +++ b/src/test/java/alex/jenkins/plugins/ChangeSequenceTest.java @@ -7,18 +7,29 @@ import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +import alex.jenkins.plugins.FileSystemListParameterDefinition.FilesLister; public class ChangeSequenceTest { - String path; + @Rule + public JenkinsRule j = new JenkinsRule(); - @Before + String path; + FileSystemListParameterGlobalConfiguration globalConfigAllowedPaths; + + @Before public void setup(){ URL resource = getClass().getResource("/1"); Assert.assertNotNull("Test test directory missing", resource); path = resource.getPath(); + + TestUtils tu = new TestUtils(); + globalConfigAllowedPaths = tu.createTestGC(path); } @Test @@ -35,7 +46,8 @@ public void testSorting() { map.put(f1.getName(), (long) 2); map.put(f2.getName(), (long) 1); - List sortedList = FileSystemListParameterDefinition.createTimeSortedList(map); + + List sortedList = Utils.createTimeSortedList(map); Assert.assertEquals(test2,sortedList.get(0)); Assert.assertEquals(test1,sortedList.get(1)); @@ -47,8 +59,10 @@ public void testSorting() { public void testReverseOrder() { boolean sortByLastModified = true; boolean sortReverseOrder = true; - boolean includePathInValue = false; - FileSystemListParameterDefinition pd = new FileSystemListParameterDefinition("name", "description", "master", "path", "", "FILE","SINGLE_SELECT", "", "", sortByLastModified, sortReverseOrder, includePathInValue); + boolean includePathInValue = false; + FileSystemListParameterDefinition pd = new FileSystemListParameterDefinition("name", "description", "master", path, "", "FILE","SINGLE_SELECT", "", "", sortByLastModified, sortReverseOrder, includePathInValue); + FileSystemListParameterDefinition.addTestGC(globalConfigAllowedPaths); + FilesLister fl = new FilesLister(pd.getSelectedEnumType(), pd.getRegexIncludePattern(), pd.getRegexExcludePattern(), pd.getPath(), pd.isSortByLastModified(), pd.isSortReverseOrder()); TreeMap map = new TreeMap<>(); String test1 = "test1"; @@ -59,7 +73,7 @@ public void testReverseOrder() { map.put(f1.getName(), (long) 2); map.put(f2.getName(), (long) 1); - List sortedList = pd.sortList(map); + List sortedList = fl.sortList(map); Assert.assertEquals(test1,sortedList.get(0)); Assert.assertEquals(test2,sortedList.get(1)); @@ -71,8 +85,10 @@ public void testReverseOrder() { public void testAlphabeticOrder() { boolean sortByLastModified = false; boolean sortReverseOrder = false; - boolean includePathInValue = false; - FileSystemListParameterDefinition pd = new FileSystemListParameterDefinition("name", "description", "master", "path", "", "FILE","SINGLE_SELECT", "", "", sortByLastModified, sortReverseOrder, includePathInValue); + boolean includePathInValue = false; + FileSystemListParameterDefinition pd = new FileSystemListParameterDefinition("name", "description", "master", path, "", "FILE","SINGLE_SELECT", "", "", sortByLastModified, sortReverseOrder, includePathInValue); + FileSystemListParameterDefinition.addTestGC(globalConfigAllowedPaths); + FilesLister fl = new FilesLister(pd.getSelectedEnumType(), pd.getRegexIncludePattern(), pd.getRegexExcludePattern(), pd.getPath(), pd.isSortByLastModified(), pd.isSortReverseOrder()); TreeMap map = new TreeMap<>(); String test1 = "test1"; @@ -86,7 +102,7 @@ public void testAlphabeticOrder() { map.put(f3.getName(), (long) 3); map.put(f2.getName(), (long) 2); - List sortedList = pd.sortList(map); + List sortedList = fl.sortList(map); Assert.assertEquals(test1,sortedList.get(0)); Assert.assertEquals(test2,sortedList.get(1)); @@ -100,12 +116,13 @@ public void testGetExistingDefaultValue() throws Exception { boolean sortByLastModified = false; boolean sortReverseOrder = false; - boolean includePathInValue = false; + boolean includePathInValue = false; String includePattern = ""; String excludePattern = ""; String definition_default = "test2.txt"; FileSystemListParameterDefinition pd = new FileSystemListParameterDefinition("name", "description", "master", path, definition_default, "FILE","SINGLE_SELECT", includePattern, excludePattern, sortByLastModified, sortReverseOrder, includePathInValue); - + FileSystemListParameterDefinition.addTestGC(globalConfigAllowedPaths); + String result_default = (String) pd.getDefaultParameterValue().getValue(); Assert.assertEquals(definition_default, result_default); @@ -121,7 +138,7 @@ public void testGetNonExistingDefaultValue() { String excludePattern = ""; String definition_default = "test4.txt"; FileSystemListParameterDefinition pd = new FileSystemListParameterDefinition("name", "description", "master", path, definition_default, "FILE","SINGLE_SELECT", includePattern, excludePattern, sortByLastModified, sortReverseOrder, includePathInValue); - + FileSystemListParameterDefinition.addTestGC(globalConfigAllowedPaths); String result_default = (String) pd.getDefaultParameterValue().getValue(); Assert.assertNotEquals(definition_default, result_default); diff --git a/src/test/java/alex/jenkins/plugins/NotAllowedBaseDirTest.java b/src/test/java/alex/jenkins/plugins/NotAllowedBaseDirTest.java index 82deb29..af46bb9 100644 --- a/src/test/java/alex/jenkins/plugins/NotAllowedBaseDirTest.java +++ b/src/test/java/alex/jenkins/plugins/NotAllowedBaseDirTest.java @@ -50,8 +50,11 @@ public void setup(){ list.add(additionalBaseDirs); gc.setAdditionalBaseDirs(list); gc.setEnabledUserContent(true); + FileSystemListParameterDefinition pd = new FileSystemListParameterDefinition("name", "description", "master", "path", "", "FILE","SINGLE_SELECT", "", "", false, false, false); + pd.getDefaultValue(); + FileSystemListParameterDefinition.addTestGC(gc); } - + private String getAbsolutePath(String path) { URL resource = getClass().getResource(path); Assert.assertNotNull("Test test directory missing", resource); @@ -64,19 +67,19 @@ public void testPaths() { assertFalse(allowedPath.startsWith(notAllowedPath)); } - + @Test public void testAdditionalBaseDir() { - assertTrue(FileSystemListParameterDefinition.isAllowedPath(allowedPath, jenkinsTmpRoot, gc)); - assertFalse(FileSystemListParameterDefinition.isAllowedPath(allowedSimilarFile, jenkinsTmpRoot, gc)); - assertFalse(FileSystemListParameterDefinition.isAllowedPath(notAllowedFile, jenkinsTmpRoot, gc)); - assertFalse(FileSystemListParameterDefinition.isAllowedPath(notAllowedSimilarFile, jenkinsTmpRoot, gc)); + assertTrue(Utils.isAllowedPath(allowedPath, jenkinsTmpRoot, gc)); + assertFalse(Utils.isAllowedPath(allowedSimilarFile, jenkinsTmpRoot, gc)); + assertFalse(Utils.isAllowedPath(notAllowedFile, jenkinsTmpRoot, gc)); + assertFalse(Utils.isAllowedPath(notAllowedSimilarFile, jenkinsTmpRoot, gc)); } @Test public void testUserContent() { - assertTrue(FileSystemListParameterDefinition.isAllowedPath(userContentAllowedFile, jenkinsTmpRoot, gc)); + assertTrue(Utils.isAllowedPath(userContentAllowedFile, jenkinsTmpRoot, gc)); gc.setEnabledUserContent(false); - assertFalse(FileSystemListParameterDefinition.isAllowedPath(userContentAllowedFile, jenkinsTmpRoot, gc)); + assertFalse(Utils.isAllowedPath(userContentAllowedFile, jenkinsTmpRoot, gc)); } } diff --git a/src/test/java/alex/jenkins/plugins/RegexFilterTest.java b/src/test/java/alex/jenkins/plugins/RegexFilterTest.java index 43c2c53..c5d9f98 100644 --- a/src/test/java/alex/jenkins/plugins/RegexFilterTest.java +++ b/src/test/java/alex/jenkins/plugins/RegexFilterTest.java @@ -5,87 +5,98 @@ import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; public class RegexFilterTest { + @Rule + public JenkinsRule j = new JenkinsRule(); + String path; - + FileSystemListParameterGlobalConfiguration globalConfigAllowedPaths; @Before - public void setup(){ + public void setup() { URL resource = getClass().getResource("/1"); Assert.assertNotNull("Test test directory missing", resource); path = resource.getPath(); + + TestUtils tu = new TestUtils(); + globalConfigAllowedPaths = tu.createTestGC(path); } - + @Test public void testRegexEmptyFilter() throws Exception { boolean sortByLastModified = false; boolean sortReverseOrder = false; - boolean includePathInValue = false; + boolean includePathInValue = false; String includePattern = ""; String excludePattern = ""; - FileSystemListParameterDefinition pd = new FileSystemListParameterDefinition("name", "description", "master", path, "", "FILE","SINGLE_SELECT", includePattern, excludePattern, sortByLastModified, sortReverseOrder, includePathInValue); - + FileSystemListParameterDefinition pd = new FileSystemListParameterDefinition("name", "description", "master", path, + "", "FILE", "SINGLE_SELECT", includePattern, excludePattern, sortByLastModified, sortReverseOrder, + includePathInValue); + FileSystemListParameterDefinition.addTestGC(globalConfigAllowedPaths); List list = pd.getFsObjectsList(); - - Assert.assertEquals(3,list.size()); - + + Assert.assertEquals(3, list.size()); + } - - + @Test public void testRegexFilterNotfound() throws Exception { boolean sortByLastModified = false; boolean sortReverseOrder = false; - boolean includePathInValue = false; + boolean includePathInValue = false; String includePattern = "notFound"; String excludePattern = ""; - FileSystemListParameterDefinition pd = new FileSystemListParameterDefinition("name", "description", "master", path, "", "FILE","SINGLE_SELECT", includePattern, excludePattern, sortByLastModified, sortReverseOrder, includePathInValue); - + FileSystemListParameterDefinition pd = new FileSystemListParameterDefinition("name", "description", "master", path, + "", "FILE", "SINGLE_SELECT", includePattern, excludePattern, sortByLastModified, sortReverseOrder, + includePathInValue); + FileSystemListParameterDefinition.addTestGC(globalConfigAllowedPaths); List list = pd.getFsObjectsList(); - - Assert.assertEquals(1,list.size()); + + Assert.assertEquals(1, list.size()); Assert.assertTrue("Contains no objects found message", list.get(0).contains("No objects of type")); - + } - - + @Test public void testRegexIncludeFilter() throws Exception { boolean sortByLastModified = false; boolean sortReverseOrder = false; - boolean includePathInValue = false; + boolean includePathInValue = false; String includePattern = "[\\w]*3[.]txt"; String excludePattern = ""; - FileSystemListParameterDefinition pd = new FileSystemListParameterDefinition("name", "description", "master", path, "", "FILE","SINGLE_SELECT", includePattern, excludePattern, sortByLastModified, sortReverseOrder, includePathInValue); - + FileSystemListParameterDefinition pd = new FileSystemListParameterDefinition("name", "description", "master", path, + "", "FILE", "SINGLE_SELECT", includePattern, excludePattern, sortByLastModified, sortReverseOrder, + includePathInValue); + FileSystemListParameterDefinition.addTestGC(globalConfigAllowedPaths); List list = pd.getFsObjectsList(); - - Assert.assertEquals(1,list.size()); - Assert.assertEquals("test3.txt",list.get(0)); - - + + Assert.assertEquals(1, list.size()); + Assert.assertEquals("test3.txt", list.get(0)); + } - @Test public void testRegexExcludeFilter() throws Exception { boolean sortByLastModified = false; boolean sortReverseOrder = false; - boolean includePathInValue = false; + boolean includePathInValue = false; String includePattern = ""; String excludePattern = "[\\w]*3[.]txt"; - FileSystemListParameterDefinition pd = new FileSystemListParameterDefinition("name", "description", "master", path, "", "FILE","SINGLE_SELECT", includePattern, excludePattern, sortByLastModified, sortReverseOrder, includePathInValue); - + FileSystemListParameterDefinition pd = new FileSystemListParameterDefinition("name", "description", "master", path, + "", "FILE", "SINGLE_SELECT", includePattern, excludePattern, sortByLastModified, sortReverseOrder, + includePathInValue); + FileSystemListParameterDefinition.addTestGC(globalConfigAllowedPaths); List list = pd.getFsObjectsList(); - - Assert.assertEquals(2,list.size()); - Assert.assertEquals("test1.txt",list.get(0)); - Assert.assertEquals("test2.txt",list.get(1)); - - + + Assert.assertEquals(2, list.size()); + Assert.assertEquals("test1.txt", list.get(0)); + Assert.assertEquals("test2.txt", list.get(1)); + } - + } diff --git a/src/test/java/alex/jenkins/plugins/TestUtils.java b/src/test/java/alex/jenkins/plugins/TestUtils.java new file mode 100644 index 0000000..37ba090 --- /dev/null +++ b/src/test/java/alex/jenkins/plugins/TestUtils.java @@ -0,0 +1,18 @@ +package alex.jenkins.plugins; + +import java.util.List; + +import jenkins.model.GlobalConfiguration; + +public class TestUtils { + + public FileSystemListParameterGlobalConfiguration createTestGC(String allowedPath) { + FileSystemListParameterGlobalConfiguration globalConfigAllowedPaths = new FileSystemListParameterGlobalConfiguration(); + GlobalConfiguration.all().get(FileSystemListParameterGlobalConfiguration.class); + List list = globalConfigAllowedPaths.getAdditionalBaseDirs(); + AdditionalBaseDirPath additionalBaseDirs = new AdditionalBaseDirPath(allowedPath); + list.add(additionalBaseDirs); + globalConfigAllowedPaths.setAdditionalBaseDirs(list); + return globalConfigAllowedPaths; + } +}