Skip to content

Commit 49ab0bb

Browse files
authored
Merge branch 'master' into build-page-console-height
2 parents c987440 + a19b790 commit 49ab0bb

File tree

79 files changed

+1094
-547
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+1094
-547
lines changed

.github/workflows/run-since-updater.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
id: run_script
3030
shell: bash
3131
- name: Create Pull Request
32-
uses: peter-evans/create-pull-request@dd2324fc52d5d43c699a5636bcf19fceaa70c284 # v7
32+
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7
3333
with:
3434
token: ${{ secrets.GITHUB_TOKEN }}
3535
commit-message: Fill in since annotations

bom/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ THE SOFTWARE.
5656
<dependency>
5757
<groupId>org.slf4j</groupId>
5858
<artifactId>slf4j-bom</artifactId>
59-
<version>2.0.16</version>
59+
<version>2.0.17</version>
6060
<type>pom</type>
6161
<scope>import</scope>
6262
</dependency>

cli/src/main/java/hudson/cli/CLI.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ public static int _main(String[] _args) throws Exception {
318318
throw new AssertionError();
319319
}
320320

321-
@SuppressFBWarnings(value = {"PATH_TRAVERSAL_IN", "URLCONNECTION_SSRF_FD"}, justification = "User provided values for running the program.")
321+
@SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "User provided value for running the program.")
322322
private static String readAuthFromFile(String auth) throws IOException {
323323
Path path;
324324
try {
@@ -329,7 +329,7 @@ private static String readAuthFromFile(String auth) throws IOException {
329329
return Files.readString(path, Charset.defaultCharset());
330330
}
331331

332-
@SuppressFBWarnings(value = {"PATH_TRAVERSAL_IN", "URLCONNECTION_SSRF_FD"}, justification = "User provided values for running the program.")
332+
@SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "User provided value for running the program.")
333333
private static File getFileFromArguments(List<String> args) {
334334
return new File(args.get(1));
335335
}

core/src/main/java/hudson/DescriptorExtensionList.java

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import edu.umd.cs.findbugs.annotations.CheckForNull;
2828
import edu.umd.cs.findbugs.annotations.NonNull;
29+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
2930
import hudson.model.Describable;
3031
import hudson.model.Descriptor;
3132
import hudson.model.Descriptor.FormException;
@@ -274,6 +275,7 @@ protected Descriptor adapt(ExtensionComponent<Descriptor> item) {
274275
/**
275276
* Exposed just for the test harness. Clear legacy instances.
276277
*/
278+
@SuppressFBWarnings(value = "HSM_HIDING_METHOD", justification = "TODO needs triage")
277279
public static void clearLegacyInstances() {
278280
legacyDescriptors.clear();
279281
}

core/src/main/java/hudson/ExtensionList.java

+35-14
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@
3636
import java.util.ArrayList;
3737
import java.util.Collection;
3838
import java.util.Collections;
39+
import java.util.IdentityHashMap;
3940
import java.util.Iterator;
4041
import java.util.List;
4142
import java.util.Map;
4243
import java.util.Objects;
44+
import java.util.Set;
4345
import java.util.Vector;
4446
import java.util.concurrent.ConcurrentHashMap;
4547
import java.util.concurrent.CopyOnWriteArrayList;
@@ -48,6 +50,8 @@
4850
import jenkins.ExtensionComponentSet;
4951
import jenkins.model.Jenkins;
5052
import jenkins.util.io.OnMaster;
53+
import org.kohsuke.accmod.Restricted;
54+
import org.kohsuke.accmod.restrictions.NoExternalUse;
5155

5256
/**
5357
* Retains the known extension instances for the given type 'T'.
@@ -335,27 +339,44 @@ protected Object getLoadLock() {
335339
/**
336340
* Used during {@link Jenkins#refreshExtensions()} to add new components into existing {@link ExtensionList}s.
337341
* Do not call from anywhere else.
342+
* @return true if {@link #fireOnChangeListeners} should be called on {@code this} after all lists have been refreshed.
338343
*/
339-
public void refresh(ExtensionComponentSet delta) {
340-
boolean fireOnChangeListeners = false;
344+
@Restricted(NoExternalUse.class)
345+
public boolean refresh(ExtensionComponentSet delta) {
341346
synchronized (getLoadLock()) {
342347
if (extensions == null)
343-
return; // not yet loaded. when we load it, we'll load everything visible by then, so no work needed
344-
345-
Collection<ExtensionComponent<T>> found = load(delta);
346-
if (!found.isEmpty()) {
347-
List<ExtensionComponent<T>> l = new ArrayList<>(extensions);
348-
l.addAll(found);
349-
extensions = sort(l);
350-
fireOnChangeListeners = true;
348+
return false; // not yet loaded. when we load it, we'll load everything visible by then, so no work needed
349+
350+
Collection<ExtensionComponent<T>> newComponents = load(delta);
351+
if (!newComponents.isEmpty()) {
352+
// We check to ensure that we do not insert duplicate instances of already-loaded extensions into the list.
353+
// This can happen when dynamically loading a plugin with an extension A that itself loads another
354+
// extension B from the same plugin in some contexts, such as in A's constructor or via a method in A called
355+
// by an ExtensionListListener. In those cases, ExtensionList.refresh may be called on a list that already
356+
// includes the new extensions. Note that ExtensionComponent objects are always unique, even when
357+
// ExtensionComponent.getInstance is identical, so we have to track the components and instances separately
358+
// to handle ordinal sorting and check for dupes.
359+
List<ExtensionComponent<T>> components = new ArrayList<>(extensions);
360+
Set<T> instances = Collections.newSetFromMap(new IdentityHashMap<>());
361+
for (ExtensionComponent<T> component : components) {
362+
instances.add(component.getInstance());
363+
}
364+
boolean fireListeners = false;
365+
for (ExtensionComponent<T> newComponent : newComponents) {
366+
if (instances.add(newComponent.getInstance())) {
367+
fireListeners = true;
368+
components.add(newComponent);
369+
}
370+
}
371+
extensions = sort(new ArrayList<>(components));
372+
return fireListeners;
351373
}
352374
}
353-
if (fireOnChangeListeners) {
354-
fireOnChangeListeners();
355-
}
375+
return false;
356376
}
357377

358-
private void fireOnChangeListeners() {
378+
@Restricted(NoExternalUse.class)
379+
public void fireOnChangeListeners() {
359380
for (ExtensionListListener listener : listeners) {
360381
try {
361382
listener.onChange();

core/src/main/java/hudson/PluginManager.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
import java.util.HashMap;
101101
import java.util.HashSet;
102102
import java.util.Iterator;
103+
import java.util.LinkedHashMap;
103104
import java.util.LinkedHashSet;
104105
import java.util.List;
105106
import java.util.Locale;
@@ -114,7 +115,6 @@
114115
import java.util.concurrent.ConcurrentMap;
115116
import java.util.concurrent.CopyOnWriteArrayList;
116117
import java.util.concurrent.Future;
117-
import java.util.function.Function;
118118
import java.util.function.Supplier;
119119
import java.util.jar.JarEntry;
120120
import java.util.jar.JarFile;
@@ -2661,7 +2661,10 @@ public boolean isActivated() {
26612661
public Map<PluginWrapper, String> getDeprecatedPlugins() {
26622662
return Jenkins.get().getPluginManager().getPlugins().stream()
26632663
.filter(PluginWrapper::isDeprecated)
2664-
.collect(Collectors.toMap(Function.identity(), it -> it.getDeprecations().get(0).url));
2664+
.sorted(Comparator.comparing(PluginWrapper::getDisplayName)) // Sort by plugin name
2665+
.collect(LinkedHashMap::new,
2666+
(map, plugin) -> map.put(plugin, plugin.getDeprecations().get(0).url),
2667+
Map::putAll);
26652668
}
26662669
}
26672670

core/src/main/java/hudson/Util.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1651,7 +1651,7 @@ public static boolean isAbsoluteUri(@NonNull String uri) {
16511651
* @since 2.3 / 1.651.2
16521652
*/
16531653
public static boolean isSafeToRedirectTo(@NonNull String uri) {
1654-
return !isAbsoluteUri(uri) && !uri.startsWith("//");
1654+
return !isAbsoluteUri(uri) && !uri.startsWith("\\") && !uri.replace('\\', '/').startsWith("//");
16551655
}
16561656

16571657
/**

core/src/main/java/hudson/cli/GetNodeCommand.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@
2727
import hudson.Extension;
2828
import hudson.model.Computer;
2929
import hudson.model.Node;
30+
import java.io.ByteArrayOutputStream;
3031
import java.io.IOException;
32+
import java.nio.charset.StandardCharsets;
3133
import jenkins.model.Jenkins;
34+
import jenkins.security.ExtendedReadRedaction;
3235
import org.kohsuke.args4j.Argument;
3336

3437
/**
@@ -52,7 +55,16 @@ protected int run() throws IOException {
5255

5356
node.checkPermission(Computer.EXTENDED_READ);
5457

55-
Jenkins.XSTREAM2.toXMLUTF8(node, stdout);
58+
if (node.hasPermission(Computer.CONFIGURE)) {
59+
Jenkins.XSTREAM2.toXMLUTF8(node, stdout);
60+
} else {
61+
var baos = new ByteArrayOutputStream();
62+
Jenkins.XSTREAM2.toXMLUTF8(node, baos);
63+
String xml = baos.toString(StandardCharsets.UTF_8);
64+
65+
xml = ExtendedReadRedaction.applyAll(xml);
66+
org.apache.commons.io.IOUtils.write(xml, stdout, StandardCharsets.UTF_8);
67+
}
5668

5769
return 0;
5870
}

core/src/main/java/hudson/cli/GetViewCommand.java

+14-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626

2727
import hudson.Extension;
2828
import hudson.model.View;
29+
import java.io.ByteArrayOutputStream;
30+
import java.nio.charset.StandardCharsets;
31+
import jenkins.security.ExtendedReadRedaction;
2932
import org.kohsuke.args4j.Argument;
3033

3134
/**
@@ -48,7 +51,17 @@ public String getShortDescription() {
4851
protected int run() throws Exception {
4952

5053
view.checkPermission(View.READ);
51-
view.writeXml(stdout);
54+
55+
if (view.hasPermission(View.CONFIGURE)) {
56+
view.writeXml(stdout);
57+
} else {
58+
var baos = new ByteArrayOutputStream();
59+
view.writeXml(baos);
60+
String xml = baos.toString(StandardCharsets.UTF_8);
61+
62+
xml = ExtendedReadRedaction.applyAll(xml);
63+
org.apache.commons.io.IOUtils.write(xml, stdout, StandardCharsets.UTF_8);
64+
}
5265

5366
return 0;
5467
}

core/src/main/java/hudson/console/ModelHyperlinkNote.java

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package hudson.console;
22

33
import edu.umd.cs.findbugs.annotations.NonNull;
4+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
45
import hudson.Extension;
56
import hudson.model.Computer;
67
import hudson.model.Item;
@@ -66,6 +67,7 @@ public static String encodeTo(Label label) {
6667
return encodeTo("/" + label.getUrl(), label.getName());
6768
}
6869

70+
@SuppressFBWarnings(value = "HSM_HIDING_METHOD", justification = "TODO needs triage")
6971
public static String encodeTo(String url, String text) {
7072
return HyperlinkNote.encodeTo(url, text, ModelHyperlinkNote::new);
7173
}

core/src/main/java/hudson/model/AutoCompletionCandidates.java

-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
package hudson.model;
2626

2727
import edu.umd.cs.findbugs.annotations.CheckForNull;
28-
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
2928
import hudson.search.Search;
3029
import hudson.search.UserSearchProperty;
3130
import jakarta.servlet.ServletException;
@@ -109,7 +108,6 @@ public static <T extends Item> AutoCompletionCandidates ofJobNames(final Class<T
109108
* The nearby contextual {@link ItemGroup} to resolve relative job names from.
110109
* @since 1.553
111110
*/
112-
@SuppressFBWarnings(value = "SBSC_USE_STRINGBUFFER_CONCATENATION", justification = "no big deal")
113111
public static <T extends Item> AutoCompletionCandidates ofJobNames(final Class<T> type, final String value, ItemGroup container) {
114112
final AutoCompletionCandidates candidates = new AutoCompletionCandidates();
115113
class Visitor extends ItemVisitor {

core/src/main/java/hudson/model/Computer.java

+19-1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
import hudson.util.RemotingDiagnostics.HeapDump;
7575
import hudson.util.RunList;
7676
import jakarta.servlet.ServletException;
77+
import java.io.ByteArrayOutputStream;
7778
import java.io.File;
7879
import java.io.IOException;
7980
import java.io.InputStream;
@@ -83,6 +84,7 @@
8384
import java.net.InetAddress;
8485
import java.net.NetworkInterface;
8586
import java.nio.charset.Charset;
87+
import java.nio.charset.StandardCharsets;
8688
import java.nio.file.Files;
8789
import java.nio.file.InvalidPathException;
8890
import java.nio.file.StandardCopyOption;
@@ -110,6 +112,8 @@
110112
import jenkins.model.IComputer;
111113
import jenkins.model.IDisplayExecutor;
112114
import jenkins.model.Jenkins;
115+
import jenkins.search.SearchGroup;
116+
import jenkins.security.ExtendedReadRedaction;
113117
import jenkins.security.ImpersonatingExecutorService;
114118
import jenkins.security.MasterToSlaveCallable;
115119
import jenkins.security.stapler.StaplerDispatchable;
@@ -1109,6 +1113,11 @@ public String getSearchUrl() {
11091113
return getUrl();
11101114
}
11111115

1116+
@Override
1117+
public SearchGroup getSearchGroup() {
1118+
return SearchGroup.get(SearchGroup.ComputerSearchGroup.class);
1119+
}
1120+
11121121
/**
11131122
* {@link RetentionStrategy} associated with this computer.
11141123
*
@@ -1526,7 +1535,16 @@ public void doConfigDotXml(StaplerRequest2 req, StaplerResponse2 rsp)
15261535
if (node == null) {
15271536
throw HttpResponses.notFound();
15281537
}
1529-
Jenkins.XSTREAM2.toXMLUTF8(node, rsp.getOutputStream());
1538+
if (hasPermission(CONFIGURE)) {
1539+
Jenkins.XSTREAM2.toXMLUTF8(node, rsp.getOutputStream());
1540+
} else {
1541+
var baos = new ByteArrayOutputStream();
1542+
Jenkins.XSTREAM2.toXMLUTF8(node, baos);
1543+
String xml = baos.toString(StandardCharsets.UTF_8);
1544+
1545+
xml = ExtendedReadRedaction.applyAll(xml);
1546+
org.apache.commons.io.IOUtils.write(xml, rsp.getOutputStream(), StandardCharsets.UTF_8);
1547+
}
15301548
return;
15311549
}
15321550
if (req.getMethod().equals("POST")) {

core/src/main/java/hudson/model/FileParameterValue.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ public org.apache.commons.fileupload.FileItem getFile() {
164164
@Override
165165
public BuildWrapper createBuildWrapper(AbstractBuild<?, ?> build) {
166166
return new BuildWrapper() {
167-
@SuppressFBWarnings(value = {"FILE_UPLOAD_FILENAME", "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"}, justification = "TODO needs triage")
167+
@SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "TODO needs triage")
168168
@Override
169169
public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException {
170170
if (location != null && !location.isEmpty() && file.getName() != null && !file.getName().isEmpty()) {

core/src/main/java/hudson/model/Item.java

+6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import java.io.IOException;
4040
import java.util.Collection;
4141
import jenkins.model.Jenkins;
42+
import jenkins.search.SearchGroup;
4243
import jenkins.util.SystemProperties;
4344
import jenkins.util.io.OnMaster;
4445
import org.kohsuke.stapler.StaplerRequest2;
@@ -249,6 +250,11 @@ default void onCreatedFromScratch() {
249250
*/
250251
void delete() throws IOException, InterruptedException;
251252

253+
@Override
254+
default SearchGroup getSearchGroup() {
255+
return SearchGroup.get(SearchGroup.ItemSearchGroup.class);
256+
}
257+
252258
PermissionGroup PERMISSIONS = new PermissionGroup(Item.class, Messages._Item_Permissions_Title());
253259
Permission CREATE =
254260
new Permission(

core/src/main/java/hudson/model/ModifiableItemGroup.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424

2525
package hudson.model;
2626

27+
import hudson.Util;
2728
import io.jenkins.servlet.ServletExceptionWrapper;
2829
import jakarta.servlet.ServletException;
2930
import java.io.IOException;
3031
import jenkins.security.stapler.StaplerNotDispatchable;
31-
import org.kohsuke.stapler.ReflectionUtils;
3232
import org.kohsuke.stapler.StaplerRequest;
3333
import org.kohsuke.stapler.StaplerRequest2;
3434
import org.kohsuke.stapler.StaplerResponse;
@@ -53,7 +53,7 @@ public interface ModifiableItemGroup<T extends Item> extends ItemGroup<T> {
5353
*/
5454
@RequirePOST
5555
default T doCreateItem(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
56-
if (ReflectionUtils.isOverridden(
56+
if (Util.isOverridden(
5757
ModifiableItemGroup.class,
5858
getClass(),
5959
"doCreateItem",
@@ -76,7 +76,7 @@ default T doCreateItem(StaplerRequest2 req, StaplerResponse2 rsp) throws IOExcep
7676
@Deprecated
7777
@StaplerNotDispatchable
7878
default T doCreateItem(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
79-
if (ReflectionUtils.isOverridden(
79+
if (Util.isOverridden(
8080
ModifiableItemGroup.class,
8181
getClass(),
8282
"doCreateItem",

core/src/main/java/hudson/model/UpdateSite.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1088,7 +1088,7 @@ public boolean isRelevant() {
10881088
* {@code false} if it does; and {@code null} when the affected component isn't being offered, or it's a warning
10891089
* for something other than core or a plugin.
10901090
*/
1091-
@SuppressFBWarnings(value = "NP_BOOLEAN_RETURN_NULL")
1091+
@SuppressFBWarnings(value = "NP_BOOLEAN_RETURN_NULL", justification = "TODO needs triage")
10921092
public Boolean isFixable() {
10931093
final Data data = UpdateSite.this.data;
10941094
if (data == null) {

0 commit comments

Comments
 (0)