Skip to content

Commit

Permalink
Merge branch 'master' into JENKINS-73172
Browse files Browse the repository at this point in the history
  • Loading branch information
Dohbedoh committed Oct 10, 2024
2 parents bae68fc + 11ce4fe commit 220550d
Show file tree
Hide file tree
Showing 15 changed files with 714 additions and 127 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/jenkins-security-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Jenkins Security Scan

on:
push:
branches:
- master
pull_request:
types: [ opened, synchronize, reopened ]
workflow_dispatch:

permissions:
security-events: write
contents: read
actions: read

jobs:
security-scan:
uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2
with:
java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate.
# java-version: 21 # Optionally specify what version of Java to set up for the build, or remove to use a recent default.
10 changes: 5 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>4.81</version>
<version>4.88</version>
<relativePath />
</parent>

Expand Down Expand Up @@ -33,7 +33,7 @@
<changelist>999999-SNAPSHOT</changelist>
<gitHubRepo>jenkinsci/${project.artifactId}-plugin</gitHubRepo>
<hpi.compatibleSinceVersion>2.2.0</hpi.compatibleSinceVersion>
<jenkins.version>2.414.3</jenkins.version>
<jenkins.version>2.440.3</jenkins.version>
<useBeta>true</useBeta>
<spotless.check.skip>false</spotless.check.skip>
</properties>
Expand All @@ -42,8 +42,8 @@
<dependencies>
<dependency>
<groupId>io.jenkins.tools.bom</groupId>
<artifactId>bom-2.414.x</artifactId>
<version>2718.v7e8a_d43b_3f0b_</version>
<artifactId>bom-2.440.x</artifactId>
<version>3234.v5ca_5154341ef</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Expand Down Expand Up @@ -107,7 +107,7 @@
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>4.2.1</version>
<version>4.2.2</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ private static class CredentialsTokenProvider extends TokenProvider {
private final GitHubAppCredentials credentials;

CredentialsTokenProvider(GitHubAppCredentials credentials) {
super(credentials.appID, credentials.privateKey.getPlainText());
super(credentials.getAppID(), credentials.getPrivateKey().getPlainText());
this.credentials = credentials;
}

Expand Down Expand Up @@ -284,17 +284,17 @@ private static long getExpirationSeconds(GHAppInstallationToken appInstallationT

@NonNull
String actualApiUri() {
return Util.fixEmpty(apiUri) == null ? "https://api.github.com" : apiUri;
return Util.fixEmpty(getApiUri()) == null ? "https://api.github.com" : getApiUri();
}

private AppInstallationToken getToken(GitHub gitHub) {
synchronized (this) {
try {
if (cachedToken == null || cachedToken.isStale()) {
LOGGER.log(Level.FINE, "Generating App Installation Token for app ID {0}", appID);
LOGGER.log(Level.FINE, "Generating App Installation Token for app ID {0}", getAppID());
cachedToken = generateAppInstallationToken(
gitHub, appID, privateKey.getPlainText(), actualApiUri(), owner);
LOGGER.log(Level.FINER, "Retrieved GitHub App Installation Token for app ID {0}", appID);
gitHub, getAppID(), getPrivateKey().getPlainText(), actualApiUri(), getOwner());
LOGGER.log(Level.FINER, "Retrieved GitHub App Installation Token for app ID {0}", getAppID());
}
} catch (Exception e) {
if (cachedToken != null && !cachedToken.isExpired()) {
Expand All @@ -304,14 +304,14 @@ private AppInstallationToken getToken(GitHub gitHub) {
LOGGER.log(
Level.WARNING,
"Failed to generate new GitHub App Installation Token for app ID "
+ appID
+ getAppID()
+ ": cached token is stale but has not expired",
e);
} else {
throw e;
}
}
LOGGER.log(Level.FINEST, "Returned GitHub App Installation Token for app ID {0}", appID);
LOGGER.log(Level.FINEST, "Returned GitHub App Installation Token for app ID {0}", getAppID());

return cachedToken;
}
Expand All @@ -328,7 +328,7 @@ public Secret getPassword() {
@NonNull
@Override
public String getUsername() {
return appID;
return getAppID();
}

@Override
Expand All @@ -338,9 +338,9 @@ public boolean isUsernameSecret() {

@NonNull
public synchronized GitHubAppCredentials withOwner(@NonNull String owner) {
if (this.owner != null) {
if (!owner.equals(this.owner)) {
throw new IllegalArgumentException("Owner mismatch: " + this.owner + " vs. " + owner);
if (this.getOwner() != null) {
if (!owner.equals(this.getOwner())) {
throw new IllegalArgumentException("Owner mismatch: " + this.getOwner() + " vs. " + owner);
}
return this;
}
Expand All @@ -349,8 +349,8 @@ public synchronized GitHubAppCredentials withOwner(@NonNull String owner) {
}
return byOwner.computeIfAbsent(owner, k -> {
GitHubAppCredentials clone =
new GitHubAppCredentials(getScope(), getId(), getDescription(), appID, privateKey);
clone.apiUri = apiUri;
new GitHubAppCredentials(getScope(), getId(), getDescription(), getAppID(), getPrivateKey());
clone.apiUri = getApiUri();
clone.owner = owner;
return clone;
});
Expand All @@ -359,7 +359,7 @@ public synchronized GitHubAppCredentials withOwner(@NonNull String owner) {
@NonNull
@Override
public Credentials forRun(Run<?, ?> context) {
if (owner != null) {
if (getOwner() != null) {
return this;
}
Job<?, ?> job = context.getParent();
Expand Down Expand Up @@ -523,12 +523,12 @@ private static final class DelegatingGitHubAppCredentials extends BaseStandardCr
DelegatingGitHubAppCredentials(GitHubAppCredentials onMaster) {
super(onMaster.getScope(), onMaster.getId(), onMaster.getDescription());
JenkinsJVM.checkJenkinsJVM();
appID = onMaster.appID;
appID = onMaster.getAppID();
JSONObject j = new JSONObject();
j.put("appID", appID);
j.put("privateKey", onMaster.privateKey.getPlainText());
j.put("privateKey", onMaster.getPrivateKey().getPlainText());
j.put("apiUri", onMaster.actualApiUri());
j.put("owner", onMaster.owner);
j.put("owner", onMaster.getOwner());
tokenRefreshData = Secret.fromString(j.toString()).getEncryptedValue();

// Check token is valid before sending it to the agent.
Expand All @@ -541,7 +541,7 @@ private static final class DelegatingGitHubAppCredentials extends BaseStandardCr
LOGGER.log(
Level.FINEST,
"Checking App Installation Token for app ID {0} before sending to agent",
onMaster.appID);
onMaster.getAppID());
onMaster.getPassword();
} catch (Exception e) {
LOGGER.log(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import hudson.util.ListBoxModel;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.time.Duration;
import java.time.format.DateTimeParseException;
Expand Down Expand Up @@ -99,13 +100,7 @@
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.github.GHMyself;
import org.kohsuke.github.GHOrganization;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GHRepositorySearchBuilder;
import org.kohsuke.github.GHUser;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.HttpException;
import org.kohsuke.github.*;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
Expand Down Expand Up @@ -1048,16 +1043,9 @@ public void visitSources(SCMSourceObserver observer) throws IOException, Interru
"Skipping repository %s because it is archived",
repo.getName())));

} else if (!gitHubSCMNavigatorContext.getTopics().isEmpty()
&& !repo.listTopics().containsAll(gitHubSCMNavigatorContext.getTopics())) {
} else if (!topicMatches(gitHubSCMNavigatorContext, repo, listener.getLogger())) {
// exclude repositories which are missing one or more of the specified topics
witness.record(repo.getName(), false);
listener.getLogger()
.println(GitHubConsoleNote.create(
System.currentTimeMillis(),
String.format(
"Skipping repository %s because it is missing one or more of the following topics: '%s'",
repo.getName(), gitHubSCMNavigatorContext.getTopics())));
} else if (!repo.isPrivate() && gitHubSCMNavigatorContext.isExcludePublicRepositories()) {
witness.record(repo.getName(), false);
listener.getLogger()
Expand Down Expand Up @@ -1137,17 +1125,9 @@ public void visitSources(SCMSourceObserver observer) throws IOException, Interru
System.currentTimeMillis(),
String.format(
"Skipping repository %s because it is archived", repo.getName())));
} else if (!gitHubSCMNavigatorContext.getTopics().isEmpty()
&& !repo.listTopics().containsAll(gitHubSCMNavigatorContext.getTopics())) {
} else if (!topicMatches(gitHubSCMNavigatorContext, repo, listener.getLogger())) {
// exclude repositories which are missing one or more of the specified topics
witness.record(repo.getName(), false);
listener.getLogger()
.println(GitHubConsoleNote.create(
System.currentTimeMillis(),
String.format(
"Skipping repository %s because it is missing one or more of the following topics: '%s'",
repo.getName(), gitHubSCMNavigatorContext.getTopics())));

} else if (!repo.isPrivate() && gitHubSCMNavigatorContext.isExcludePublicRepositories()) {
witness.record(repo.getName(), false);
listener.getLogger()
Expand Down Expand Up @@ -1207,16 +1187,9 @@ public void visitSources(SCMSourceObserver observer) throws IOException, Interru
String.format(
"Skipping repository %s because it is archived", repo.getName())));

} else if (!gitHubSCMNavigatorContext.getTopics().isEmpty()
&& !repo.listTopics().containsAll(gitHubSCMNavigatorContext.getTopics())) {
} else if (!topicMatches(gitHubSCMNavigatorContext, repo, listener.getLogger())) {
// exclude repositories which are missing one or more of the specified topics
witness.record(repo.getName(), false);
listener.getLogger()
.println(GitHubConsoleNote.create(
System.currentTimeMillis(),
String.format(
"Skipping repository %s because it is missing one or more of the following topics: '%s'",
repo.getName(), gitHubSCMNavigatorContext.getTopics())));
} else if (gitHubSCMNavigatorContext.isExcludeForkedRepositories()
&& repo.getSource() != null) {
witness.record(repo.getName(), false);
Expand Down Expand Up @@ -1249,9 +1222,44 @@ public void visitSources(SCMSourceObserver observer) throws IOException, Interru
}
}

private boolean topicMatches(final GitHubSCMNavigatorContext context, final GHRepository repo, PrintStream logger)
throws IOException {
if (context.getTopics().isEmpty()) return true;

final List<String> topics = repo.listTopics();
return context.getTopics().stream().allMatch(topic -> {
if (topic.startsWith("-")) {
boolean contains = topics.contains(topic.substring(1));
if (contains) {
logger.println(GitHubConsoleNote.create(
System.currentTimeMillis(),
String.format(
"Skipping repository %s because it contains excluded topic: '%s'",
repo.getName(), topic)));
return false;
}
return true;
} else {
boolean contains = topics.contains(topic);
if (!contains) {
logger.println(GitHubConsoleNote.create(
System.currentTimeMillis(),
String.format(
"Skipping repository %s because it does not contain topic: '%s'",
repo.getName(), topic)));
return false;
}
return true;
}
});
}

private Iterable<GHRepository> searchRepositories(final GitHub github, final GitHubSCMNavigatorContext context) {
final GHRepositorySearchBuilder ghRepositorySearchBuilder = github.searchRepositories();
context.getTopics().forEach(ghRepositorySearchBuilder::topic);
context.getTopics().forEach(topic -> {
if (topic.startsWith("-")) ghRepositorySearchBuilder.q("-topic:" + topic.substring(1));
else ghRepositorySearchBuilder.topic(topic);
});
ghRepositorySearchBuilder.org(getRepoOwner());
if (!context.isExcludeForkedRepositories()) {
ghRepositorySearchBuilder.q("fork:true");
Expand Down Expand Up @@ -1338,16 +1346,9 @@ public void visitSource(String sourceName, SCMSourceObserver observer) throws IO
"Skipping repository %s because it is archived",
repo.getName())));

} else if (!gitHubSCMNavigatorContext.getTopics().isEmpty()
&& !repo.listTopics().containsAll(gitHubSCMNavigatorContext.getTopics())) {
} else if (!topicMatches(gitHubSCMNavigatorContext, repo, listener.getLogger())) {
// exclude repositories which are missing one or more of the specified topics
witness.record(repo.getName(), false);
listener.getLogger()
.println(GitHubConsoleNote.create(
System.currentTimeMillis(),
String.format(
"Skipping repository %s because it is missing one or more of the following topics: '%s'",
repo.getName(), gitHubSCMNavigatorContext.getTopics())));
} else if (!repo.isPrivate() && gitHubSCMNavigatorContext.isExcludePublicRepositories()) {
witness.record(repo.getName(), false);
listener.getLogger()
Expand Down Expand Up @@ -1406,16 +1407,9 @@ public void visitSource(String sourceName, SCMSourceObserver observer) throws IO
String.format(
"Skipping repository %s because it is archived", repo.getName())));

} else if (!gitHubSCMNavigatorContext.getTopics().isEmpty()
&& !repo.listTopics().containsAll(gitHubSCMNavigatorContext.getTopics())) {
} else if (!topicMatches(gitHubSCMNavigatorContext, repo, listener.getLogger())) {
// exclude repositories which are missing one or more of the specified topics
witness.record(repo.getName(), false);
listener.getLogger()
.println(GitHubConsoleNote.create(
System.currentTimeMillis(),
String.format(
"Skipping repository %s because it is missing one or more of the following topics: '%s'",
repo.getName(), gitHubSCMNavigatorContext.getTopics())));
} else if (StringUtils.isNotBlank(gitHubSCMNavigatorContext.getTeamSlug())
&& !isRepositoryVisibleToTeam(org, repo, gitHubSCMNavigatorContext.getTeamSlug())) {
listener.getLogger()
Expand Down Expand Up @@ -1484,16 +1478,9 @@ public void visitSource(String sourceName, SCMSourceObserver observer) throws IO
String.format(
"Skipping repository %s because it is archived", repo.getName())));

} else if (!gitHubSCMNavigatorContext.getTopics().isEmpty()
&& !repo.listTopics().containsAll(gitHubSCMNavigatorContext.getTopics())) {
} else if (!topicMatches(gitHubSCMNavigatorContext, repo, listener.getLogger())) {
// exclude repositories which are missing one or more of the specified topics
witness.record(repo.getName(), false);
listener.getLogger()
.println(GitHubConsoleNote.create(
System.currentTimeMillis(),
String.format(
"Skipping repository %s because it is missing one or more of the following topics: '%s'",
repo.getName(), gitHubSCMNavigatorContext.getTopics())));
} else if (!repo.isPrivate() && gitHubSCMNavigatorContext.isExcludePublicRepositories()) {
witness.record(repo.getName(), false);
listener.getLogger()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div>
<p>Specify a comma-separated list of <strong>topics</strong> to filter for repositories that have <u>all of them</u>.</p>
</div>
<p>Specify a comma-separated list of <strong>topics</strong> to filter for repositories that have (you can prefix topic with `-` to have it <u>excluded</u>) <u>all of them</u>.</p>
</div>
Loading

0 comments on commit 220550d

Please sign in to comment.