Skip to content
24 changes: 23 additions & 1 deletion core/src/main/java/hudson/model/UpdateSite.java
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,29 @@
*/
@Restricted(NoExternalUse.class)
public final FormValidation verifySignatureInternal(JSONObject o) throws IOException {
return getJsonSignatureValidator().verifySignature(o);
FormValidation result = getJsonSignatureValidator().verifySignature(o);

if (result.kind == FormValidation.Kind.ERROR) {
String message = result.getMessage();
if (message != null) {

Check warning on line 301 in core/src/main/java/hudson/model/UpdateSite.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 301 is only partially covered, one branch is missing
// String siteUrl = getUrl();
String updatedMessage;

if (message.contains("update site") && message.contains(" Path") && !message.contains(url)) {

Check warning on line 305 in core/src/main/java/hudson/model/UpdateSite.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 305 is only partially covered, 2 branches are missing
// Ensure the update site URL is included in error messages by replacing the site identifier in messages of the 'update site … Path' pattern or appending it otherwise.
updatedMessage = message.replaceAll(
"(update site\\s+).*?(\\s+Path)",
"$1" + url + "$2"
);
} else {
// Do not alter message structure; only add URL context
updatedMessage = message + " (URL: " + url + ")";
}
return FormValidation.error(updatedMessage);
}
}

return result;
}

/**
Expand Down
24 changes: 23 additions & 1 deletion core/src/main/java/jenkins/util/JSONSignatureValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,9 @@
if (warning != null) return warning;
return FormValidation.ok();
} catch (GeneralSecurityException e) {
return FormValidation.error(e, "Signature verification failed in " + name);
// Return a user-friendly error message without the full stack trace
String rootCauseMessage = getRootCauseMessage(e);
return FormValidation.error("Signature verification failed in " + name + ": " + rootCauseMessage);
}
}

Expand Down Expand Up @@ -321,5 +323,25 @@
return anchors;
}

/**
* Extracts a user-friendly message from an exception chain.
*
* @param e the exception to extract the message from
* @return a concise, readable error message
*/
private String getRootCauseMessage(Throwable e) {
Throwable cause = e;
while (cause.getCause() != null && cause.getCause() != cause) {

Check warning on line 334 in core/src/main/java/jenkins/util/JSONSignatureValidator.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 334 is only partially covered, one branch is missing
cause = cause.getCause();
}

String message = cause.getMessage();
if (message != null && !message.isEmpty()) {

Check warning on line 339 in core/src/main/java/jenkins/util/JSONSignatureValidator.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 339 is only partially covered, 2 branches are missing
return message;
}

return cause.getClass().getSimpleName();

Check warning on line 343 in core/src/main/java/jenkins/util/JSONSignatureValidator.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 343 is not covered by tests
}

private static final Logger LOGGER = Logger.getLogger(JSONSignatureValidator.class.getName());
}
20 changes: 20 additions & 0 deletions test/src/test/java/hudson/model/UpdateSiteTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -299,4 +299,24 @@ private PluginWrapper buildPluginWrapper(String name, String wikiUrl) {
new ArrayList<>()
);
}

@Test
void signatureVerificationFailureIncludesUpdateSiteUrl() throws Exception {
// Create an UpdateSite with an invalid/malformed signature that will trigger an error
URL url = new URL(baseUrl, "/plugins/invalid-signature-update-center.json");
UpdateSite site = new UpdateSite(UpdateCenter.ID_DEFAULT, url.toString());
overrideUpdateSite(site);

FormValidation validation = site.updateDirectlyNow(true);

assertEquals(FormValidation.Kind.ERROR, validation.kind);

String message = validation.getMessage();
assertNotNull(message);
assertTrue(
message.contains(url.toString()),
"Signature verification error should include update site URL"
);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"updateCenterVersion": "1",
"connectionCheckUrl": "http://www.google.com/",
"core": {
"name": "core",
"version": "2.0",
"url": "http://updates.jenkins-ci.org/download/war/2.0/jenkins.war"
},
"plugins": {},
"signature": {
"certificates": [
"InvalidBase64CertificateDataThatWillFailValidation=="
],
"correct_digest": "invalid_digest_value",
"correct_signature": "invalid_signature_value"
}
}
Loading