From cb84ed93e695f10d879b8e6a4603ecdee0ff70eb Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 23 Mar 2022 15:58:07 -0400 Subject: [PATCH 1/6] [JENKINS-62220] Automatically select `owner` for `GitHubAppCredentials` acc. to requesting `Run` --- pom.xml | 5 ++ .../GitHubAppCredentials.java | 48 +++++++++++++++++++ .../GitHubAppCredentials/help-owner.html | 5 +- 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5f4fbbe90..42231ddf5 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,11 @@ github 1.34.3 + + org.jenkins-ci.plugins + credentials + 1078.v80a_fc6a_267e1 + org.jenkins-ci.plugins.workflow workflow-support diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java index cade19be3..226dc897e 100644 --- a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java +++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java @@ -2,15 +2,20 @@ import static org.jenkinsci.plugins.github_branch_source.GitHubSCMNavigator.DescriptorImpl.getPossibleApiUriItems; +import com.cloudbees.jenkins.GitHubRepositoryName; +import com.cloudbees.plugins.credentials.Credentials; import com.cloudbees.plugins.credentials.CredentialsScope; import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials; import com.cloudbees.plugins.credentials.impl.BaseStandardCredentials; +import com.coravy.hudson.plugins.github.GithubProjectProperty; import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Extension; import hudson.Functions; import hudson.Util; +import hudson.model.Job; +import hudson.model.Run; import hudson.remoting.Channel; import hudson.util.FormValidation; import hudson.util.ListBoxModel; @@ -20,10 +25,13 @@ import java.security.GeneralSecurityException; import java.time.Duration; import java.time.Instant; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; +import jenkins.scm.api.SCMSource; import jenkins.security.SlaveToMasterCallable; import jenkins.util.JenkinsJVM; import net.sf.json.JSONObject; @@ -77,6 +85,11 @@ public class GitHubAppCredentials extends BaseStandardCredentials private transient AppInstallationToken cachedToken; + /** + * Cache of credentials specialized by {@link #owner}, so that {@link #cachedToken} is preserved. + */ + private transient Map byOwner; + @DataBoundConstructor @SuppressWarnings("unused") // by stapler public GitHubAppCredentials( @@ -310,6 +323,41 @@ public String getUsername() { return appID; } + private synchronized GitHubAppCredentials withOwner(String owner) { + assert this.owner == null; + if (byOwner == null) { + byOwner = new HashMap<>(); + } + return byOwner.computeIfAbsent( + owner, + k -> { + GitHubAppCredentials clone = + new GitHubAppCredentials(getScope(), getId(), getDescription(), appID, privateKey); + clone.apiUri = apiUri; + clone.owner = owner; + return clone; + }); + } + + @NonNull + @Override + public Credentials forRun(Run context) { + if (owner != null) { + return this; + } + Job job = context.getParent(); + SCMSource src = SCMSource.SourceByItem.findSource(job); + if (src instanceof GitHubSCMSource) { + return withOwner(((GitHubSCMSource) src).getRepoOwner()); + } + GitHubRepositoryName ghrn = + GitHubRepositoryName.create(job.getProperty(GithubProjectProperty.class)); + if (ghrn != null) { + return withOwner(ghrn.userName); + } + return this; + } + private AppInstallationToken getCachedToken() { synchronized (this) { return cachedToken; diff --git a/src/main/resources/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials/help-owner.html b/src/main/resources/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials/help-owner.html index 2097e42f0..86a279f3f 100644 --- a/src/main/resources/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials/help-owner.html +++ b/src/main/resources/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials/help-owner.html @@ -1,3 +1,6 @@

- The organisation or user that this app is to be used for. Only required if this app is installed to multiple organisations. + The organisation or user that this app is to be used for. + Only required if this app is installed to multiple organisations. + May be omitted in case credentials are used from GitHub multibranch projects + (in that case the account is determined from the branch source where the credentials are used).

