mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-10-26 19:15:09 +00:00
Refine how administrative monitors are displayed (#26417)
Co-authored-by: Jan Faracik <43062514+janfaracik@users.noreply.github.com> Co-authored-by: Tim Jacomb <21194782+timja@users.noreply.github.com> Co-authored-by: Tim Jacomb <timjacomb1@gmail.com>
This commit is contained in:
57 files changed
+637
-507
No files matched your search
@@ -66,10 +66,9 @@ import org.kohsuke.stapler.interceptor.RequirePOST;
|
||||
* <dd>
|
||||
* If {@link #isActivated()} returns true, Jenkins will use the {@code message.jelly}
|
||||
* view of this object to render the warning text. This happens in the
|
||||
* {@code http://SERVER/jenkins/manage} page. This view should typically render
|
||||
* a DIV box with class='alert alert-danger' or class='alert alert-warning' with a human-readable text
|
||||
* inside it. It often also contains a link to a page that provides more details
|
||||
* about the problem.<br>
|
||||
* {@code http://SERVER/jenkins/manage} page. This view should use {@code l:adminMonitor}
|
||||
* to display the warning text in a consistent way.
|
||||
* <br>
|
||||
* Additionally 2 numbers are shown in the Jenkins header of administrators, one with the number or active
|
||||
* non-security relevant monitors and one with the number of active security relevant monitors.
|
||||
* </dd>
|
||||
|
||||
+7
-6
@@ -24,12 +24,13 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-danger">
|
||||
<l:adminMonitor severity="danger">
|
||||
<dl>
|
||||
<dt>${%PluginCycles}</dt>
|
||||
<j:forEach var="p" items="${it.pluginsWithCycle}">
|
||||
<dd><j:out value="${p.longName} v${p.version}"/></dd>
|
||||
</j:forEach>
|
||||
<dt>${%PluginCycles}</dt>
|
||||
<dd>abc 123.345</dd>
|
||||
<j:forEach var="p" items="${it.pluginsWithCycle}">
|
||||
<dd><j:out value="${p.longName} v${p.version}"/></dd>
|
||||
</j:forEach>
|
||||
</dl>
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -24,7 +24,7 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<l:adminMonitor>
|
||||
<dl>
|
||||
<dt>${%DeprecatedPlugins}</dt>
|
||||
<j:forEach var="e" items="${it.getDeprecatedPlugins()}">
|
||||
@@ -32,5 +32,5 @@ THE SOFTWARE.
|
||||
</j:forEach>
|
||||
</dl>
|
||||
<p>${%DeprecatedPluginsDescription}</p>
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -24,12 +24,12 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-danger">
|
||||
<l:adminMonitor severity="danger">
|
||||
<dl>
|
||||
<dt>${%RequiredPluginUpdates}</dt>
|
||||
<j:forEach var="p" items="${it.pluginsToBeUpdated}">
|
||||
<dd><j:out value="${p.pluginName}"/> — <j:out value="${p.message}"/></dd>
|
||||
</j:forEach>
|
||||
</dl>
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
+7
-7
@@ -1,10 +1,10 @@
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-danger" role="alert">
|
||||
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="correct" value="${%Correct}"/>
|
||||
</form>
|
||||
<p>${%blurbOriginal}</p>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:l="/lib/layout">
|
||||
<j:set var="controls">
|
||||
<a href="${rootURL}/pluginManager" class="jenkins-button jenkins-button--primary">${%Correct}</a>
|
||||
</j:set>
|
||||
<l:adminMonitor severity="danger" controls="${controls}">
|
||||
${%blurbOriginal}
|
||||
<p><strong>${%DirectlyDependentPlugins.title}</strong></p>
|
||||
<j:forEach items="${it.plugins}" var="plugin">
|
||||
<j:if test="${plugin.hasOriginalDependencyErrors()}">
|
||||
@@ -30,5 +30,5 @@
|
||||
</j:forEach>
|
||||
</dl>
|
||||
</j:if>
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -27,7 +27,7 @@ THE SOFTWARE.
|
||||
<l:layout title="${%JENKINS_HOME is almost full}">
|
||||
<l:main-panel>
|
||||
<h1>
|
||||
<l:icon class="icon-warning icon-xlg"/>
|
||||
<l:icon src="symbol-warning" class="icon-xlg jenkins-!-warning-color"/>
|
||||
${%blurb}
|
||||
</h1>
|
||||
|
||||
|
||||
@@ -24,11 +24,10 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="yes" value="${%Tell me more}"/>
|
||||
<f:submit name="no" value="${%Dismiss}"/>
|
||||
</form>
|
||||
${%blurb(app.rootDir)}
|
||||
</div>
|
||||
<j:set var="controls">
|
||||
<a href="${rootURL}/${it.url}/" class="jenkins-button jenkins-button--primary">${%Tell me more}</a>
|
||||
</j:set>
|
||||
<l:adminMonitor controls="${controls}">
|
||||
${%blurb(app.rootDir)}
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -24,12 +24,12 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-danger">
|
||||
<dl>
|
||||
<dt>${%blurb}</dt>
|
||||
<j:forEach var="d" items="${it.problems}">
|
||||
<dd>${%problem(d, d.displayName, app.pluginManager.whichPlugin(d.getClass()))}</dd>
|
||||
</j:forEach>
|
||||
</dl>
|
||||
</div>
|
||||
<l:adminMonitor severity="danger">
|
||||
<dl>
|
||||
<dt>${%blurb}</dt>
|
||||
<j:forEach var="d" items="${it.problems}">
|
||||
<dd>${%problem(d, d.displayName, app.pluginManager.whichPlugin(d.getClass()))}</dd>
|
||||
</j:forEach>
|
||||
</dl>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -24,11 +24,10 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="yes" value="${%Manage}"/>
|
||||
<f:submit name="no" value="${%Dismiss}"/>
|
||||
</form>
|
||||
<j:set var="controls">
|
||||
<a href="${rootURL}/${it.url}/manage" class="jenkins-button jenkins-button--primary">${%Manage}</a>
|
||||
</j:set>
|
||||
<l:adminMonitor controls="${controls}">
|
||||
${%You have data stored in an older format and/or unreadable data.}
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -23,16 +23,12 @@ THE SOFTWARE.
|
||||
-->
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:f="/lib/form" xmlns:l="/lib/layout">
|
||||
<div id="redirect-error" class="jenkins-alert jenkins-alert-danger reverse-proxy__hidden"
|
||||
data-url="${rootURL}/${it.url}/test" data-context="${rootURL}">
|
||||
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="yes" value="${%More Info}"/>
|
||||
<l:isAdmin>
|
||||
<f:submit name="no" value="${%Dismiss}"/>
|
||||
</l:isAdmin>
|
||||
</form>
|
||||
<div>${%blurb}</div>
|
||||
<div class="js-context-message reverse-proxy__hidden">${%missingContextMessage(rootURL)}</div>
|
||||
</div>
|
||||
<j:set var="controls">
|
||||
<a href="https://www.jenkins.io/redirect/troubleshooting/broken-reverse-proxy" class="jenkins-button jenkins-button--primary">${%More Info}</a>
|
||||
</j:set>
|
||||
<l:adminMonitor severity="danger" dismissable="true" class="jenkins-hidden" id="redirect-error" controls="${controls}">
|
||||
<div id="redirect-data" data-url="${rootURL}/${it.url}/test" data-context="${rootURL}"/>
|
||||
<div>${%blurb} <span class="js-context-message jenkins-hidden">${%missingContextMessage(rootURL)}</span></div>
|
||||
</l:adminMonitor>
|
||||
<st:adjunct includes="hudson.diagnosis.ReverseProxySetupMonitor.resources"/>
|
||||
</j:jelly>
|
||||
@@ -1,3 +0,0 @@
|
||||
.reverse-proxy__hidden {
|
||||
display: none;
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
(function () {
|
||||
var redirectForm = document.getElementById("redirect-error");
|
||||
const redirectData = document.getElementById("redirect-data");
|
||||
|
||||
if (!redirectForm) {
|
||||
console.warn(
|
||||
'This script expects to have an element with id="redirect-error" to be working.',
|
||||
@@ -7,7 +9,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
var urlToTest = redirectForm.getAttribute("data-url");
|
||||
var urlToTest = redirectData.getAttribute("data-url");
|
||||
var callUrlToTest = function (testWithContext, callback) {
|
||||
var headers = {};
|
||||
var body = null;
|
||||
@@ -28,19 +30,19 @@
|
||||
};
|
||||
|
||||
var displayWarningMessage = function (withContextMessage) {
|
||||
redirectForm.classList.remove("reverse-proxy__hidden");
|
||||
redirectForm.classList.remove("jenkins-hidden");
|
||||
if (withContextMessage === true) {
|
||||
redirectForm
|
||||
.querySelectorAll(".js-context-message")
|
||||
.forEach(function (node) {
|
||||
return node.classList.remove("reverse-proxy__hidden");
|
||||
return node.classList.remove("jenkins-hidden");
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
callUrlToTest(false, function (response) {
|
||||
if (response.status !== 200) {
|
||||
var context = redirectForm.getAttribute("data-context");
|
||||
var context = redirectData.getAttribute("data-context");
|
||||
// to cover the case where the JenkinsRootUrl is configured without the context
|
||||
if (context) {
|
||||
callUrlToTest(true, function (response2) {
|
||||
|
||||
@@ -24,13 +24,10 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<div id="tooManyJobsButNoView" class="jenkins-alert jenkins-alert-warning">
|
||||
<l:isAdmin>
|
||||
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="yes" value="${%Create a view now}"/>
|
||||
<f:submit name="no" value="${%Dismiss}"/>
|
||||
</form>
|
||||
</l:isAdmin>
|
||||
<j:set var="controls">
|
||||
<a href="${rootURL}/newView" class="jenkins-button jenkins-button--primary">${%Create a view now}</a>
|
||||
</j:set>
|
||||
<l:adminMonitor controls="${controls}">
|
||||
${%blurb}
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -24,9 +24,33 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-info">
|
||||
<j:set var="ucData" value="${it.data}" />
|
||||
<j:set var="upJob" value="${app.updateCenter.hudsonJob}" />
|
||||
<j:set var="ucData" value="${it.data}" />
|
||||
<j:set var="upJob" value="${app.updateCenter.hudsonJob}" />
|
||||
<j:set var="controls">
|
||||
<j:choose>
|
||||
<j:when test="${upJob.status.success}">
|
||||
</j:when>
|
||||
<j:when test="${upJob!=null and upJob.error != null}">
|
||||
<j:if test="${ucData.canUpgrade()}">
|
||||
<form method="post" action="${rootURL}/updateCenter/upgrade">
|
||||
<f:submit value="${%Retry}"/>
|
||||
</form>
|
||||
</j:if>
|
||||
</j:when>
|
||||
<j:when test="${upJob!=null}">
|
||||
</j:when>
|
||||
<j:otherwise>
|
||||
<l:isAdmin>
|
||||
<j:if test="${ucData.canUpgrade()}">
|
||||
<form method="post" action="${rootURL}/updateCenter/upgrade">
|
||||
<f:submit value="${%Or Upgrade Automatically}"/>
|
||||
</form>
|
||||
</j:if>
|
||||
</l:isAdmin>
|
||||
</j:otherwise>
|
||||
</j:choose>
|
||||
</j:set>
|
||||
<l:adminMonitor severity="info" controls="${controls}">
|
||||
<j:choose>
|
||||
<j:when test="${upJob.status.success}">
|
||||
<j:invokeStatic var="lifecycle" className="hudson.lifecycle.Lifecycle" method="get" />
|
||||
@@ -41,11 +65,6 @@ THE SOFTWARE.
|
||||
</j:when>
|
||||
<j:when test="${upJob!=null and upJob.error != null}">
|
||||
${%UpgradeFailed(ucData.core.version,upJob.errorMessage,rootURL+'/updateCenter/')}
|
||||
<j:if test="${ucData.canUpgrade()}">
|
||||
<form method="post" action="${rootURL}/updateCenter/upgrade">
|
||||
<f:submit value="${%Retry}"/>
|
||||
</form>
|
||||
</j:if>
|
||||
</j:when>
|
||||
<j:when test="${upJob!=null}">
|
||||
${%UpgradeProgress(ucData.core.version,rootURL+'/updateCenter/')}
|
||||
@@ -53,14 +72,7 @@ THE SOFTWARE.
|
||||
<j:otherwise>
|
||||
<j:set var="changelog_url" value="${app.CHANGELOG_URL}"/>
|
||||
${%NewVersionAvailable(ucData.core.version,ucData.core.url,changelog_url)}
|
||||
<l:isAdmin>
|
||||
<j:if test="${ucData.canUpgrade()}">
|
||||
<form method="post" action="${rootURL}/updateCenter/upgrade">
|
||||
<f:submit value="${%Or Upgrade Automatically}"/>
|
||||
</form>
|
||||
</j:if>
|
||||
</l:isAdmin>
|
||||
</j:otherwise>
|
||||
</j:choose>
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -24,10 +24,7 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<form method="post" action="${rootURL}/${it.url}/disable">
|
||||
<f:submit value="${%Dismiss}"/>
|
||||
</form>
|
||||
<l:adminMonitor>
|
||||
${%blurb(rootURL)}
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
+6
-7
@@ -23,12 +23,11 @@ THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="learn" value="${%Learn more}"/>
|
||||
<f:submit name="dismiss" value="${%Dismiss}"/>
|
||||
</form>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:l="/lib/layout">
|
||||
<j:set var="controls">
|
||||
<a href="https://www.jenkins.io/redirect/csrf-protection/" class="jenkins-button jenkins-button--primary">${%Learn more}</a>
|
||||
</j:set>
|
||||
<l:adminMonitor controls="${controls}">
|
||||
${%blurb}
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
+3
-3
@@ -23,8 +23,8 @@ THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:t="/lib/hudson">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout">
|
||||
<l:adminMonitor>
|
||||
${%blurb(rootURL)}
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -1,48 +0,0 @@
|
||||
package hudson.triggers.SlowTriggerAdminMonitor
|
||||
|
||||
import hudson.Util
|
||||
import hudson.triggers.SlowTriggerAdminMonitor
|
||||
import jenkins.model.Jenkins
|
||||
import org.apache.commons.jelly.tags.fmt.FmtTagLibrary
|
||||
|
||||
SlowTriggerAdminMonitor tam = my
|
||||
|
||||
dl {
|
||||
div(class: "jenkins-alert jenkins-alert-warning") {
|
||||
form(method: "post", name: "clear", action: rootURL + "/" + tam.url + "/clear") {
|
||||
button(name: "clear", type: "submit", class: "jenkins-button jenkins-submit-button jenkins-button--primary") {
|
||||
raw _("Dismiss")
|
||||
}
|
||||
}
|
||||
|
||||
text(_("blurb"))
|
||||
|
||||
table(class: "sortable jenkins-table jenkins-!-margin-top-2", width: "100%") {
|
||||
thead {
|
||||
tr {
|
||||
th(_("Trigger"))
|
||||
th(_("Most Recent Occurrence"))
|
||||
th(_("Most Recently Occurring Job"))
|
||||
th(_("Duration"))
|
||||
}
|
||||
}
|
||||
|
||||
tam.errors.each { trigger, val ->
|
||||
def job = Jenkins.get().getItemByFullName(val.fullJobName)
|
||||
|
||||
tr {
|
||||
td(Jenkins.get().getDescriptorByType(val.trigger).getDisplayName())
|
||||
td(val.getTimeString())
|
||||
if (job == null) {
|
||||
td(val.fullJobName)
|
||||
} else {
|
||||
td {
|
||||
a(job.getFullDisplayName(), href: rootURL + '/' + job.getUrl(), class: 'model-link')
|
||||
}
|
||||
}
|
||||
td(Util.getTimeSpanString(val.duration))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<j:set var="controls">
|
||||
<form method="post" name="clear" action="${rootURL}/${it.url}/clear">
|
||||
<f:submit value="${%Clear}"/>
|
||||
</form>
|
||||
</j:set>
|
||||
<l:adminMonitor controls="${controls}" dismissValue="${%Disable}">
|
||||
${%blurb}
|
||||
<table class="sortable jenkins-table jenkins-!-margin-top-3 jenkins-!-margin-bottom-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>${%Trigger}</th>
|
||||
<th>${%Most Recent Occurrence}</th>
|
||||
<th>${%Most Recently Occurring Job}</th>
|
||||
<th>${%Duration}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<j:forEach var="trigger" items="${it.getErrors().entrySet()}">
|
||||
<j:set var="trigger" value="${trigger.key}"/>
|
||||
<j:set var="val" value="${trigger.value}"/>
|
||||
<j:set var="job" value="${app.getItemByFullName(trigger.fullJobName)}"/>
|
||||
<tr>
|
||||
<td>${app.getDescriptorByType(val.trigger).getDisplayName()}</td>
|
||||
<td>${val.getTimeString()}</td>
|
||||
<j:if test="${job!=null}">
|
||||
<td><a href="${rootURL}/${job.url}" class="model-link">${job.fullDisplayName}</a></td>
|
||||
</j:if>
|
||||
<j:if test="${job==null}">
|
||||
<td>${val.fullJobName}</td>
|
||||
</j:if>
|
||||
<td>${h.getTimeSpanString(val.duration)}</td>
|
||||
</tr>
|
||||
</j:forEach>
|
||||
</tbody>
|
||||
</table>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -24,24 +24,22 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<p>
|
||||
${%message(it.home)}
|
||||
</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td>${%This Jenkins}:</td>
|
||||
<td>${it.id}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>${%Other Jenkins}:</td>
|
||||
<td>${it.collidingId}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div>
|
||||
<form method="post" action="${rootURL}/${it.url}/disable">
|
||||
<f:submit value="${%label}" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<j:set var="controls">
|
||||
<form method="post" action="${rootURL}/${it.url}/disable">
|
||||
<f:submit value="${%label}" />
|
||||
</form>
|
||||
</j:set>
|
||||
<l:adminMonitor dismissable="false" controls="${controls}">
|
||||
${%message(it.home)}
|
||||
<table>
|
||||
<tr>
|
||||
<td>${%This Jenkins}:</td>
|
||||
<td>${it.id}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>${%Other Jenkins}:</td>
|
||||
<td>${it.collidingId}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -24,7 +24,7 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-danger">
|
||||
<l:adminMonitor severity="danger">
|
||||
${%blurb(rootURL+'/'+it.url)}
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
+8
-8
@@ -1,11 +1,11 @@
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
${%blurb(app.initLevel)}
|
||||
${%Example: usage of} <code>@Initializer(after = InitMilestone.COMPLETED)</code> ${%in a plugin}
|
||||
(<a href="https://www.jenkins.io/redirect/troubleshooting/initialization-not-completed" rel="noopener noreferrer" target="_blank">${%See documentation}</a>).
|
||||
${%Please} <a href="https://www.jenkins.io/redirect/report-an-issue" rel="noopener noreferrer" target="_blank">${%report a bug}</a> ${%in the Jenkins bugtracker}.
|
||||
<!--TODO: Nice2have: cause diagnostics-->
|
||||
<!-- FIXME TODO XXX i18n does not take into account different sentence structure, rewrite with arguments -->
|
||||
</div>
|
||||
<l:adminMonitor>
|
||||
${%blurb(app.initLevel)}
|
||||
${%Example: usage of} <code>@Initializer(after = InitMilestone.COMPLETED)</code> ${%in a plugin}
|
||||
(<a href="https://www.jenkins.io/redirect/troubleshooting/initialization-not-completed" rel="noopener noreferrer" target="_blank">${%See documentation}</a>).
|
||||
${%Please} <a href="https://www.jenkins.io/redirect/report-an-issue" rel="noopener noreferrer" target="_blank">${%report a bug}</a> ${%in the Jenkins bugtracker}.
|
||||
<!--TODO: Nice2have: cause diagnostics-->
|
||||
<!-- FIXME TODO XXX i18n does not take into account different sentence structure, rewrite with arguments -->
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -24,12 +24,10 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="yes" value="${%Manage}"/>
|
||||
<f:submit name="no" value="${%Dismiss}"/>
|
||||
</form>
|
||||
|
||||
<j:set var="controls">
|
||||
<a href="${rootURL}/computer/(built-in)/configure" class="jenkins-button jenkins-button--primary">${%Manage}</a>
|
||||
</j:set>
|
||||
<l:adminMonitor controls="${controls}">
|
||||
${%ExecutorsWarning}
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
+6
-7
@@ -24,12 +24,11 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="agent" value="${%Set up agent}"/>
|
||||
<f:submit name="cloud" value="${%Set up cloud}"/>
|
||||
<f:submit name="no" value="${%Dismiss}"/>
|
||||
</form>
|
||||
<j:set var="controls">
|
||||
<a href="${rootURL}/computer/new" class="jenkins-button jenkins-button--primary">${%Set up agent}</a>
|
||||
<a href="${rootURL}/manage/cloud" class="jenkins-button jenkins-button--primary">${%Set up cloud}</a>
|
||||
</j:set>
|
||||
<l:adminMonitor controls="${controls}">
|
||||
${%ExecutorsWarning}
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -23,12 +23,7 @@ THE SOFTWARE.
|
||||
-->
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:l="/lib/layout">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<l:isAdmin>
|
||||
<form method="post" action="${rootURL}/${it.url}/disable">
|
||||
<f:submit value="${%Dismiss}"/>
|
||||
</form>
|
||||
</l:isAdmin>
|
||||
<l:adminMonitor>
|
||||
<j:set var="actionAnchor">
|
||||
<a href="${rootURL}/configure">${%actionUrlContent}</a>
|
||||
</j:set>
|
||||
@@ -45,5 +40,5 @@ THE SOFTWARE.
|
||||
<l:isAdmin>
|
||||
<j:out value="${%actionToTake(actionAnchor)}"/>
|
||||
</l:isAdmin>
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -24,11 +24,10 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="yes" value="${%Setup Security}"/>
|
||||
<f:submit name="no" value="${%Dismiss}"/>
|
||||
</form>
|
||||
<j:set var="controls">
|
||||
<a href="${rootURL}/configureSecurity" class="jenkins-button jenkins-button--primary">${%Setup Security}</a>
|
||||
</j:set>
|
||||
<l:adminMonitor controls="${controls}">
|
||||
${%blurb}
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -1,7 +1,7 @@
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<j:if test="${it.checkEnabled}">
|
||||
<div id="URICheckEncodingMonitor-message" data-url="${rootURL}/${it.url}/checkURIEncoding"/>
|
||||
<st:adjunct includes="jenkins.diagnostics.URICheckEncodingMonitor.uri-check-encoding-monitor"/>
|
||||
</j:if>
|
||||
<l:adminMonitor class="jenkins-hidden">
|
||||
<div id="URICheckEncodingMonitor-message" data-url="${rootURL}/${it.url}/checkURIEncoding"/>
|
||||
</l:adminMonitor>
|
||||
<st:adjunct includes="jenkins.diagnostics.URICheckEncodingMonitor.uri-check-encoding-monitor"/>
|
||||
</j:jelly>
|
||||
+5
-4
@@ -7,10 +7,11 @@ Behaviour.specify(
|
||||
var params = new URLSearchParams({ value: "\u57f7\u4e8b" });
|
||||
fetch(url + "?" + params).then((rsp) => {
|
||||
rsp.text().then((responseText) => {
|
||||
var message = document.getElementById(
|
||||
"URICheckEncodingMonitor-message",
|
||||
);
|
||||
message.innerHTML = responseText;
|
||||
if (responseText !== "<div/>") {
|
||||
const alertDiv = element.closest(".app-adminmonitor");
|
||||
alertDiv.classList.remove("jenkins-hidden");
|
||||
element.innerHTML = responseText;
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="yes" value="${%Apply Migration}"/>
|
||||
<f:submit name="no" value="${%Dismiss}"/>
|
||||
</form>
|
||||
${%blurb}
|
||||
</div>
|
||||
<j:set var="controls">
|
||||
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="yes" value="${%Apply Migration}"/>
|
||||
</form>
|
||||
</j:set>
|
||||
<l:adminMonitor controls="${controls}">
|
||||
${%blurb}
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
+4
-2
@@ -23,10 +23,12 @@ THE SOFTWARE.
|
||||
-->
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<j:set var="controls">
|
||||
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="reset" value="${%reset(it.expectedPort)}"/>
|
||||
</form>
|
||||
</j:set>
|
||||
<l:adminMonitor controls="${controls}">
|
||||
${%description(it.systemPropertyName, it.expectedPort)}
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -24,12 +24,14 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<j:if test="${app.updateCenter.downgradable}">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
${%Restore the previous version of Jenkins}
|
||||
<form method="post" action="${rootURL}/updateCenter/downgrade">
|
||||
<f:submit value="${%buttonText(app.updateCenter.backupVersion)}"/>
|
||||
</form>
|
||||
</div>
|
||||
</j:if>
|
||||
<j:if test="${app.updateCenter.downgradable}">
|
||||
<j:set var="controls">
|
||||
<form method="post" action="${rootURL}/updateCenter/downgrade">
|
||||
<f:submit value="${%buttonText(app.updateCenter.backupVersion)}"/>
|
||||
</form>
|
||||
</j:set>
|
||||
<l:adminMonitor dismissable="false" controls="${controls}">
|
||||
${%Restore the previous version of Jenkins}
|
||||
</l:adminMonitor>
|
||||
</j:if>
|
||||
</j:jelly>
|
||||
+7
-10
@@ -24,14 +24,11 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-${it.severityAsString}">
|
||||
<form id="JavaVersionRecommendationAdminMonitor" method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="yes" value="${%More Info}"/>
|
||||
<l:isAdmin>
|
||||
<f:submit value="${%Ignore}" name="no"/>
|
||||
</l:isAdmin>
|
||||
</form>
|
||||
<h2>${%Recommended_Java_Version_Heading(it.javaVersion)}</h2>
|
||||
${%Recommended_Java_Version(it.javaVersion, it.endOfLifeAsDate)}
|
||||
</div>
|
||||
<j:set var="controls">
|
||||
<a href="https://jenkins.io/redirect/java-support/" class="jenkins-button jenkins-button--primary">${%More Info}</a>
|
||||
</j:set>
|
||||
<l:adminMonitor severity="${it.severityAsString}" controls="${controls}">
|
||||
<h4 class="jenkins-!-margin-bottom-1">${%Recommended_Java_Version_Heading(it.javaVersion)}</h4>
|
||||
${%Recommended_Java_Version(it.javaVersion, it.endOfLifeAsDate)}
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
+6
-9
@@ -25,14 +25,11 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-danger">
|
||||
<form id="${it.id}" method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="yes" value="${%More Info}"/>
|
||||
<l:isAdmin>
|
||||
<f:submit value="${%Ignore}" name="no"/>
|
||||
</l:isAdmin>
|
||||
</form>
|
||||
<h2 class="h3">${it.displayName}</h2>
|
||||
<j:set var="controls">
|
||||
<a href="https://www.jenkins.io/redirect/operating-system-end-of-life" class="jenkins-button jenkins-button--primary">${%More Info}</a>
|
||||
</j:set>
|
||||
<l:adminMonitor severity="danger" controls="${controls}">
|
||||
<h4 class="jenkins-!-margin-bottom-1">${it.displayName}</h4>
|
||||
<j:choose>
|
||||
<j:when test="${it.afterEndOfLifeDate}">
|
||||
${%Past_End_of_Life(it.operatingSystemName, it.endOfLifeDate, it.documentationUrl)}
|
||||
@@ -41,5 +38,5 @@ THE SOFTWARE.
|
||||
${%Upcoming_End_of_Life(it.operatingSystemName, it.endOfLifeDate, it.documentationUrl)}
|
||||
</j:otherwise>
|
||||
</j:choose>
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright 2019 CloudBees, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package jenkins.security.ResourceDomainRecommendation
|
||||
|
||||
def f = namespace(lib.FormTagLib)
|
||||
def l = namespace(lib.LayoutTagLib)
|
||||
|
||||
dl {
|
||||
div(class: "jenkins-alert jenkins-alert-info") {
|
||||
a(name: "resource-root-url")
|
||||
l.isAdmin() {
|
||||
form(method: "post", action: "${rootURL}/${my.url}/act") {
|
||||
f.submit(name: 'redirect', value: _("Configure resource root URL"))
|
||||
f.submit(name: 'dismiss', value: _("Dismiss"))
|
||||
}
|
||||
}
|
||||
|
||||
raw(_("blurb"))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout" xmlns:f="/lib/form">
|
||||
<j:set var="controls">
|
||||
<l:isAdmin>
|
||||
<a href="${rootURL}/configure" class="jenkins-button jenkins-button--primary">
|
||||
${%Configure resource root URL}
|
||||
</a>
|
||||
</l:isAdmin>
|
||||
</j:set>
|
||||
<l:adminMonitor severity="info" controls="${controls}">
|
||||
${%blurb}
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
+6
-1
@@ -38,11 +38,16 @@ def printEntry(warning, title, checked) {
|
||||
div(class: "setting-description") {
|
||||
a(warning.url, href: warning.url)
|
||||
}
|
||||
if (!warning.isFixable()) {
|
||||
div(class: "error") {
|
||||
text(_("No fix available"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f.section(title:_("Hidden security warnings")) {
|
||||
|
||||
div(id: "hidden-security-warnings")
|
||||
f.advanced(title: _("Security warnings"), align:"left") {
|
||||
f.block {
|
||||
text(_("blurb"))
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
<p>
|
||||
Checked entries (the default) are
|
||||
<em>active</em>
|
||||
, i.e. they're shown to administrators in an administrative monitor. Entries
|
||||
can be unchecked to hide them. This can be useful if you've evaluated a
|
||||
specific warning and are confident it does not apply to your environment or
|
||||
, i.e. they're shown in the plugin manager and in an administrative monitor.
|
||||
Entries can be unchecked to hide them. This can be useful if you've evaluated
|
||||
a specific warning and are confident it does not apply to your environment or
|
||||
configuration, and continued use of the specified component does not
|
||||
constitute a security problem.
|
||||
</p>
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2016, CloudBees, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package jenkins.security.UpdateSiteWarningsMonitor
|
||||
|
||||
def f = namespace(lib.FormTagLib)
|
||||
def l = namespace(lib.LayoutTagLib)
|
||||
|
||||
def listWarnings(warnings, boolean core) {
|
||||
def fixables = 0
|
||||
warnings.each { warning ->
|
||||
dd {
|
||||
a(warning.message, href: warning.url, rel: 'noopener noreferrer', target: "_blank")
|
||||
def fixable = warning.isFixable()
|
||||
if (fixable != null) {
|
||||
if (fixable) {
|
||||
fixables++
|
||||
} else {
|
||||
raw(_(core ? "unfixableCore" : "unfixable"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fixables == warnings.size()) {
|
||||
dd {
|
||||
if (fixables == 1) {
|
||||
raw(_(core ? "allFixable1Core" : "allFixable1", rootURL))
|
||||
} else {
|
||||
raw(_(core ? "allFixableCore" : "allFixable", rootURL))
|
||||
}
|
||||
}
|
||||
} else if (fixables > 0) {
|
||||
dd {
|
||||
raw(_(core ? "someFixableCore" : "someFixable", rootURL))
|
||||
}
|
||||
} else {
|
||||
dd {
|
||||
raw(_(core ? "noneFixableCore" : "noneFixable"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def coreWarnings = my.activeCoreWarnings
|
||||
def pluginWarnings = my.activePluginWarningsByPlugin
|
||||
|
||||
div(class: "jenkins-alert jenkins-alert-danger", role: "alert") {
|
||||
|
||||
l.isAdmin() {
|
||||
form(method: "post", action: "${rootURL}/${my.url}/forward") {
|
||||
if (!pluginWarnings.isEmpty()) {
|
||||
f.submit(name: 'fix', value: _("pluginManager.link"))
|
||||
}
|
||||
f.submit(name: 'configure', value: _("configureSecurity.link"))
|
||||
}
|
||||
}
|
||||
|
||||
text(_("blurb"))
|
||||
|
||||
if (!coreWarnings.isEmpty()) {
|
||||
dl {
|
||||
dt {
|
||||
text(_("coreTitle", jenkins.model.Jenkins.version))
|
||||
}
|
||||
listWarnings(coreWarnings, true)
|
||||
}
|
||||
}
|
||||
if (!pluginWarnings.isEmpty()) {
|
||||
dl {
|
||||
pluginWarnings.each { plugin, warnings ->
|
||||
dt {
|
||||
a(_("pluginTitle", plugin.displayName, plugin.version), href: plugin.url, rel: 'noopener noreferrer', target: "_blank")
|
||||
}
|
||||
listWarnings(warnings, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (my.hasApplicableHiddenWarnings()) {
|
||||
text(_("more"))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:local="local">
|
||||
<d:taglib uri="local">
|
||||
<d:tag name="message">
|
||||
<j:choose>
|
||||
<j:when test="${attrs.core}">
|
||||
<j:out value="${attrs.c}"/>
|
||||
</j:when>
|
||||
<j:otherwise>
|
||||
<j:out value="${attrs.p}"/>
|
||||
</j:otherwise>
|
||||
</j:choose>
|
||||
</d:tag>
|
||||
<d:tag name="listWarnings" >
|
||||
<j:set var="fixables" value="0"/>
|
||||
<j:forEach var="warning" items="${attrs.warnings}">
|
||||
<dd>
|
||||
<a href="${warning.url}" rel="noopener noreferrer" target="_blank">${warning.message}</a>
|
||||
<j:set var="fixable" value="${warning.isFixable()}"/>
|
||||
<j:if test="${fixable != null}">
|
||||
<j:if test="${fixable}">
|
||||
<j:set var="fixables" value="${fixables + 1}"/>
|
||||
</j:if>
|
||||
<j:if test="${!fixable}">
|
||||
${%unfixable}
|
||||
</j:if>
|
||||
</j:if>
|
||||
</dd>
|
||||
</j:forEach>
|
||||
<j:choose>
|
||||
<j:when test="${fixables eq warnings.size()}">
|
||||
<dd>
|
||||
<j:if test="${fixables == 1}">
|
||||
<local:message core="${attrs.core}" c="${%allFixable1Core(rootURL)}" p="${%allFixable1(rootURL)}"/>
|
||||
</j:if>
|
||||
<j:if test="${fixables != 1}">
|
||||
<local:message core="${attrs.core}" c="${%allFixableCore(rootURL)}" p="${%allFixable(rootURL)}"/>
|
||||
</j:if>
|
||||
</dd>
|
||||
</j:when>
|
||||
<j:when test="${fixables > 0}">
|
||||
<dd>
|
||||
<local:message core="${attrs.core}" c="${%someFixableCore(rootURL)}" p="${%someFixable(rootURL)}"/>
|
||||
</dd>
|
||||
</j:when>
|
||||
<j:otherwise>
|
||||
<dd>
|
||||
<local:message core="${attrs.core}" c="${%noneFixableCore}" p="${%noneFixable}"/>
|
||||
</dd>
|
||||
</j:otherwise>
|
||||
</j:choose>
|
||||
</d:tag>
|
||||
</d:taglib>
|
||||
<j:set var="coreWarnings" value="${it.activeCoreWarnings}"/>
|
||||
<j:set var="pluginWarnings" value="${it.activePluginWarningsByPlugin}"/>
|
||||
<j:set var="controls">
|
||||
<l:isAdmin>
|
||||
<a href="${rootURL}/configureSecurity/#hidden-security-warnings" class="jenkins-button jenkins-button--primary">${%configureSecurity.link}</a>
|
||||
<j:if test="${pluginWarnings.size() > 0}">
|
||||
<a href="${rootURL}/pluginManager" class="jenkins-button jenkins-button--primary">${%pluginManager.link}</a>
|
||||
</j:if>
|
||||
</l:isAdmin>
|
||||
</j:set>
|
||||
<l:adminMonitor severity="danger" controls="${controls}">
|
||||
<div class="jenkins-!-margin-bottom-1">${%blurb}</div>
|
||||
<j:if test="${it.hasApplicableHiddenWarnings()}">
|
||||
${%more}
|
||||
</j:if>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
+4
-4
@@ -23,8 +23,8 @@
|
||||
pluginTitle = {0} {1}
|
||||
coreTitle = Jenkins {0} core and libraries
|
||||
|
||||
blurb = Warnings have been published for the following currently installed components:
|
||||
more = Additional warnings are hidden due to the current security configuration.
|
||||
blurb = Warnings have been published for some installed components.
|
||||
more = Some of these warnings are hidden in the plugin manager due to the current security configuration.
|
||||
|
||||
allFixable = Fixes for all of these issues are available. \
|
||||
Go to the <a href="{0}/pluginManager">plugin manager</a> to update the plugin.
|
||||
@@ -50,5 +50,5 @@ noneFixableCore = No fixes for these issues are available. \
|
||||
# Leading space to separate from link
|
||||
unfixableCore = \u0020(no fix available)
|
||||
|
||||
pluginManager.link = Go to plugin manager
|
||||
configureSecurity.link = Configure which of these warnings are shown
|
||||
pluginManager.link = Plugin manager
|
||||
configureSecurity.link = View
|
||||
+5
-4
@@ -22,12 +22,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:l="/lib/layout">
|
||||
<j:set var="controls">
|
||||
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="yes" value="${%Disable automatic generation of legacy API tokens}"/>
|
||||
<f:submit name="no" value="${%Dismiss}"/>
|
||||
</form>
|
||||
</j:set>
|
||||
<l:adminMonitor controls="${controls}">
|
||||
${%warningMessage}
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
+5
-4
@@ -22,12 +22,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:l="/lib/layout">
|
||||
<j:set var="controls">
|
||||
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="yes" value="${%Prevent users from manually creating legacy API tokens}"/>
|
||||
<f:submit name="no" value="${%Dismiss}"/>
|
||||
</form>
|
||||
</j:set>
|
||||
<l:adminMonitor controls="${controls}">
|
||||
${%warningMessage}
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
+4
-4
@@ -22,8 +22,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
${%warningMessage(rootURL, it.url)}
|
||||
</div>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout">
|
||||
<l:adminMonitor>
|
||||
${%warningMessage(rootURL, it.url)}
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -22,12 +22,11 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-info">
|
||||
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
|
||||
<f:submit name="more" value="${%Learn more}"/>
|
||||
<f:submit name="dismiss" primary="false" value="${%Dismiss}"/>
|
||||
</form>
|
||||
${%blurb}
|
||||
</div>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:l="/lib/layout">
|
||||
<j:set var="controls">
|
||||
<a href="${rootURL}/manage/administrativeMonitor/jenkins.security.csp.impl.CspRecommendation" class="jenkins-button jenkins-button--primary">${%Learn more}</a>
|
||||
</j:set>
|
||||
<l:adminMonitor severity="info" controls="${controls}">
|
||||
${%blurb}
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
+3
-6
@@ -22,11 +22,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
|
||||
<div class="jenkins-alert jenkins-alert-warning">
|
||||
<form method="post" action="${rootURL}/${it.url}/disable">
|
||||
<f:submit value="${%Dismiss}"/>
|
||||
</form>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:l="/lib/layout">
|
||||
<l:adminMonitor>
|
||||
<j:set var="referenceAnchor">
|
||||
<a href="https://www.jenkins.io/redirect/csrf-protection" rel="noopener noreferrer" target="_blank">${%referenceUrlContent}</a>
|
||||
</j:set>
|
||||
@@ -36,5 +33,5 @@ THE SOFTWARE.
|
||||
<j:out value="${%warningMessage(referenceAnchor)}"/>
|
||||
<p />
|
||||
<j:out value="${%actionMessage(actionAnchor)}"/>
|
||||
</div>
|
||||
</l:adminMonitor>
|
||||
</j:jelly>
|
||||
@@ -0,0 +1,34 @@
|
||||
Behaviour.specify(
|
||||
".app-adminmonitor-dismiss-button",
|
||||
"admin-monitor",
|
||||
0,
|
||||
function (element) {
|
||||
element.addEventListener("click", function (event) {
|
||||
event.preventDefault();
|
||||
const url = element.dataset.url;
|
||||
fetch(url, {
|
||||
method: "POST",
|
||||
cache: "no-cache",
|
||||
headers: crumb.wrap({
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
}),
|
||||
body: new URLSearchParams({}),
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.ok) {
|
||||
const parent = element.closest(".app-adminmonitor");
|
||||
if (parent) {
|
||||
parent.remove();
|
||||
}
|
||||
} else {
|
||||
console.warn(
|
||||
`AdminMonitor dismiss request failed with status ${response.status}`,
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((error) =>
|
||||
console.warn(`AdminMonitor dismiss request failed: ${error}`),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,71 @@
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:d="jelly:define">
|
||||
<st:documentation> <![CDATA[
|
||||
Displays an administrative monitor alert.
|
||||
|
||||
@since TODO
|
||||
]]>
|
||||
<st:attribute name="severity" use="optional" >
|
||||
Severity of the alert, one of info, warning, danger or success. Defaults to warning if not specified.
|
||||
</st:attribute>
|
||||
<st:attribute name="dismissable" use="optional">
|
||||
If the alert can be dismissed by the user, defaults to true if not specified. Dismissed alerts can be re-enabled
|
||||
in the global configuration.
|
||||
</st:attribute>
|
||||
<st:attribute name="dismissValue" use="optional">
|
||||
The value of the dismiss tooltip. Defaults to "Dismiss" if not specified.
|
||||
</st:attribute>
|
||||
<st:attribute name="class" use="optional">
|
||||
Additional CSS class to add to the alert div.
|
||||
</st:attribute>
|
||||
<st:attribute name="id" use="optional">
|
||||
The id attribute to add to the alert div.
|
||||
</st:attribute>
|
||||
<st:attribute name="controls" use="optional"><![CDATA[
|
||||
Shows additional controls in the top right of the alert besides the dismiss button.
|
||||
|
||||
Define the controls like this:
|
||||
|
||||
<j:set var="controls">
|
||||
<form method="post" name="clear" action="${rootURL}/${it.url}/clear">
|
||||
<f:submit value="${%Clear}"/>
|
||||
</form>
|
||||
</j:set>
|
||||
|
||||
To be able to set controls, You must use a message.jelly. It is not possible
|
||||
to do this in groovy.
|
||||
]]>
|
||||
</st:attribute>
|
||||
|
||||
</st:documentation>
|
||||
<j:set var="severity" value="${attrs.severity ?: 'warning'}"/>
|
||||
<j:set var="dismissable" value="${attrs.dismissable ?: true}"/>
|
||||
<j:set var="dismissValue" value="${attrs.dismissValue ?: '%Dismiss'}"/>
|
||||
<st:adjunct includes="lib.layout.admin-monitor"/>
|
||||
<div id="${attrs.id}" class="app-adminmonitor jenkins-alert jenkins-alert-${severity} ${attrs.class}" data-monitor-id="${it.id}">
|
||||
<j:choose>
|
||||
<j:when test="${severity == 'danger'}">
|
||||
<l:icon src="symbol-alert-circle-outline" class="app-adminmonitor-icon"/>
|
||||
</j:when>
|
||||
<j:when test="${severity == 'warning'}">
|
||||
<l:icon src="symbol-warning-outline" class="app-adminmonitor-icon"/>
|
||||
</j:when>
|
||||
<j:otherwise>
|
||||
<l:icon src="symbol-information-circle" class="app-adminmonitor-icon"/>
|
||||
</j:otherwise>
|
||||
</j:choose>
|
||||
<div class="app-adminmonitor-content">
|
||||
<div class="app-adminmonitor-controls">
|
||||
<j:out value="${attrs.controls}"/>
|
||||
<l:isAdmin>
|
||||
<j:if test="${dismissable}">
|
||||
<button class="app-adminmonitor-dismiss-button jenkins-button" type="button" tooltip="${dismissValue}" data-url="${rootURL}/${it.url}/disable">
|
||||
<l:icon src="symbol-close" />
|
||||
</button>
|
||||
</j:if>
|
||||
</l:isAdmin>
|
||||
</div>
|
||||
<d:invokeBody />
|
||||
</div>
|
||||
</div>
|
||||
</j:jelly>
|
||||
@@ -19,3 +19,56 @@ searchBarInput.suggestions = function () {
|
||||
}))
|
||||
.filter((item) => !item.url.endsWith("#"));
|
||||
};
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const messagesContainer = document.querySelector(".manage-messages");
|
||||
if (!messagesContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updateLastVisibleMessageMargin = () => {
|
||||
const messageDivs = Array.from(messagesContainer.children).filter(
|
||||
(el) => el.tagName === "DIV",
|
||||
);
|
||||
|
||||
messageDivs.forEach((el) => {
|
||||
el.style.marginBottom = "";
|
||||
});
|
||||
|
||||
const visibleDivs = messageDivs.filter((el) => {
|
||||
const style = window.getComputedStyle(el);
|
||||
return (
|
||||
style.display !== "none" &&
|
||||
style.visibility !== "hidden" &&
|
||||
!el.hasAttribute("hidden") &&
|
||||
el.getClientRects().length > 0
|
||||
);
|
||||
});
|
||||
|
||||
const lastVisible = visibleDivs[visibleDivs.length - 1];
|
||||
if (lastVisible) {
|
||||
lastVisible.style.marginBottom = "var(--section-padding)";
|
||||
}
|
||||
};
|
||||
|
||||
let rafId = null;
|
||||
const scheduleUpdate = () => {
|
||||
if (rafId !== null) {
|
||||
return;
|
||||
}
|
||||
rafId = requestAnimationFrame(() => {
|
||||
rafId = null;
|
||||
updateLastVisibleMessageMargin();
|
||||
});
|
||||
};
|
||||
|
||||
updateLastVisibleMessageMargin();
|
||||
|
||||
const observer = new MutationObserver(scheduleUpdate);
|
||||
observer.observe(messagesContainer, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributes: true,
|
||||
attributeFilter: ["style", "class", "hidden", "aria-hidden"],
|
||||
});
|
||||
});
|
||||
@@ -88,11 +88,15 @@ $semantics: (
|
||||
--alert-success-text-color: var(--success-color);
|
||||
--alert-success-bg-color: color-mix(
|
||||
in sRGB,
|
||||
var(--success-color) 10%,
|
||||
var(--success-color) 4%,
|
||||
transparent
|
||||
);
|
||||
--alert-info-text-color: var(--accent-color);
|
||||
--alert-info-bg-color: color-mix(
|
||||
in sRGB,
|
||||
var(--accent-color) 4%,
|
||||
transparent
|
||||
);
|
||||
--alert-info-text-color: var(--blue);
|
||||
--alert-info-bg-color: color-mix(in sRGB, var(--blue) 10%, transparent);
|
||||
--alert-warning-text-color: color-mix(
|
||||
in sRGB,
|
||||
var(--warning-color) 80%,
|
||||
@@ -100,13 +104,13 @@ $semantics: (
|
||||
);
|
||||
--alert-warning-bg-color: color-mix(
|
||||
in sRGB,
|
||||
var(--warning-color) 10%,
|
||||
var(--warning-color) 4%,
|
||||
transparent
|
||||
);
|
||||
--alert-danger-text-color: var(--error-color);
|
||||
--alert-danger-bg-color: color-mix(
|
||||
in sRGB,
|
||||
var(--error-color) 10%,
|
||||
var(--error-color) 4%,
|
||||
transparent
|
||||
);
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
.alert,
|
||||
.jenkins-alert {
|
||||
font-size: var(--font-size-sm);
|
||||
padding: 15px;
|
||||
padding: 1rem;
|
||||
margin-bottom: var(--section-padding);
|
||||
border: var(--jenkins-border--inherit-subtle);
|
||||
border: var(--jenkins-border-width) solid rgb(from currentColor r g b / 0.1);
|
||||
border-radius: var(--form-input-border-radius);
|
||||
|
||||
strong {
|
||||
|
||||
@@ -1,3 +1,72 @@
|
||||
@use "../abstracts/mixins";
|
||||
|
||||
.app-adminmonitor {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
align-items: start;
|
||||
gap: 0.5rem;
|
||||
font-weight: 450;
|
||||
|
||||
&-icon {
|
||||
width: 1.375rem;
|
||||
height: 1.375rem;
|
||||
margin: -0.0625rem 0 -0.0625rem -0.0625rem;
|
||||
|
||||
* {
|
||||
stroke-width: 34px;
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
margin-bottom: -8px;
|
||||
}
|
||||
|
||||
&-controls {
|
||||
margin: -8px -8px 0 4px !important;
|
||||
float: right;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
& > form {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.jenkins-button {
|
||||
min-height: 36px;
|
||||
padding: 0 14px;
|
||||
}
|
||||
}
|
||||
|
||||
&-dismiss-button {
|
||||
--button-background: none;
|
||||
--button-background--hover: oklch(from currentColor l c h / 0.1);
|
||||
--button-background--active: oklch(from currentColor l c h / 0.2);
|
||||
--button-box-shadow--focus: oklch(from currentColor l c h / 0.1);
|
||||
|
||||
&:not(.jenkins-button--primary) {
|
||||
&::before {
|
||||
border: var(--jenkins-border-width) solid
|
||||
rgb(from currentColor r g b / 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
color: var(--color) !important;
|
||||
min-width: 36px;
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.manage-messages {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: calc(var(--section-padding) / 3);
|
||||
|
||||
& > div {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.manage-messages a:not(.jenkins-button),
|
||||
.manage-messages a:visited:not(.jenkins-button) {
|
||||
color: inherit !important;
|
||||
@@ -9,7 +78,7 @@
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.manage-messages dl:first-child {
|
||||
.manage-messages dl:first-of-type {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@@ -36,10 +105,6 @@
|
||||
|
||||
.manage-messages .alert,
|
||||
.manage-messages .jenkins-alert {
|
||||
&:last-of-type {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
@@ -47,7 +112,7 @@
|
||||
form {
|
||||
position: relative;
|
||||
float: right;
|
||||
margin: -6px 0 0 !important;
|
||||
margin: -6px 0 0;
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
|
||||
|
||||
@@ -2,29 +2,21 @@ package hudson.diagnosis;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import hudson.model.User;
|
||||
import hudson.security.GlobalMatrixAuthorizationStrategy;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import jenkins.model.Jenkins;
|
||||
import org.htmlunit.ElementNotFoundException;
|
||||
import org.htmlunit.HttpMethod;
|
||||
import org.htmlunit.Page;
|
||||
import org.htmlunit.WebRequest;
|
||||
import org.htmlunit.html.HtmlForm;
|
||||
import org.htmlunit.html.HtmlPage;
|
||||
import org.htmlunit.util.NameValuePair;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.jvnet.hudson.test.Issue;
|
||||
import org.jvnet.hudson.test.JenkinsRule;
|
||||
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* @author Kohsuke Kawaguchi
|
||||
@@ -39,25 +31,6 @@ class HudsonHomeDiskUsageMonitorTest {
|
||||
j = rule;
|
||||
}
|
||||
|
||||
@Test
|
||||
void flow() throws Exception {
|
||||
// manually activate this
|
||||
HudsonHomeDiskUsageMonitor mon = HudsonHomeDiskUsageMonitor.get();
|
||||
mon.activated = true;
|
||||
|
||||
// clicking yes should take us to somewhere
|
||||
j.submit(getForm(mon), "yes");
|
||||
assertTrue(mon.isEnabled());
|
||||
|
||||
// now dismiss
|
||||
// submit(getForm(mon),"no"); TODO: figure out why this test is fragile
|
||||
mon.doAct("no");
|
||||
assertFalse(mon.isEnabled());
|
||||
|
||||
// and make sure it's gone
|
||||
assertThrows(ElementNotFoundException.class, () -> getForm(mon));
|
||||
}
|
||||
|
||||
@Issue("SECURITY-371")
|
||||
@Test
|
||||
void noAccessForNonAdmin() throws Exception {
|
||||
@@ -77,9 +50,7 @@ class HudsonHomeDiskUsageMonitorTest {
|
||||
User bob = User.getById("bob", true);
|
||||
User administrator = User.getById("administrator", true);
|
||||
|
||||
WebRequest request = new WebRequest(new URI(wc.getContextPath() + "administrativeMonitor/hudsonHomeIsFull/act").toURL(), HttpMethod.POST);
|
||||
NameValuePair param = new NameValuePair("no", "true");
|
||||
request.setRequestParameters(List.of(param));
|
||||
WebRequest request = new WebRequest(new URI(wc.getContextPath() + "administrativeMonitor/hudsonHomeIsFull/disable").toURL(), HttpMethod.POST);
|
||||
|
||||
HudsonHomeDiskUsageMonitor mon = HudsonHomeDiskUsageMonitor.get();
|
||||
|
||||
@@ -94,18 +65,9 @@ class HudsonHomeDiskUsageMonitorTest {
|
||||
assertEquals(HttpURLConnection.HTTP_FORBIDDEN, p.getWebResponse().getStatusCode());
|
||||
|
||||
wc.withBasicApiToken(administrator);
|
||||
request = new WebRequest(new URI(wc.getContextPath() + "administrativeMonitor/hudsonHomeIsFull/act").toURL(), HttpMethod.POST);
|
||||
request.setRequestParameters(List.of(param));
|
||||
request = new WebRequest(new URI(wc.getContextPath() + "administrativeMonitor/hudsonHomeIsFull/disable").toURL(), HttpMethod.POST);
|
||||
p = wc.getPage(request);
|
||||
assertEquals(HttpURLConnection.HTTP_OK, p.getWebResponse().getStatusCode());
|
||||
assertFalse(mon.isEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the warning form.
|
||||
*/
|
||||
private HtmlForm getForm(HudsonHomeDiskUsageMonitor mon) throws IOException, SAXException {
|
||||
HtmlPage p = j.createWebClient().goTo("manage");
|
||||
return p.getFormByName(mon.id);
|
||||
}
|
||||
}
|
||||
@@ -5,19 +5,16 @@ import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import hudson.model.AdministrativeMonitor;
|
||||
import hudson.model.Item;
|
||||
import hudson.model.ListView;
|
||||
import hudson.model.View;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import jenkins.model.Jenkins;
|
||||
import org.htmlunit.ElementNotFoundException;
|
||||
import org.htmlunit.html.DomElement;
|
||||
import org.htmlunit.html.HtmlForm;
|
||||
import org.htmlunit.html.HtmlAnchor;
|
||||
import org.htmlunit.html.HtmlPage;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -39,7 +36,6 @@ class TooManyJobsButNoViewTest {
|
||||
@BeforeEach
|
||||
void setUp(JenkinsRule rule) {
|
||||
r = rule;
|
||||
mon = AdministrativeMonitor.all().get(TooManyJobsButNoView.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,12 +43,9 @@ class TooManyJobsButNoViewTest {
|
||||
*/
|
||||
@Test
|
||||
void initialState() throws Exception {
|
||||
verifyNoForm();
|
||||
}
|
||||
|
||||
private void verifyNoForm() throws IOException, SAXException {
|
||||
HtmlPage p = r.createWebClient().goTo("manage");
|
||||
assertThrows(ElementNotFoundException.class, () -> p.getFormByName(mon.id));
|
||||
try (JenkinsRule.WebClient wc = r.createWebClient()) {
|
||||
verifyNoMonitor(wc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,22 +56,23 @@ class TooManyJobsButNoViewTest {
|
||||
for (int i = 0; i <= TooManyJobsButNoView.THRESHOLD; i++)
|
||||
r.createFreeStyleProject();
|
||||
|
||||
HtmlPage p = r.createWebClient().goTo("manage");
|
||||
HtmlForm f = p.getFormByName(mon.id);
|
||||
assertNotNull(f);
|
||||
try (JenkinsRule.WebClient wc = r.createWebClient()) {
|
||||
HtmlPage p = wc.goTo("manage");
|
||||
HtmlAnchor link = p.querySelector("div[data-monitor-id=\"hudson.diagnosis.TooManyJobsButNoView\"] a");
|
||||
assertNotNull(link);
|
||||
|
||||
// this should take us to the new view page
|
||||
URL url = r.submit(f, "yes").getUrl();
|
||||
assertTrue(url.toExternalForm().endsWith("/newView"), url.toExternalForm());
|
||||
// this should take us to the new view page
|
||||
URL url = link.click().getUrl();
|
||||
assertTrue(url.toExternalForm().endsWith("/newView"), url.toExternalForm());
|
||||
|
||||
// since we didn't create a view, if we go back, we should see the warning again
|
||||
p = r.createWebClient().goTo("manage");
|
||||
assertNotNull(p.getFormByName(mon.id));
|
||||
// since we didn't create a view, if we go back, we should see the warning again
|
||||
verifyMonitor(wc);
|
||||
|
||||
// once we create a view, the message should disappear
|
||||
r.jenkins.addView(new ListView("test"));
|
||||
// once we create a view, the message should disappear
|
||||
r.jenkins.addView(new ListView("test"));
|
||||
|
||||
verifyNoForm();
|
||||
verifyNoMonitor(wc);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -102,7 +96,7 @@ class TooManyJobsButNoViewTest {
|
||||
|
||||
private void verifyNoMonitor(JenkinsRule.WebClient wc) throws IOException, SAXException {
|
||||
HtmlPage p = wc.goTo("manage");
|
||||
DomElement adminMonitorDiv = p.getElementById("tooManyJobsButNoView");
|
||||
DomElement adminMonitorDiv = p.querySelector("div[data-monitor-id=\"hudson.diagnosis.TooManyJobsButNoView\"]");
|
||||
assertThat(adminMonitorDiv, is(nullValue()));
|
||||
}
|
||||
|
||||
@@ -129,9 +123,8 @@ class TooManyJobsButNoViewTest {
|
||||
|
||||
private void verifyMonitor(JenkinsRule.WebClient wc) throws IOException, SAXException {
|
||||
HtmlPage p = wc.goTo("manage");
|
||||
DomElement adminMonitorDiv = p.getElementById("tooManyJobsButNoView");
|
||||
DomElement adminMonitorDiv = p.querySelector("div[data-monitor-id=\"hudson.diagnosis.TooManyJobsButNoView\"]");
|
||||
assertThat(adminMonitorDiv, is(notNullValue()));
|
||||
assertThat(adminMonitorDiv.getTextContent(), is(notNullValue()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import jenkins.security.csp.CspHeaderDecider;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.htmlunit.Page;
|
||||
import org.htmlunit.html.DomElement;
|
||||
import org.htmlunit.html.HtmlAnchor;
|
||||
import org.htmlunit.html.HtmlCheckBoxInput;
|
||||
import org.htmlunit.html.HtmlFormUtil;
|
||||
import org.htmlunit.html.HtmlPage;
|
||||
@@ -198,7 +199,8 @@ public class CspHeaderDeciderTest {
|
||||
assertTrue(ExtensionList.lookupSingleton(CspRecommendation.class).isActivated());
|
||||
|
||||
final HtmlPage htmlPage = webClient.goTo("manage/");
|
||||
final Page recommendationClick = htmlPage.getElementByName("more").click();
|
||||
HtmlAnchor link = htmlPage.querySelector("div[data-monitor-id=\"jenkins.security.csp.impl.CspRecommendation\"] a");
|
||||
final Page recommendationClick = link.click();
|
||||
assertThat(recommendationClick, instanceOf(HtmlPage.class));
|
||||
HtmlPage recommendationPage = (HtmlPage) recommendationClick;
|
||||
assertThat(
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><path d="M448 256c0-106-86-192-192-192S64 150 64 256s86 192 192 192 192-86 192-192z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><path d="M250.26 166.05L256 288l5.73-121.95a5.74 5.74 0 00-5.79-6h0a5.74 5.74 0 00-5.68 6z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/><path d="M256 367.91a20 20 0 1120-20 20 20 0 01-20 20z" fill="currentColor"/></svg>
|
||||
|
After Width: | Height: | Size: 514 B |
@@ -1 +1,24 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><path d="M248 64C146.39 64 64 146.39 64 248s82.39 184 184 184 184-82.39 184-184S349.61 64 248 64z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M220 220h32v116"/><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="32" d="M208 340h88"/><path fill="currentColor" d="M248 130a26 26 0 1026 26 26 26 0 00-26-26z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path d="M448 256c0-106-86-192-192-192S64 150 64 256s86 192 192 192 192-86 192-192z" fill="none" stroke="currentColor"
|
||||
stroke-miterlimit="10" stroke-width="32" />
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="32"
|
||||
d="M224 220h32v116"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-miterlimit="10"
|
||||
stroke-width="32"
|
||||
d="M212 340h88"
|
||||
/>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M255 130a26 26 0 1026 26 26 26 0 00-26-26z"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 581 B After Width: | Height: | Size: 666 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><path d="M85.57 446.25h340.86a32 32 0 0028.17-47.17L284.18 82.58c-12.09-22.44-44.27-22.44-56.36 0L57.4 399.08a32 32 0 0028.17 47.17z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/><path d="M250.26 195.39l5.74 122 5.73-121.95a5.74 5.74 0 00-5.79-6h0a5.74 5.74 0 00-5.68 5.95z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/><path d="M256 397.25a20 20 0 1120-20 20 20 0 01-20 20z" fill="currentColor"/></svg>
|
||||
|
After Width: | Height: | Size: 591 B |
Reference in new issue
Block a user