Skip to content

Commit

Permalink
Merge branch 'master' into JENKINS-73404
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkEWaite committed Jul 19, 2024
2 parents a3e4648 + 9e629f6 commit cbed629
Show file tree
Hide file tree
Showing 88 changed files with 2,466 additions and 590 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/publish-release-artifact.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ jobs:
wget -q https://get.jenkins.io/${REPO}/${PROJECT_VERSION}/${FILE_NAME}
- name: Upload Release Asset
id: upload-war
uses: softprops/action-gh-release@a74c6b72af54cfa997e81df42d94703d6313a2d0
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
Expand Down Expand Up @@ -108,7 +108,7 @@ jobs:
- name: Upload Release Asset
id: upload-deb
if: always()
uses: softprops/action-gh-release@a74c6b72af54cfa997e81df42d94703d6313a2d0
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
Expand Down Expand Up @@ -144,7 +144,7 @@ jobs:
- name: Upload Release Asset
id: upload-rpm
if: always()
uses: softprops/action-gh-release@a74c6b72af54cfa997e81df42d94703d6313a2d0
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
Expand Down Expand Up @@ -180,7 +180,7 @@ jobs:
- name: Upload Release Asset
id: upload-msi
if: always()
uses: softprops/action-gh-release@a74c6b72af54cfa997e81df42d94703d6313a2d0
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
Expand Down Expand Up @@ -216,7 +216,7 @@ jobs:
- name: Upload Release Asset
id: upload-suse-rpm
if: always()
uses: softprops/action-gh-release@a74c6b72af54cfa997e81df42d94703d6313a2d0
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
Expand Down
2 changes: 1 addition & 1 deletion ath.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ set -o xtrace
cd "$(dirname "$0")"

# https://github.com/jenkinsci/acceptance-test-harness/releases
export ATH_VERSION=5883.vdea_99c1762a_d
export ATH_VERSION=5895.v44475b_ca_0c78

if [[ $# -eq 0 ]]; then
export JDK=17
Expand Down
2 changes: 1 addition & 1 deletion bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ THE SOFTWARE.
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.17.0</version>
<version>1.17.1</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/ClassicPluginStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ private void fix(Attributes atts, List<PluginWrapper.Dependency> optionalDepende

for (Dependency d : DetachedPluginsUtil.getImpliedDependencies(pluginName, jenkinsVersion)) {
LOGGER.fine(() -> "implied dep " + pluginName + " → " + d.shortName);
pluginManager.considerDetachedPlugin(d.shortName);
pluginManager.considerDetachedPlugin(d.shortName, pluginName);
optionalDependencies.add(d);
}
}
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/hudson/PluginManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ public void run(Reactor reactor) throws Exception {
}});
}