From d016f400fa33c3811fbd5d47b7b91df186ef9065 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 23 Mar 2022 16:22:25 -0400 Subject: [PATCH 2/6] Also apply an `owner` to `lookupScanCredentials` --- .../github_branch_source/Connector.java | 74 +++++++++++++++---- .../GitHubAppCredentials.java | 10 ++- .../GitHubBuildStatusNotification.java | 2 +- .../GitHubSCMFileSystem.java | 2 +- .../GitHubSCMNavigator.java | 15 ++-- .../github_branch_source/GitHubSCMSource.java | 38 +++++----- .../GitHubSCMSource/config-detail.jelly | 2 +- 7 files changed, 102 insertions(+), 41 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/Connector.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/Connector.java index f50b43346..0c402ed8c 100644 --- a/src/main/java/org/jenkinsci/plugins/github_branch_source/Connector.java +++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/Connector.java @@ -150,7 +150,7 @@ public static ListBoxModel listScanCredentials(@CheckForNull Item context, Strin * @param apiUri the api endpoint. * @param scanCredentialsId the credentials ID. * @return the {@link FormValidation} results. - * @deprecated use {@link #checkScanCredentials(Item, String, String)} + * @deprecated use {@link #checkScanCredentials(Item, String, String, String)} */ @Deprecated public static FormValidation checkScanCredentials( @@ -166,9 +166,29 @@ public static FormValidation checkScanCredentials( * @param apiUri the api endpoint. * @param scanCredentialsId the credentials ID. * @return the {@link FormValidation} results. + * @deprecated use {@link #checkScanCredentials(Item, String, String, String)} */ + @Deprecated public static FormValidation checkScanCredentials( @CheckForNull Item context, String apiUri, String scanCredentialsId) { + return checkScanCredentials(context, apiUri, scanCredentialsId, null); + } + + /** + * Checks the credential ID for use as scan credentials in the supplied context against the + * supplied API endpoint. + * + * @param context the context. + * @param apiUri the api endpoint. + * @param scanCredentialsId the credentials ID. + * @param repoOwner the org/user + * @return the {@link FormValidation} results. + */ + public static FormValidation checkScanCredentials( + @CheckForNull Item context, + String apiUri, + String scanCredentialsId, + @CheckForNull String repoOwner) { if (context == null && !Jenkins.get().hasPermission(Jenkins.ADMINISTER) || context != null && !context.hasPermission(Item.EXTENDED_READ)) { return FormValidation.ok(); @@ -192,7 +212,8 @@ public static FormValidation checkScanCredentials( Connector.lookupScanCredentials( context, StringUtils.defaultIfEmpty(apiUri, GitHubServerConfig.GITHUB_URL), - scanCredentialsId); + scanCredentialsId, + repoOwner); if (credentials == null) { return FormValidation.error("Credentials not found"); } else { @@ -239,7 +260,7 @@ public static FormValidation checkScanCredentials( * @param apiUri the API endpoint. * @param scanCredentialsId the credentials to resolve. * @return the {@link StandardCredentials} or {@code null} - * @deprecated use {@link #lookupScanCredentials(Item, String, String)} + * @deprecated use {@link #lookupScanCredentials(Item, String, String, String)} */ @Deprecated @CheckForNull @@ -258,25 +279,52 @@ public static StandardCredentials lookupScanCredentials( * @param apiUri the API endpoint. * @param scanCredentialsId the credentials to resolve. * @return the {@link StandardCredentials} or {@code null} + * @deprecated use {@link #lookupScanCredentials(Item, String, String, String)} */ + @Deprecated @CheckForNull public static StandardCredentials lookupScanCredentials( @CheckForNull Item context, @CheckForNull String apiUri, @CheckForNull String scanCredentialsId) { + return lookupScanCredentials(context, apiUri, scanCredentialsId, null); + } + + /** + * Resolves the specified scan credentials in the specified context for use against the specified + * API endpoint. + * + * @param context the context. + * @param apiUri the API endpoint. + * @param scanCredentialsId the credentials to resolve. + * @param repoOwner the org/user + * @return the {@link StandardCredentials} or {@code null} + */ + @CheckForNull + public static StandardCredentials lookupScanCredentials( + @CheckForNull Item context, + @CheckForNull String apiUri, + @CheckForNull String scanCredentialsId, + @CheckForNull String repoOwner) { if (Util.fixEmpty(scanCredentialsId) == null) { return null; } else { - return CredentialsMatchers.firstOrNull( - CredentialsProvider.lookupCredentials( - StandardUsernameCredentials.class, - context, - context instanceof Queue.Task - ? ((Queue.Task) context).getDefaultAuthentication() - : ACL.SYSTEM, - githubDomainRequirements(apiUri)), - CredentialsMatchers.allOf( - CredentialsMatchers.withId(scanCredentialsId), githubScanCredentialsMatcher())); + StandardCredentials c = + CredentialsMatchers.firstOrNull( + CredentialsProvider.lookupCredentials( + StandardUsernameCredentials.class, + context, + context instanceof Queue.Task + ? ((Queue.Task) context).getDefaultAuthentication() + : ACL.SYSTEM, + githubDomainRequirements(apiUri)), + CredentialsMatchers.allOf( + CredentialsMatchers.withId(scanCredentialsId), githubScanCredentialsMatcher())); + if (c instanceof GitHubAppCredentials && repoOwner != null) { + return ((GitHubAppCredentials) c).withOwner(repoOwner); + } else { + return c; + } } } diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java index 226dc897e..762a60290 100644 --- a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java +++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java @@ -323,8 +323,14 @@ public String getUsername() { return appID; } - private synchronized GitHubAppCredentials withOwner(String owner) { - assert this.owner == null; + @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); + } + return this; + } if (byOwner == null) { byOwner = new HashMap<>(); } diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubBuildStatusNotification.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubBuildStatusNotification.java index f38ab10e9..20600f1df 100644 --- a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubBuildStatusNotification.java +++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubBuildStatusNotification.java @@ -191,7 +191,7 @@ private static GitHub lookUpGitHub(@NonNull Job job) throws IOException { return Connector.connect( source.getApiUri(), Connector.lookupScanCredentials( - job, source.getApiUri(), source.getScanCredentialsId())); + job, source.getApiUri(), source.getScanCredentialsId(), source.getRepoOwner())); } } return null; diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMFileSystem.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMFileSystem.java index 7f37df602..29bf35a43 100644 --- a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMFileSystem.java +++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMFileSystem.java @@ -241,7 +241,7 @@ public SCMFileSystem build( String apiUri = src.getApiUri(); StandardCredentials credentials = Connector.lookupScanCredentials( - (Item) src.getOwner(), apiUri, src.getScanCredentialsId()); + (Item) src.getOwner(), apiUri, src.getScanCredentialsId(), src.getRepoOwner()); // Github client and validation GitHub github = Connector.connect(apiUri, credentials); diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMNavigator.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMNavigator.java index 06440c3db..22254c9d0 100644 --- a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMNavigator.java +++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMNavigator.java @@ -934,7 +934,8 @@ public void visitSources(SCMSourceObserver observer) throws IOException, Interru } StandardCredentials credentials = - Connector.lookupScanCredentials((Item) observer.getContext(), apiUri, credentialsId); + Connector.lookupScanCredentials( + (Item) observer.getContext(), apiUri, credentialsId, repoOwner); // Github client and validation GitHub github = Connector.connect(apiUri, credentials); @@ -1261,7 +1262,8 @@ public void visitSource(String sourceName, SCMSourceObserver observer) } StandardCredentials credentials = - Connector.lookupScanCredentials((Item) observer.getContext(), apiUri, credentialsId); + Connector.lookupScanCredentials( + (Item) observer.getContext(), apiUri, credentialsId, repoOwner); // Github client and validation GitHub github; @@ -1575,7 +1577,7 @@ public List retrieveActions( listener.getLogger().printf("Looking up details of %s...%n", getRepoOwner()); List result = new ArrayList<>(); StandardCredentials credentials = - Connector.lookupScanCredentials((Item) owner, getApiUri(), credentialsId); + Connector.lookupScanCredentials((Item) owner, getApiUri(), credentialsId, repoOwner); GitHub hub = Connector.connect(getApiUri(), credentials); try { Connector.configureLocalRateLimitChecker(listener, hub); @@ -1607,7 +1609,7 @@ public void afterSave(@NonNull SCMNavigatorOwner owner) { try { // FIXME MINOR HACK ALERT StandardCredentials credentials = - Connector.lookupScanCredentials((Item) owner, getApiUri(), credentialsId); + Connector.lookupScanCredentials((Item) owner, getApiUri(), credentialsId, repoOwner); GitHub hub = Connector.connect(getApiUri(), credentials); try { GitHubOrgWebHook.register(hub, repoOwner); @@ -1733,8 +1735,9 @@ protected SCMSourceCategory[] createCategories() { public FormValidation doCheckCredentialsId( @CheckForNull @AncestorInPath Item context, @QueryParameter String apiUri, - @QueryParameter String credentialsId) { - return Connector.checkScanCredentials(context, apiUri, credentialsId); + @QueryParameter String credentialsId, + @QueryParameter String repoOwner) { + return Connector.checkScanCredentials(context, apiUri, credentialsId, repoOwner); } /** diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java index 90447deb6..d4fa4975c 100644 --- a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java +++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java @@ -986,7 +986,7 @@ protected final void retrieve( @NonNull final TaskListener listener) throws IOException, InterruptedException { StandardCredentials credentials = - Connector.lookupScanCredentials((Item) getOwner(), apiUri, credentialsId); + Connector.lookupScanCredentials((Item) getOwner(), apiUri, credentialsId, repoOwner); // Github client and validation final GitHub github = Connector.connect(apiUri, credentials); try { @@ -1296,7 +1296,7 @@ public SCMRevision create(@NonNull PullRequestSCMHead head, @Nullable Void ignor protected Set retrieveRevisions(@NonNull TaskListener listener, Item retrieveContext) throws IOException, InterruptedException { StandardCredentials credentials = - Connector.lookupScanCredentials(retrieveContext, apiUri, credentialsId); + Connector.lookupScanCredentials(retrieveContext, apiUri, credentialsId, repoOwner); // Github client and validation final GitHub github = Connector.connect(apiUri, credentials); try { @@ -1406,7 +1406,7 @@ protected SCMRevision retrieve( @NonNull String headName, @NonNull TaskListener listener, Item retrieveContext) throws IOException, InterruptedException { StandardCredentials credentials = - Connector.lookupScanCredentials(retrieveContext, apiUri, credentialsId); + Connector.lookupScanCredentials(retrieveContext, apiUri, credentialsId, repoOwner); // Github client and validation final GitHub github = Connector.connect(apiUri, credentials); try { @@ -1654,7 +1654,7 @@ public void unwrap() throws IOException, InterruptedException { protected SCMProbe createProbe(@NonNull SCMHead head, @CheckForNull final SCMRevision revision) throws IOException { StandardCredentials credentials = - Connector.lookupScanCredentials((Item) getOwner(), apiUri, credentialsId); + Connector.lookupScanCredentials((Item) getOwner(), apiUri, credentialsId, repoOwner); // Github client and validation GitHub github = Connector.connect(apiUri, credentials); try { @@ -1673,7 +1673,7 @@ protected SCMProbe createProbe(@NonNull SCMHead head, @CheckForNull final SCMRev protected SCMRevision retrieve(SCMHead head, TaskListener listener) throws IOException, InterruptedException { StandardCredentials credentials = - Connector.lookupScanCredentials((Item) getOwner(), apiUri, credentialsId); + Connector.lookupScanCredentials((Item) getOwner(), apiUri, credentialsId, repoOwner); // Github client and validation GitHub github = Connector.connect(apiUri, credentials); @@ -1825,7 +1825,7 @@ PullRequestSource retrievePullRequestSource(int number) { String fullName = repoOwner + "/" + repository; LOGGER.log(Level.INFO, "Getting remote pull requests from {0}", fullName); StandardCredentials credentials = - Connector.lookupScanCredentials((Item) getOwner(), apiUri, credentialsId); + Connector.lookupScanCredentials((Item) getOwner(), apiUri, credentialsId, repoOwner); LogTaskListener listener = new LogTaskListener(LOGGER, Level.INFO); try { GitHub github = Connector.connect(apiUri, credentials); @@ -1995,7 +1995,7 @@ protected List retrieveActions( String repository = this.repository; StandardCredentials credentials = - Connector.lookupScanCredentials((Item) getOwner(), apiUri, credentialsId); + Connector.lookupScanCredentials((Item) getOwner(), apiUri, credentialsId, repoOwner); GitHub hub = Connector.connect(apiUri, credentials); try { Connector.checkConnectionValidity(apiUri, listener, credentials, hub); @@ -2129,8 +2129,9 @@ public ListBoxModel doFillCredentialsIdItems( public FormValidation doCheckCredentialsId( @CheckForNull @AncestorInPath Item context, @QueryParameter String apiUri, + @QueryParameter String repoOwner, @QueryParameter String value) { - return Connector.checkScanCredentials(context, apiUri, value); + return Connector.checkScanCredentials(context, apiUri, value, repoOwner); } @RequirePOST @@ -2138,7 +2139,8 @@ public FormValidation doCheckCredentialsId( public FormValidation doValidateRepositoryUrlAndCredentials( @CheckForNull @AncestorInPath Item context, @QueryParameter String repositoryUrl, - @QueryParameter String credentialsId) { + @QueryParameter String credentialsId, + @QueryParameter String repoOwner) { if (context == null && !Jenkins.get().hasPermission(Jenkins.ADMINISTER) || context != null && !context.hasPermission(Item.EXTENDED_READ)) { return FormValidation.error( @@ -2158,7 +2160,7 @@ public FormValidation doValidateRepositoryUrlAndCredentials( } StandardCredentials credentials = - Connector.lookupScanCredentials(context, info.getApiUri(), credentialsId); + Connector.lookupScanCredentials(context, info.getApiUri(), credentialsId, repoOwner); StringBuilder sb = new StringBuilder(); try { GitHub github = Connector.connect(info.getApiUri(), credentials); @@ -2197,8 +2199,9 @@ public FormValidation doCheckIncludes(@QueryParameter String value) { public FormValidation doCheckScanCredentialsId( @CheckForNull @AncestorInPath Item context, @QueryParameter String apiUri, - @QueryParameter String scanCredentialsId) { - return doCheckCredentialsId(context, apiUri, scanCredentialsId); + @QueryParameter String scanCredentialsId, + @QueryParameter String repoOwner) { + return doCheckCredentialsId(context, apiUri, scanCredentialsId, repoOwner); } @Restricted(NoExternalUse.class) @@ -2282,7 +2285,8 @@ public boolean isApiUriSelectable() { public ListBoxModel doFillOrganizationItems( @CheckForNull @AncestorInPath Item context, @QueryParameter String apiUri, - @QueryParameter String credentialsId) + @QueryParameter String credentialsId, + @QueryParameter String repoOwner) throws IOException { if (credentialsId == null) { return new ListBoxModel(); @@ -2296,7 +2300,7 @@ public ListBoxModel doFillOrganizationItems( } try { StandardCredentials credentials = - Connector.lookupScanCredentials(context, apiUri, credentialsId); + Connector.lookupScanCredentials(context, apiUri, credentialsId, repoOwner); GitHub github = Connector.connect(apiUri, credentials); try { if (!github.isAnonymous()) { @@ -2344,7 +2348,7 @@ public ListBoxModel doFillRepositoryItems( } try { StandardCredentials credentials = - Connector.lookupScanCredentials(context, apiUri, credentialsId); + Connector.lookupScanCredentials(context, apiUri, credentialsId, repoOwner); GitHub github = Connector.connect(apiUri, credentials); try { @@ -2918,7 +2922,7 @@ protected Set create() { "Connecting to %s to obtain list of collaborators for %s/%s%n", apiUri, repoOwner, repository); StandardCredentials credentials = - Connector.lookupScanCredentials((Item) getOwner(), apiUri, credentialsId); + Connector.lookupScanCredentials((Item) getOwner(), apiUri, credentialsId, repoOwner); // Github client and validation try { GitHub github = Connector.connect(apiUri, credentials); @@ -2986,7 +2990,7 @@ public GHPermissionType fetch(String username) throws IOException, InterruptedEx "Connecting to %s to check permissions of obtain list of %s for %s/%s%n", apiUri, username, repoOwner, repository); StandardCredentials credentials = - Connector.lookupScanCredentials((Item) getOwner(), apiUri, credentialsId); + Connector.lookupScanCredentials((Item) getOwner(), apiUri, credentialsId, repoOwner); github = Connector.connect(apiUri, credentials); String fullName = repoOwner + "/" + repository; repo = github.getRepository(fullName); diff --git a/src/main/resources/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource/config-detail.jelly b/src/main/resources/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource/config-detail.jelly index ad84a0a01..5af7baa48 100644 --- a/src/main/resources/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource/config-detail.jelly +++ b/src/main/resources/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource/config-detail.jelly @@ -17,7 +17,7 @@ - + From 2273f86fa5990f3e0657189cfb6335f7bf248901 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 23 Mar 2022 16:25:23 -0400 Subject: [PATCH 3/6] Need to update POM, BOM to accommodate new `credentials` dep --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 42231ddf5..630868448 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 4.29 + 4.38 github-branch-source @@ -123,7 +123,7 @@ io.jenkins.tools.bom bom-2.289.x - 1090.v0a_33df40457a_ + 1210.vcd41f6657f03 import pom From b1baf5f0734563835b7a66c1507388e99ff5d2ad Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 23 Mar 2022 17:44:00 -0400 Subject: [PATCH 4/6] SpotBugs --- .../plugins/github_branch_source/GitHubAppCredentials.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java index 762a60290..7fadf8f92 100644 --- a/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java +++ b/src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubAppCredentials.java @@ -81,6 +81,9 @@ public class GitHubAppCredentials extends BaseStandardCredentials private String apiUri; + @SuppressFBWarnings( + value = "IS2_INCONSISTENT_SYNC", + justification = "#withOwner locking only for #byOwner") private String owner; private transient AppInstallationToken cachedToken; From 84d12a2a151b7321b96d92e3fbcd3ec3867afe72 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 24 Mar 2022 08:22:09 -0400 Subject: [PATCH 5/6] `GithubAppCredentialsAppInstallationTokenTest` from #326 was flaking; use `closeTo` for actual times --- ...ppCredentialsAppInstallationTokenTest.java | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/github_branch_source/GithubAppCredentialsAppInstallationTokenTest.java b/src/test/java/org/jenkinsci/plugins/github_branch_source/GithubAppCredentialsAppInstallationTokenTest.java index 814b738dc..a58cb6890 100644 --- a/src/test/java/org/jenkinsci/plugins/github_branch_source/GithubAppCredentialsAppInstallationTokenTest.java +++ b/src/test/java/org/jenkinsci/plugins/github_branch_source/GithubAppCredentialsAppInstallationTokenTest.java @@ -1,11 +1,16 @@ package org.jenkinsci.plugins.github_branch_source; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.is; import hudson.util.Secret; +import java.math.BigDecimal; import java.time.Duration; import java.time.Instant; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; +import org.hamcrest.number.BigDecimalCloseTo; import org.junit.Test; public class GithubAppCredentialsAppInstallationTokenTest { @@ -22,7 +27,7 @@ public void testAppInstallationTokenStale() throws Exception { assertThat(token.isStale(), is(false)); assertThat( token.getTokenStaleEpochSeconds(), - equalTo(now + GitHubAppCredentials.AppInstallationToken.NOT_STALE_MINIMUM_SECONDS)); + closeTo(now + GitHubAppCredentials.AppInstallationToken.NOT_STALE_MINIMUM_SECONDS, 3)); now = Instant.now().getEpochSecond(); token = @@ -31,7 +36,7 @@ public void testAppInstallationTokenStale() throws Exception { assertThat(token.isStale(), is(false)); assertThat( token.getTokenStaleEpochSeconds(), - equalTo(now + GitHubAppCredentials.AppInstallationToken.NOT_STALE_MINIMUM_SECONDS)); + closeTo(now + GitHubAppCredentials.AppInstallationToken.NOT_STALE_MINIMUM_SECONDS, 3)); now = Instant.now().getEpochSecond(); token = @@ -41,7 +46,7 @@ public void testAppInstallationTokenStale() throws Exception { assertThat(token.isStale(), is(false)); assertThat( token.getTokenStaleEpochSeconds(), - equalTo(now + GitHubAppCredentials.AppInstallationToken.NOT_STALE_MINIMUM_SECONDS)); + closeTo(now + GitHubAppCredentials.AppInstallationToken.NOT_STALE_MINIMUM_SECONDS, 3)); now = Instant.now().getEpochSecond(); token = @@ -52,7 +57,7 @@ public void testAppInstallationTokenStale() throws Exception { + Duration.ofMinutes(7).getSeconds()); assertThat(token.isStale(), is(false)); assertThat( - token.getTokenStaleEpochSeconds(), equalTo(now + Duration.ofMinutes(7).getSeconds())); + token.getTokenStaleEpochSeconds(), closeTo(now + Duration.ofMinutes(7).getSeconds(), 3)); now = Instant.now().getEpochSecond(); token = @@ -61,8 +66,9 @@ public void testAppInstallationTokenStale() throws Exception { assertThat(token.isStale(), is(false)); assertThat( token.getTokenStaleEpochSeconds(), - equalTo(now + GitHubAppCredentials.AppInstallationToken.STALE_AFTER_SECONDS + 1)); + closeTo(now + GitHubAppCredentials.AppInstallationToken.STALE_AFTER_SECONDS + 1, 3)); + // TODO use FlagRule long notStaleSeconds = GitHubAppCredentials.AppInstallationToken.NOT_STALE_MINIMUM_SECONDS; try { // Should revert to 1 second minimum @@ -71,7 +77,7 @@ public void testAppInstallationTokenStale() throws Exception { now = Instant.now().getEpochSecond(); token = new GitHubAppCredentials.AppInstallationToken(secret, now); assertThat(token.isStale(), is(false)); - assertThat(token.getTokenStaleEpochSeconds(), equalTo(now + 1)); + assertThat(token.getTokenStaleEpochSeconds(), closeTo(now + 1, 3)); // Verify goes stale Thread.sleep(1000); @@ -80,4 +86,25 @@ public void testAppInstallationTokenStale() throws Exception { GitHubAppCredentials.AppInstallationToken.NOT_STALE_MINIMUM_SECONDS = notStaleSeconds; } } + + private static Matcher closeTo(long operand, long error) { + BigDecimalCloseTo delegate = + new BigDecimalCloseTo(new BigDecimal(operand), new BigDecimal(error)); + return new TypeSafeMatcher(Long.class) { + @Override + protected boolean matchesSafely(Long item) { + return delegate.matches(new BigDecimal(item)); + } + + @Override + protected void describeMismatchSafely(Long item, Description mismatchDescription) { + delegate.describeMismatchSafely(new BigDecimal(item), mismatchDescription); + } + + @Override + public void describeTo(Description description) { + delegate.describeTo(description); + } + }; + } } From 5030dcd1a0b37a65cc8dfc50c0da2c71ed492ace Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Sat, 26 Mar 2022 13:07:40 -0400 Subject: [PATCH 6/6] https://github.com/jenkinsci/credentials-plugin/pull/293 released --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 630868448..ac7d28795 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ org.jenkins-ci.plugins credentials - 1078.v80a_fc6a_267e1 + 1087.v16065d268466 org.jenkins-ci.plugins.workflow