Skip to content

Commit

Permalink
Validate core dependencies (#685)
Browse files Browse the repository at this point in the history
* Validate core dependencies

* Fail non-fatally in DirectoryTreeBuilder when a version is invalid

---------

Co-authored-by: Daniel Beck <daniel-beck@users.noreply.github.com>
  • Loading branch information
daniel-beck and daniel-beck authored Feb 16, 2023
1 parent 7f56061 commit 091ef99
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,11 @@ private void buildIndex(File dir, String title, String subtitle,
try (IndexHtmlBuilder index = service.newIndexHtmlBuilder(dir, title).withSubtitle(subtitle)) {
index.add(permalink, "permalink to the latest");
for (MavenArtifact a : list) {
index.add(a);
try {
index.add(a);
} catch (IOException ex) {
LOGGER.log(Level.INFO, "Failed to add " + a, ex);
}
}
}
}
Expand Down
41 changes: 33 additions & 8 deletions src/main/java/io/jenkins/update_center/HPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,20 +86,45 @@ public URL getDownloadUrl() throws MalformedURLException {
return new URL(StringUtils.removeEnd(DOWNLOADS_ROOT_URL, "/") + "/plugins/" + artifact.artifactId + "/" + version + "/" + artifact.artifactId + ".hpi");
}

/**
* Check whether a specified core dependency is valid.
*
* Dependencies on incrementals, RCs, or similar should not appear in update sites, so this only considers dependencies on versions looking like weekly or LTS versions to be valid.
* Currently, no effort is made to confirm that the specified version actually exists, e.g. a dependency on 2.99999999 is considered valid.
*
* @param version the specified core dependency version
* @return true if valid, false otherwise
*/
public static boolean isValidCoreDependency(String version) {
return version.matches("[12][.](0|[1-9][0-9]*)([.][1-9])?");
}

/**
* Perform validation (e.g., manifest contents) and throws an exception if it fails.
*/
public void validate() throws IOException {
getRequiredJenkinsVersion();
}

public String getRequiredJenkinsVersion() throws IOException {
String v = getManifestAttributes().getValue("Jenkins-Version");
if (v!=null) return v;
if (v != null) {
if (!isValidCoreDependency(v)) {
throw new IOException("Invalid Jenkins-Version in " + this + ": " + v);
}
return v;
}

v = getManifestAttributes().getValue("Hudson-Version");
if (fixNull(v) != null) {
try {
VersionNumber n = new VersionNumber(v);
if (n.compareTo(JenkinsWar.HUDSON_CUT_OFF)<=0)
return v; // Hudson <= 1.395 is treated as Jenkins
// TODO: Jenkins-Version started appearing from Jenkins 1.401 POM.
// so maybe Hudson > 1.400 shouldn't be considered as a Jenkins plugin?
} catch (IllegalArgumentException e) {
if (!isValidCoreDependency(v)) {
throw new IOException("Invalid Hudson-Version in " + this + ": " + v);
}
VersionNumber n = new VersionNumber(v);
if (n.compareTo(JenkinsWar.HUDSON_CUT_OFF)<=0)
return v; // Hudson <= 1.395 is treated as Jenkins
// TODO: Jenkins-Version started appearing from Jenkins 1.401 POM.
// so maybe Hudson > 1.400 shouldn't be considered as a Jenkins plugin?
}

// Parent versions 1.393 to 1.398 failed to record requiredCore.
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/io/jenkins/update_center/Plugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,9 @@ public String getArtifactId() {
public TreeMap<VersionNumber, HPI> getArtifacts() {
return artifacts;
}

@Override
public String toString() {
return "Plugin '" + artifactId + "'";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ private PluginUpdateCenterEntry(String artifactId, HPI latestOffered, HPI previo
this.previousOffered = previousOffered;
}

public PluginUpdateCenterEntry(Plugin plugin) {
public PluginUpdateCenterEntry(Plugin plugin) throws IOException {
this.artifactId = plugin.getArtifactId();
HPI previous = null, latest = null;

Expand All @@ -49,7 +49,7 @@ public PluginUpdateCenterEntry(Plugin plugin) {
while (latest == null && it.hasNext()) {
HPI h = it.next();
try {
h.getManifest();
h.validate();
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Failed to resolve "+h+". Dropping this version.",e);
continue;
Expand All @@ -60,14 +60,18 @@ public PluginUpdateCenterEntry(Plugin plugin) {
while (previous == null && it.hasNext()) {
HPI h = it.next();
try {
h.getManifest();
h.validate();
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Failed to resolve "+h+". Dropping this version.",e);
continue;
}
previous = h;
}

if (latest == null) {
throw new IOException("Plugin '" + artifactId + "' has no valid release");
}

this.latestOffered = latest;
this.previousOffered = previous == latest ? null : previous;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public Map<String, PluginVersions> getPlugins() throws IOException {
if (plugins == null) {
plugins = new TreeMap<>(repository.listJenkinsPlugins().stream().collect(Collectors.toMap(Plugin::getArtifactId, plugin -> new PluginVersions(plugin.getArtifacts()))));
}
plugins.entrySet().removeIf(e -> e.getValue().releases.isEmpty());
return plugins;
}
}
12 changes: 10 additions & 2 deletions src/main/java/io/jenkins/update_center/json/UpdateCenterRoot.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;

public class UpdateCenterRoot extends WithSignature {
private static final Logger LOGGER = Logger.getLogger(UpdateCenterRoot.class.getName());

@JSONField
@SuppressFBWarnings(value = "SS_SHOULD_BE_STATIC", justification = "Accessed by JSON serializer")
public final String updateCenterVersion = "1";
Expand Down Expand Up @@ -62,8 +66,12 @@ public UpdateCenterRoot(String id, String connectionCheckUrl, MavenRepository re
deprecations = new TreeMap<>(Deprecations.getDeprecatedPlugins().collect(Collectors.toMap(Functions.identity(), UpdateCenterRoot::deprecationForPlugin)));

for (Plugin plugin : repo.listJenkinsPlugins()) {
PluginUpdateCenterEntry entry = new PluginUpdateCenterEntry(plugin);
plugins.put(plugin.getArtifactId(), entry);
try {
PluginUpdateCenterEntry entry = new PluginUpdateCenterEntry(plugin);
plugins.put(plugin.getArtifactId(), entry);
} catch (IOException ex) {
LOGGER.log(Level.INFO, "Failed to add update center entry for: " + plugin, ex);
}
}

core = new UpdateCenterCore(repo.getJenkinsWarsByVersionNumber());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public Collection<Plugin> listJenkinsPlugins() throws IOException {
}
}
} catch (IOException x) {
LOGGER.log(Level.WARNING, "Failed to filter plugin for plugin: " + h.getArtifactId(), x);
LOGGER.log(Level.WARNING, "Failed to filter version " + e.getKey() + " by core dependency for plugin: " + h.getArtifactId(), x);
}
}

Expand Down
22 changes: 22 additions & 0 deletions src/test/java/io/jenkins/update_center/HPITest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.jenkins.update_center;

import org.junit.Test;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class HPITest {
@Test
public void isValidCoreDependencyTest() {
assertTrue(HPI.isValidCoreDependency("1.0"));
assertTrue(HPI.isValidCoreDependency("1.654"));
assertTrue(HPI.isValidCoreDependency("2.0"));
assertTrue(HPI.isValidCoreDependency("2.1"));
assertTrue(HPI.isValidCoreDependency("2.1000"));
assertFalse(HPI.isValidCoreDependency("2.00"));
assertFalse(HPI.isValidCoreDependency("2.01"));
assertFalse(HPI.isValidCoreDependency("2.100-SNAPSHOT"));
assertFalse(HPI.isValidCoreDependency("2.0-rc-1"));
assertFalse(HPI.isValidCoreDependency("2.0-rc-1.vabcd1234"));
}
}

0 comments on commit 091ef99

Please sign in to comment.