void considerDetachedPlugin(String shortName) {
void considerDetachedPlugin(String shortName, String source) {
if (new File(rootDir, shortName + ".jpi").isFile() ||
new File(rootDir, shortName + ".hpi").isFile() ||
new File(rootDir, shortName + ".jpl").isFile() ||
Expand All @@ -627,7 +627,7 @@ void considerDetachedPlugin(String shortName) {
for (String loadedFile : loadPluginsFromWar(getDetachedLocation(), (dir, name) -> normalisePluginName(name).equals(shortName))) {
String loaded = normalisePluginName(loadedFile);
File arc = new File(rootDir, loaded + ".jpi");
LOGGER.info(() -> "Loading a detached plugin as a dependency: " + arc);
LOGGER.info(() -> "Loading a detached plugin " + arc + " as a dependency of " + source);
try {
plugins.add(strategy.createPluginWrapper(arc));
} catch (IOException e) {
Expand Down
45 changes: 43 additions & 2 deletions core/src/main/java/hudson/model/AdministrativeMonitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -183,14 +183,18 @@ public void doDisable(StaplerRequest req, StaplerResponse rsp) throws IOExceptio

/**
* Required permission to view this admin monitor.
* By default {@link Jenkins#ADMINISTER}, but {@link Jenkins#SYSTEM_READ} is also supported.
* By default {@link Jenkins#ADMINISTER}, but {@link Jenkins#SYSTEM_READ} or {@link Jenkins#MANAGE} are also supported.
* <p>
* Changing this permission check to return {@link Jenkins#SYSTEM_READ} will make the active
* administrative monitor appear on {@code manage.jelly} and on the globally visible
* {@link jenkins.management.AdministrativeMonitorsDecorator} to users without Administer permission.
* {@link #doDisable(StaplerRequest, StaplerResponse)} will still always require Administer permission.
* </p>
* <p>
* This method only allows for a single permission to be returned. If more complex permission checks are required,
* override {@link #checkRequiredPermission()} and {@link #hasRequiredPermission()} instead.
* </p>
* <p>
* Implementers need to ensure that {@code doAct} and other web methods perform necessary permission checks:
* Users with System Read permissions are expected to be limited to read-only access.
* Form UI elements that change system state, e.g. toggling a feature on or off, need to be hidden from users
Expand All @@ -201,13 +205,50 @@ public Permission getRequiredPermission() {
return Jenkins.ADMINISTER;
}

/**
* Checks if the current user has the minimum required permission to view this administrative monitor.
* <p>
* Subclasses may override this method and {@link #hasRequiredPermission()} instead of {@link #getRequiredPermission()} to perform more complex permission checks,
* for example, checking either {@link Jenkins#MANAGE} or {@link Jenkins#SYSTEM_READ}.
* </p>
* @see #getRequiredPermission()
* @see #hasRequiredPermission()
*/
public void checkRequiredPermission() {
Jenkins.get().checkPermission(getRequiredPermission());
}

/**
* Checks if the current user has the minimum required permission to view this administrative monitor.
* <p>
* Subclasses may override this method and {@link #checkRequiredPermission} instead of {@link #getRequiredPermission()} to perform more complex permission checks,
* for example, checking either {@link Jenkins#MANAGE} or {@link Jenkins#SYSTEM_READ}.
* </p>
* @see #getRequiredPermission()
* @see #checkRequiredPermission()
*/
public boolean hasRequiredPermission() {
return Jenkins.get().hasPermission(getRequiredPermission());
}

/**
* Checks if the current user has the minimum required permission to view any administrative monitor.
*
* @return true if the current user has the minimum required permission to view any administrative monitor.
*
* @since TODO
*/
public static boolean hasPermissionToDisplay() {
return Jenkins.get().hasAnyPermission(Jenkins.SYSTEM_READ, Jenkins.MANAGE);
}

/**
* Ensure that URLs in this administrative monitor are only accessible to users with {@link #getRequiredPermission()}.
*/
@Override
@Restricted(NoExternalUse.class)
public Object getTarget() {
Jenkins.get().checkPermission(getRequiredPermission());
checkRequiredPermission();
return this;
}

Expand Down
6 changes: 6 additions & 0 deletions core/src/main/java/hudson/model/MyViewsProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import hudson.Extension;
import hudson.Util;
import hudson.model.Descriptor.FormException;
import hudson.model.userproperty.UserPropertyCategory;
import hudson.security.ACL;
import hudson.util.FormValidation;
import hudson.views.MyViewsTabBar;
Expand Down Expand Up @@ -246,6 +247,11 @@ public String getDisplayName() {
public UserProperty newInstance(User user) {
return new MyViewsProperty();
}

@Override
public @NonNull UserPropertyCategory getUserPropertyCategory() {
return UserPropertyCategory.get(UserPropertyCategory.Preferences.class);
}
}

@Override
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/java/hudson/model/PaneStatusProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import static java.lang.String.format;

import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Extension;
import hudson.model.userproperty.UserPropertyCategory;
import hudson.util.PersistedList;
import java.io.IOException;
import javax.servlet.http.HttpSession;
Expand Down Expand Up @@ -56,6 +58,10 @@ public boolean isEnabled() {
return false;
}

@Override
public @NonNull UserPropertyCategory getUserPropertyCategory() {
return UserPropertyCategory.get(UserPropertyCategory.Invisible.class);
}
}

private static class PaneStatusPropertiesSessionFallback extends PaneStatusProperties {
Expand Down
5 changes: 5 additions & 0 deletions core/src/main/java/hudson/model/TimeZoneProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Extension;
import hudson.Util;
import hudson.model.userproperty.UserPropertyCategory;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
import hudson.util.ListBoxModel.Option;
Expand Down Expand Up @@ -106,6 +107,10 @@ public FormValidation doCheckTimeZoneName(@QueryParameter String timeZoneName) {
}
}

@Override
public @NonNull UserPropertyCategory getUserPropertyCategory() {
return UserPropertyCategory.get(UserPropertyCategory.Account.class);
}
}

@CheckForNull
Expand Down
25 changes: 18 additions & 7 deletions core/src/main/java/hudson/model/UpdateCenter.java
Original file line number Diff line number Diff line change
Expand Up @@ -1322,6 +1322,10 @@ public File download(DownloadJob job, URL src) throws IOException {
sha512 != null ? new DigestOutputStream(_out, sha512) : _out, sha256) : _out, sha1) : _out;
InputStream in = con.getInputStream();
CountingInputStream cin = new CountingInputStream(in)) {
if (LOGGER.isLoggable(Level.FINE)) {
var sourceUrlString = getSourceUrl(src, con);
LOGGER.fine(() -> "Downloading " + job.getName() + " from " + sourceUrlString);
}
while ((len = cin.read(buf)) >= 0) {
out.write(buf, 0, len);
final int count = cin.getCount();
Expand Down Expand Up @@ -1358,15 +1362,22 @@ public File download(DownloadJob job, URL src) throws IOException {
return tmp;
} catch (IOException e) {
// assist troubleshooting in case of e.g. "too many redirects" by printing actual URL
String extraMessage = "";
if (con != null && con.getURL() != null && !src.toString().equals(con.getURL().toString())) {
// Two URLs are considered equal if different hosts resolve to same IP. Prefer to log in case of string inequality,
// because who knows how the server responds to different host name in the request header?
// Also, since it involved name resolution, it'd be an expensive operation.
extraMessage = " (redirected to: " + con.getURL() + ")";
throw new IOException("Failed to download from " + getSourceUrl(src, con), e);
}
}

private static String getSourceUrl(@NonNull URL src, @CheckForNull URLConnection connection) {
var sourceUrlString = src.toExternalForm();
if (connection != null) {
var connectionURL = connection.getURL();
if (connectionURL != null) {
var finalUrlString = connectionURL.toExternalForm();
if (!sourceUrlString.equals(finalUrlString)) {
return sourceUrlString + " → " + finalUrlString;
}
}
throw new IOException("Failed to download from " + src + extraMessage, e);
}
return sourceUrlString;
}

/**
Expand Down
69 changes: 23 additions & 46 deletions core/src/main/java/hudson/model/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,11 @@
import hudson.XmlFile;
import hudson.init.InitMilestone;
import hudson.init.Initializer;
import hudson.model.Descriptor.FormException;
import hudson.model.listeners.SaveableListener;
import hudson.security.ACL;
import hudson.security.AccessControlled;
import hudson.security.SecurityRealm;
import hudson.security.UserMayOrMayNotExistException2;
import hudson.util.FormApply;
import hudson.util.FormValidation;
import hudson.util.RunList;
import hudson.util.XStream2;
Expand Down Expand Up @@ -77,7 +75,6 @@
import jenkins.security.LastGrantedAuthoritiesProperty;
import jenkins.security.UserDetailsCache;
import jenkins.util.SystemProperties;
import net.sf.json.JSONObject;
import org.jenkinsci.Symbol;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
Expand All @@ -87,7 +84,6 @@
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;
import org.kohsuke.stapler.interceptor.RequirePOST;
import org.kohsuke.stapler.verb.POST;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
Expand Down Expand Up @@ -342,6 +338,29 @@ public synchronized void addProperty(@NonNull UserProperty p) throws IOException
save();
}

/**
* Expand {@link #addProperty(UserProperty)} for multiple properties to be done at once.
* Expected to be used by the categorized configuration pages to update part of the properties.
* The properties not included in the list will be let untouched.
* It will call the {@link UserProperty#setUser(User)} method and at the end, {@link #save()} once.
*
* @since TODO
*/
public synchronized void addProperties(@NonNull List<UserProperty> multipleProperties) throws IOException {
List<UserProperty> newProperties = new ArrayList<>(this.properties);
for (UserProperty property : multipleProperties) {
UserProperty oldProp = getProperty(property.getClass());
if (oldProp != null) {
newProperties.remove(oldProp);
}
newProperties.add(property);
property.setUser(this);
}

this.properties = newProperties;
this.save();
}

/**
* List of all {@link UserProperty}s exposed primarily for the remoting API.
*/
Expand Down Expand Up @@ -859,48 +878,6 @@ public Api getApi() {
return new Api(this);
}

/**
* Accepts submission from the configuration page.
*/
@POST
public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
checkPermission(Jenkins.ADMINISTER);

JSONObject json = req.getSubmittedForm();
String oldFullName = this.fullName;
fullName = json.getString("fullName");
description = json.getString("description");

List<UserProperty> props = new ArrayList<>();
int i = 0;
for (UserPropertyDescriptor d : UserProperty.all()) {
UserProperty p = getProperty(d.clazz);

JSONObject o = json.optJSONObject("userProperty" + i++);
if (o != null) {
if (p != null) {
p = p.reconfigure(req, o);
} else {
p = d.newInstance(req, o);
}
}

if (p != null) {
p.setUser(this);
props.add(p);
}
}
this.properties = props;

save();

if (oldFullName != null && !oldFullName.equals(this.fullName)) {
UserDetailsCache.get().invalidate(oldFullName);
}

FormApply.success(".").generateResponse(req, rsp, this);
}

/**
* Deletes this user from Hudson.
*/
Expand Down
Loading

0 comments on commit cbed629

Please sign in to comment.