Skip to content

Commit 6327441

Browse files
committed
Merge branch 'master' into skip-symlink-tests-if-not-supported
2 parents ab244ce + 587f636 commit 6327441

File tree

18 files changed

+552
-340
lines changed

18 files changed

+552
-340
lines changed

.github/workflows/announce-lts-rc.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
discourse-author-username: jenkins-release-bot
1818
discourse-category: 23
1919
- name: Post on mailing list
20-
uses: dawidd6/action-send-mail@6e71c855c9a091d80a519621b9fd3e8d252ca40c # v7
20+
uses: dawidd6/action-send-mail@afe978662944c6805dd197bac88b27acb0bda55a # v8
2121
with:
2222
server_address: smtp.gmail.com
2323
server_port: 465

ath.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ set -o xtrace
66
cd "$(dirname "$0")"
77

88
# https://github.com/jenkinsci/acceptance-test-harness/releases
9-
export ATH_VERSION=6528.v0005e222b_5b_c
9+
export ATH_VERSION=6535.v65db_170d2a_03
1010

1111
if [[ $# -eq 0 ]]; then
1212
export JDK=21

cli/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<url>https://github.com/jenkinsci/jenkins</url>
1616

1717
<properties>
18-
<mina-sshd.version>2.16.0</mina-sshd.version>
18+
<mina-sshd.version>2.17.1</mina-sshd.version>
1919
<!-- Filled in by jacoco-maven-plugin -->
2020
<jacocoSurefireArgs />
2121
</properties>

core/src/main/java/hudson/Functions.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@
170170
import jenkins.model.details.Detail;
171171
import jenkins.model.details.DetailFactory;
172172
import jenkins.model.details.DetailGroup;
173+
import jenkins.telemetry.impl.PasswordMasking;
173174
import jenkins.util.SystemProperties;
174175
import org.apache.commons.jelly.JellyContext;
175176
import org.apache.commons.jelly.JellyTagException;
@@ -2256,32 +2257,64 @@ public String getPasswordValue(Object o) {
22562257
if (o instanceof Secret || Secret.BLANK_NONSECRET_PASSWORD_FIELDS_WITHOUT_ITEM_CONFIGURE) {
22572258
if (req != null) {
22582259
if (NON_RECURSIVE_PASSWORD_MASKING_PERMISSION_CHECK) {
2260+
List<Ancestor> ancestors = req.getAncestors();
2261+
String closestAncestor = ancestors.isEmpty() ? "unknown" :
2262+
ancestors.getLast().getObject().getClass().getName();
2263+
22592264
Item item = req.findAncestorObject(Item.class);
22602265
if (item != null && !item.hasPermission(Item.CONFIGURE)) {
2266+
PasswordMasking.recordMasking(
2267+
item.getClass().getName(),
2268+
closestAncestor,
2269+
getJellyViewsInformationForCurrentRequest()
2270+
);
22612271
return "********";
22622272
}
22632273
Computer computer = req.findAncestorObject(Computer.class);
22642274
if (computer != null && !computer.hasPermission(Computer.CONFIGURE)) {
2275+
PasswordMasking.recordMasking(
2276+
computer.getClass().getName(),
2277+
closestAncestor,
2278+
getJellyViewsInformationForCurrentRequest()
2279+
);
22652280
return "********";
22662281
}
22672282
} else {
22682283
List<Ancestor> ancestors = req.getAncestors();
2284+
String closestAncestor = ancestors.isEmpty() ? "unknown" :
2285+
ancestors.getLast().getObject().getClass().getName();
2286+
22692287
for (Ancestor ancestor : Iterators.reverse(ancestors)) {
22702288
Object type = ancestor.getObject();
22712289
if (type instanceof Item item) {
22722290
if (!item.hasPermission(Item.CONFIGURE)) {
2291+
PasswordMasking.recordMasking(
2292+
item.getClass().getName(),
2293+
closestAncestor,
2294+
getJellyViewsInformationForCurrentRequest()
2295+
);
22732296
return "********";
22742297
}
22752298
break;
22762299
}
22772300
if (type instanceof Computer computer) {
22782301
if (!computer.hasPermission(Computer.CONFIGURE)) {
2302+
PasswordMasking.recordMasking(
2303+
computer.getClass().getName(),
2304+
closestAncestor,
2305+
getJellyViewsInformationForCurrentRequest()
2306+
);
22792307
return "********";
22802308
}
22812309
break;
22822310
}
22832311
if (type instanceof View view) {
22842312
if (!view.hasPermission(View.CONFIGURE)) {
2313+
PasswordMasking.recordMasking(
2314+
view.getClass().getName(),
2315+
closestAncestor,
2316+
getJellyViewsInformationForCurrentRequest()
2317+
);
22852318
return "********";
22862319
}
22872320
break;
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* The MIT License
3+
*
4+
* Copyright (c) 2026, CloudBees, Inc.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
package jenkins.telemetry.impl;
26+
27+
import edu.umd.cs.findbugs.annotations.NonNull;
28+
import hudson.Extension;
29+
import java.time.LocalDate;
30+
import java.util.Map;
31+
import java.util.concurrent.ConcurrentHashMap;
32+
import java.util.concurrent.atomic.AtomicLong;
33+
import jenkins.telemetry.Telemetry;
34+
import net.sf.json.JSONArray;
35+
import net.sf.json.JSONObject;
36+
import org.kohsuke.accmod.Restricted;
37+
import org.kohsuke.accmod.restrictions.NoExternalUse;
38+
39+
/**
40+
* Telemetry implementation gathering information about password field masking.
41+
*/
42+
@Extension
43+
@Restricted(NoExternalUse.class)
44+
public class PasswordMasking extends Telemetry {
45+
46+
private static final Map<String, AtomicLong> maskingCounts = new ConcurrentHashMap<>();
47+
48+
/**
49+
* Records when password masking occurs.
50+
*
51+
* @param className the class name of the object
52+
* @param closestAncestor the closest ancestor class name
53+
* @param jellyView the Jelly view where masking occurred
54+
*/
55+
public static void recordMasking(String className, String closestAncestor, String jellyView) {
56+
if (Telemetry.isDisabled()) {
57+
return;
58+
}
59+
60+
String key = className + "|" + closestAncestor + "|" + jellyView;
61+
maskingCounts.computeIfAbsent(key, k -> new AtomicLong(0)).incrementAndGet();
62+
}
63+
64+
@NonNull
65+
@Override
66+
public String getDisplayName() {
67+
return "Password field masking";
68+
}
69+
70+
@NonNull
71+
@Override
72+
public LocalDate getStart() {
73+
return LocalDate.of(2026, 1, 26);
74+
}
75+
76+
@NonNull
77+
@Override
78+
public LocalDate getEnd() {
79+
return LocalDate.of(2026, 7, 26);
80+
}
81+
82+
@Override
83+
public JSONObject createContent() {
84+
JSONArray events = new JSONArray();
85+
for (Map.Entry<String, AtomicLong> entry : maskingCounts.entrySet()) {
86+
String[] parts = entry.getKey().split("\\|", 3);
87+
if (parts.length == 3) {
88+
String className = parts[0];
89+
String closestAncestor = parts[1];
90+
String jellyView = parts[2];
91+
long count = entry.getValue().longValue();
92+
93+
JSONObject event = new JSONObject();
94+
event.put("className", className);
95+
event.put("closestAncestor", closestAncestor);
96+
event.put("jellyView", jellyView);
97+
event.put("count", count);
98+
events.add(event);
99+
}
100+
}
101+
102+
maskingCounts.clear();
103+
104+
JSONObject payload = new JSONObject();
105+
payload.put("components", buildComponentInformation());
106+
payload.put("masking", events);
107+
108+
return payload;
109+
}
110+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!--
2+
The MIT License
3+
4+
Copyright (c) 2026 Somil Jain
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
THE SOFTWARE.
23+
-->
24+
25+
<?jelly escape-by-default='true'?>
26+
<j:jelly xmlns:j="jelly:core"
27+
xmlns:st="jelly:stapler">
28+
<st:redirect url="thirdPartyLicenses"/>
29+
</j:jelly>

core/src/main/resources/jenkins/security/csp/impl/CspRecommendation/index.jelly

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ THE SOFTWARE.
3838
<form method="post" action="${rootURL}/${it.url}/act" name="${it.id}">
3939
<div>
4040
<f:bottomButtonBar>
41-
<f:submit name="setup" value="${%Set up now}"/>
41+
<f:submit name="setup" value="${%Go to configuration}"/>
4242
<f:submit primary="false" name="defer" value="${%Cancel}"/>
4343
</f:bottomButtonBar>
4444
</div>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?jelly escape-by-default='true'?>
2+
<j:jelly xmlns:j="jelly:core">
3+
This trial collects detailed information about password field masking when users lack Configure permission on Items, Computers, or Views:
4+
<ul>
5+
<li>The class name</li>
6+
<li>The closest ancestor class name</li>
7+
<li>The Jelly view hierarchy where masking occurred</li>
8+
<li>The frequency of each combination</li>
9+
</ul>
10+
<p>
11+
This masking behavior is a fallback that should normally be rare, as views rendering content for users without Configure permission should use read-only mode instead.
12+
</p>
13+
<p>
14+
Additionally, this trial collects the list of installed plugins, their version, and the version of Jenkins.
15+
</p>
16+
</j:jelly>

core/src/main/resources/lib/layout/keyboard-shortcut.jelly

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ THE SOFTWARE.
5353
</j:choose>
5454
</div>
5555
</j:set>
56-
<j:out value="${h.formatMessage(message, h.translateModifierKeysForUsersPlatform(body))}"/>
56+
<j:out value="${h.formatMessage(attrs.message, h.translateModifierKeysForUsersPlatform(body))}"/>
5757
</div>
5858
</j:set>
5959

package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,28 @@
2424
},
2525
"devDependencies": {
2626
"@babel/cli": "7.28.6",
27-
"@babel/core": "7.28.6",
28-
"@babel/preset-env": "7.28.6",
27+
"@babel/core": "7.29.0",
28+
"@babel/preset-env": "7.29.0",
2929
"@eslint/js": "9.39.2",
3030
"babel-loader": "10.0.0",
3131
"clean-webpack-plugin": "4.0.0",
32-
"css-loader": "7.1.2",
32+
"css-loader": "7.1.3",
3333
"css-minimizer-webpack-plugin": "7.0.4",
3434
"eslint": "9.39.2",
3535
"eslint-config-prettier": "10.1.8",
3636
"eslint-formatter-checkstyle": "9.0.1",
37-
"globals": "17.0.0",
37+
"globals": "17.3.0",
3838
"handlebars-loader": "1.7.3",
3939
"mini-css-extract-plugin": "2.10.0",
4040
"postcss": "8.5.6",
4141
"postcss-loader": "8.2.0",
42-
"postcss-preset-env": "11.1.1",
42+
"postcss-preset-env": "11.1.2",
4343
"postcss-scss": "4.0.9",
4444
"prettier": "3.8.1",
45-
"sass": "1.97.2",
45+
"sass": "1.97.3",
4646
"sass-loader": "16.0.6",
4747
"style-loader": "4.0.0",
48-
"stylelint": "17.0.0",
48+
"stylelint": "17.1.0",
4949
"stylelint-checkstyle-reporter": "1.1.1",
5050
"stylelint-config-standard-scss": "17.0.0",
5151
"webpack": "5.104.1",

0 commit comments

Comments
 (0)