Skip to content

Commit 4778ca8

Browse files
authored
[JENKINS-69651] CSP compatibility for ScriptApproval (#582)
1 parent 79b7281 commit 4778ca8

File tree

4 files changed

+274
-191
lines changed

4 files changed

+274
-191
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
document.getElementById('deprecated-approvedClasspaths-clear-btn').style.display = 'none';
2+
document.getElementById('deprecated-approvedClasspaths-clear-spinner').style.display = '';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
document.getElementById('deprecated-approvedClasspaths-clear-btn').style.display = '';
2+
document.getElementById('deprecated-approvedClasspaths-clear-spinner').style.display = 'none';

src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/index.jelly

Lines changed: 19 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -27,176 +27,8 @@ THE SOFTWARE.
2727
<l:layout title="In-process Script Approval" permission="${app.ADMINISTER}">
2828
<st:include page="sidepanel.jelly" it="${app}"/>
2929
<l:main-panel>
30-
<script>
31-
var mgr = <st:bind value="${it}"/>;
32-
function hideScript(hash) {
33-
document.getElementById('ps-' + hash).remove();
34-
}
35-
function approveScript(hash) {
36-
mgr.approveScript(hash);
37-
hideScript(hash);
38-
}
39-
function denyScript(hash) {
40-
mgr.denyScript(hash);
41-
hideScript(hash);
42-
}
43-
function hideSignature(hash) {
44-
document.getElementById('s-' + hash).style.display = 'none';
45-
}
46-
function updateApprovedSignatures(r) {
47-
var both = r.responseObject();
48-
document.getElementById('approvedSignatures').value = both[0].join('\n');
49-
document.getElementById('aclApprovedSignatures').value = both[1].join('\n');
50-
if (document.getElementById('dangerousApprovedSignatures')) {
51-
document.getElementById('dangerousApprovedSignatures').value = both[2].join('\n');
52-
}
53-
}
54-
function approveSignature(signature, hash) {
55-
mgr.approveSignature(signature, function(r) {
56-
updateApprovedSignatures(r);
57-
});
58-
hideSignature(hash);
59-
}
60-
function aclApproveSignature(signature, hash) {
61-
mgr.aclApproveSignature(signature, function(r) {
62-
updateApprovedSignatures(r);
63-
});
64-
hideSignature(hash);
65-
}
66-
function denySignature(signature, hash) {
67-
mgr.denySignature(signature);
68-
hideSignature(hash);
69-
}
70-
function clearApprovedSignatures() {
71-
mgr.clearApprovedSignatures(function(r) {
72-
updateApprovedSignatures(r);
73-
});
74-
}
75-
function clearDangerousApprovedSignatures() {
76-
mgr.clearDangerousApprovedSignatures(function(r) {
77-
updateApprovedSignatures(r);
78-
});
79-
}
80-
81-
function renderPendingClasspathEntries(pendingClasspathEntries) {
82-
if (pendingClasspathEntries.length == 0) {
83-
document.getElementById('pendingClasspathEntries-none').style.display = '';
84-
Array.from(document.getElementById('pendingClasspathEntries').children).forEach(function(e){e.remove()});
85-
document.getElementById('pendingClasspathEntries').style.display = 'none';
86-
} else {
87-
document.getElementById('pendingClasspathEntries-none').style.display = 'none';
88-
Array.from(document.getElementById('pendingClasspathEntries').children).forEach(function(e){e.remove()});
89-
/*
90-
Create a list like:
91-
<p id="pcp-${pcp.hash}">
92-
<button class="approve" onclick="approveClasspathEntry('${pcp.hash}')">Approve</button> /
93-
<button class="deny" onclick="denyClasspathEntry('${pcp.hash}')">Deny</button>
94-
${pcp.hash} (${pcp.path})
95-
</p>
96-
*/
97-
pendingClasspathEntries.forEach(function(e) {
98-
var block = document.createElement('p');
99-
block.setAttribute('id', 'pcp-' + e.hash);
100-
var approveButton = document.createElement('button');
101-
approveButton.setAttribute('class', 'approve');
102-
approveButton.setAttribute('hash', e.hash);
103-
approveButton.textContent = 'Approve';
104-
approveButton.addEventListener('click', function() {
105-
approveClasspathEntry(this.getAttribute('hash'));
106-
});
107-
var denyButton = document.createElement('button');
108-
denyButton.setAttribute('class', 'deny');
109-
denyButton.setAttribute('hash', e.hash);
110-
denyButton.textContent = 'Deny';
111-
denyButton.addEventListener('click', function() {
112-
denyClasspathEntry(this.getAttribute('hash'));
113-
});
114-
block.appendChild(approveButton);
115-
block.appendChild(denyButton);
116-
var code = document.createElement('code');
117-
code.setAttribute('title', e.hash);
118-
code.textContent = e.path;
119-
block.appendChild(code);
120-
121-
document.getElementById('pendingClasspathEntries').appendChild(block);
122-
});
123-
document.getElementById('pendingClasspathEntries').style.display = '';
124-
}
125-
}
126-
127-
function renderApprovedClasspathEntries(approvedClasspathEntries) {
128-
if (approvedClasspathEntries.length == 0) {
129-
document.getElementById('approvedClasspathEntries-none').style.display = '';
130-
Array.from(document.getElementById('approvedClasspathEntries').children).forEach(function(e){e.remove()});
131-
document.getElementById('approvedClasspathEntries').style.display = 'none';
132-
document.getElementById('approvedClasspathEntries-clear').style.display = 'none';
133-
} else {
134-
document.getElementById('approvedClasspathEntries-none').style.display = 'none';
135-
Array.from(document.getElementById('approvedClasspathEntries').children).forEach(function(e){e.remove()});
136-
/*
137-
Create a list like:
138-
<p id="acp-${acp.hash}">
139-
<button class="delete" onclick="denyApprovedClasspathEntry('${pcp.hash}')">Delete</button>
140-
${acp.hash} (${acp.path})
141-
</p>
142-
*/
143-
approvedClasspathEntries.forEach(function(e) {
144-
var block = document.createElement('p');
145-
block.setAttribute('id', 'acp-' + e.hash);
146-
var deleteButton = document.createElement('button');
147-
deleteButton.setAttribute('class', 'delete');
148-
deleteButton.setAttribute('hash', e.hash);
149-
deleteButton.textContent = 'Delete';
150-
deleteButton.addEventListener('click', function() {
151-
if (confirm('Really delete this approved classpath entry? Any existing scripts using it will need to be rerun and the entry reapproved.')) {
152-
denyApprovedClasspathEntry(this.getAttribute('hash'));
153-
}
154-
});
155-
block.appendChild(deleteButton);
156-
var code = document.createElement('code');
157-
code.setAttribute('title', e.hash);
158-
code.textContent = e.path;
159-
block.appendChild(code);
160-
161-
document.getElementById('approvedClasspathEntries').appendChild(block);
162-
});
163-
document.getElementById('approvedClasspathEntries').style.display = '';
164-
document.getElementById('approvedClasspathEntries-clear').style.display = '';
165-
}
166-
}
167-
168-
function renderClasspaths(r) {
169-
renderPendingClasspathEntries(r.responseObject()[0]);
170-
renderApprovedClasspathEntries(r.responseObject()[1]);
171-
}
172-
173-
function approveClasspathEntry(hash) {
174-
mgr.approveClasspathEntry(hash, function(r) {
175-
renderClasspaths(r);
176-
});
177-
}
178-
function denyClasspathEntry(hash) {
179-
mgr.denyClasspathEntry(hash, function(r) {
180-
renderClasspaths(r);
181-
});
182-
}
183-
function denyApprovedClasspathEntry(hash) {
184-
mgr.denyApprovedClasspathEntry(hash, function(r) {
185-
renderClasspaths(r);
186-
});
187-
}
188-
function clearApprovedClasspathEntries() {
189-
mgr.clearApprovedClasspathEntries(function(r) {
190-
renderClasspaths(r);
191-
});
192-
}
193-
194-
window.addEventListener("load", function(){
195-
mgr.getClasspathRenderInfo(function(r) {
196-
renderClasspaths(r);
197-
});
198-
});
199-
</script>
30+
<st:bind value="${it}" var="mgr"/>
31+
<st:adjunct includes="org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval.script-approval"/>
20032
<j:choose>
20133
<j:when test="${it.pendingScripts.isEmpty()}">
20234
<p>
@@ -207,7 +39,7 @@ THE SOFTWARE.
20739
<j:forEach var="ps" items="${it.pendingScripts}">
20840
<div id="ps-${ps.hash}" class="pending-script">
20941
<p class="ps-context">
210-
<button class="approve" onclick="approveScript('${ps.hash}')">Approve</button> / <button class="deny" onclick="denyScript('${ps.hash}')">Deny</button> ${ps.language.displayName} script
42+
<button class="approve" data-hash="${ps.hash}">Approve</button> / <button class="deny" data-hash="${ps.hash}">Deny</button> ${ps.language.displayName} script
21143
<st:include it="${ps.context}" page="index.jelly"/>:
21244
</p>
21345
<f:textarea readonly="readonly" codemirror-mode="${ps.language.codeMirrorMode}" codemirror-config='"readOnly": true' rows="10" cols="80" value="${ps.script}"/>
@@ -218,7 +50,7 @@ THE SOFTWARE.
21850
<j:if test="${it.hasDeprecatedApprovedScriptHashes()}">
21951
<p id="deprecated-approvedScripts-clear">
22052
You have <st:out value="${it.countDeprecatedApprovedScriptHashes()}"/> script approvals with deprecated hashes:
221-
<button onclick="if (confirm('Really delete all deprecated approvals? Any existing scripts will need to be requeued and reapproved.')) {mgr.clearDeprecatedApprovedScripts(); document.getElementById('deprecated-approvedScripts-clear').style.display = 'none';}">Clear Deprecated Approvals</button>
53+
<button>Clear Deprecated Approvals</button>
22254
</p>
22355
<p class="setting-description">
22456
Script approvals are stored in Jenkins as the hashed value of the script. Old approvals were hashed using SHA-1, which is deprecated.
@@ -228,7 +60,7 @@ THE SOFTWARE.
22860
</j:if>
22961
<p id="approvedScripts-clear">
23062
You can also remove all previous script approvals:
231-
<button onclick="if (confirm('Really delete all approvals? Any existing scripts will need to be requeued and reapproved.')) {mgr.clearApprovedScripts()}">Clear Approvals</button>
63+
<button>Clear Approvals</button>
23264
</p>
23365
<hr/>
23466
<j:choose>
@@ -240,12 +72,12 @@ THE SOFTWARE.
24072
<j:otherwise>
24173
<j:forEach var="s" items="${it.pendingSignatures}">
24274
<div id="s-${s.hash}">
243-
<p>
244-
<button onclick="approveSignature('${s.signature}', '${s.hash}')">Approve</button> /
75+
<p class="s-context">
76+
<button data-signature="${s.signature}" data-hash="${s.hash}" class="approve">Approve</button> /
24577
<j:if test="${!s.signature.startsWith('field')}">
246-
<button onclick="aclApproveSignature('${s.signature}', '${s.hash}')">Approve assuming permission check</button> /
78+
<button data-signature="${s.signature}" data-hash="${s.hash}" class="acl-approve">Approve assuming permission check</button> /
24779
</j:if>
248-
<button onclick="denySignature('${s.signature}', '${s.hash}')">Deny</button> signature
80+
<button data-signature="${s.signature}" data-hash="${s.hash}" class="deny">Deny</button> signature
24981
<st:include it="${s.context}" page="index.jelly"/>:
25082
<code>${s.signature}</code>
25183
<j:if test="${s.dangerous}">
@@ -274,13 +106,15 @@ THE SOFTWARE.
274106
<j:forEach var="line" items="${dangerousApprovedSignatures}">${line}<st:out value="&#10;"/></j:forEach>
275107
</textarea>
276108
</j:if>
277-
<p>
109+
<p id="approvedSignatures-clear">
278110
You can also remove all previous signature approvals:
279-
<button onclick="if (confirm('Really delete all approvals? Any existing scripts will need to be rerun and signatures reapproved.')) {clearApprovedSignatures()}">Clear Approvals</button>
111+
<button>Clear Approvals</button>
280112
</p>
281113
<j:if test="${!empty(dangerousApprovedSignatures)}">
282-
Or you can just remove the dangerous ones:
283-
<button onclick="clearDangerousApprovedSignatures()">Clear only dangerous Approvals</button>
114+
<p id="dangerousApprovedSignatures-clear">
115+
Or you can just remove the dangerous ones:
116+
<button>Clear only dangerous Approvals</button>
117+
</p>
284118
</j:if>
285119
<hr/>
286120
<p id="pendingClasspathEntries-none">
@@ -299,7 +133,7 @@ THE SOFTWARE.
299133
<p id="deprecated-approvedClasspaths-clear">
300134
You have ${it.countDeprecatedApprovedClasspathHashes()} approved classpath entries with deprecated hashes:
301135
<span id="deprecated-approvedClasspaths-clear-btn">
302-
<button onclick="if (confirm('This will be scheduled on a background thread. You can follow the progress in the system log')) {mgr.convertDeprecatedApprovedClasspathEntries(); document.getElementById('deprecated-approvedClasspaths-clear-btn').style.display = 'none'; document.getElementById('deprecated-approvedClasspaths-clear-spinner').style.display = '';}">Rehash Deprecated Approvals</button>
136+
<button>Rehash Deprecated Approvals</button>
303137
</span>
304138
<span id="deprecated-approvedClasspaths-clear-spinner">
305139
<l:icon alt="${%Converting...}" class="${it.spinnerIconClassName} icon-md"/>
@@ -312,22 +146,16 @@ THE SOFTWARE.
312146
</p>
313147
<j:choose>
314148
<j:when test="${it.isConvertingDeprecatedApprovedClasspathEntries()}">
315-
<script>
316-
document.getElementById('deprecated-approvedClasspaths-clear-btn').style.display = 'none';
317-
document.getElementById('deprecated-approvedClasspaths-clear-spinner').style.display = '';
318-
</script>
149+
<st:adjunct includes="org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval.deprecated-approvedClasspaths-clear-btn-hide"/>
319150
</j:when>
320151
<j:otherwise>
321-
<script>
322-
document.getElementById('deprecated-approvedClasspaths-clear-btn').style.display = '';
323-
document.getElementById('deprecated-approvedClasspaths-clear-spinner').style.display = 'none';
324-
</script>
152+
<st:adjunct includes="org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval.deprecated-approvedClasspaths-clear-btn-show"/>
325153
</j:otherwise>
326154
</j:choose>
327155
</j:if>
328156
<p id="approvedClasspathEntries-clear">
329157
You can also remove all previous classpath entry approvals:
330-
<button onclick="if (confirm('Really delete all approvals? Any existing scripts using a classpath will need to be rerun and entries reapproved.')) {clearApprovedClasspathEntries()}">Clear Classpath Entries</button>
158+
<button>Clear Classpath Entries</button>
331159
</p>
332160
</l:main-panel>
333161
</l:layout>

0 commit comments

Comments
 (0)