Skip to content

Conversation

dwnusbaum
Copy link
Member

@dwnusbaum dwnusbaum commented Dec 20, 2024

Description

See JENKINS-75058. See also jenkins-infra/jenkins.io#7770 for greater context around this change. For now this is a draft PR. I will go through the PR and add review comments to help clarify things.

This PR adds new configuration options to GitHub App credentials that make use of the repositories and permissions parameters when using the /app/installations/{installation_id}/access_tokens GitHub API endpoint to create installation access tokens.

There are two new high-level options:

  • The "Repository access strategy" uses the repositories parameter to control which repositories are available to the installation access tokens. There are three strategies, please see the changes to docs/github-app.adoc and the corresponding help-*.html for details.
  • The "Default permissions strategy" uses the permissions parameter to control which permissions are available to the installation access tokens, but only when the tokens are generated and used in an untrusted context. There are three strategies, please see the changes to docs/github-app.adoc for details.

If you have any recommendations for renaming of these options or any of their sub-options, please feel free to suggest them.

I will go through and add comments to the PR to various points of interest. Please feel free to ask about anything that is not clear.

Backwards compatibility:

  • The new configuration options are not fully backwards compatible. When migrating existing credentials which do not have the owner field set, we can 1) either preserve compatibility for users who have the app installed in multiple orgs and only use the credentials in contexts where owner inference is supported by using AccessInferredOwner as the migration, or 2) we can preserve compatibility for users who have the app installed in a single org and use it in contexts where inference is not supported by using AccessSpecifiedRepositories with a null owner. None of the new strategies currnetly support these two use cases simultaneously.

Notes for downstream plugins:

Submitter checklist

  • Link to JIRA ticket in description, if appropriate.
  • Change is code complete and matches issue description
  • Automated tests have been added to exercise the changes
  • Reviewer's manual test instructions provided in PR description. See Reviewer's first task below.

Reviewer checklist

  • Run the changes and verify that the change matches the issue description
  • Reviewed the code
  • Verified that the appropriate tests have been written or valid explanation given

Documentation changes

  • Link to jenkins.io PR, or an explanation for why no doc changes are needed

Users/aliases to notify

…ns of the repositories and permissions available to installation access tokens in some contexts

Co-authored-by: Jérôme Pochat <[email protected]>
*/
private transient Map<String, GitHubAppCredentials> byOwner;
private transient Map<GitHubAppUsageContext, GitHubAppCredentials> cachedCredentials = new ConcurrentHashMap<>();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still dynamically create different credentials for each context, but now the contexts are more complicated.

Comment on lines +168 to +169
// This method is not deprecated or restricted only to preserve compatibility with existing CasC YAML files.
/** Do not call this method, use {@link #setRepositoryAccessStrategy} instead. */
Copy link
Member Author

@dwnusbaum dwnusbaum Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, we could mark this method @Deprecated, in which case all CasC users that configure GitHub App credentials would have to edit their YAML scripts when applying this plugin update to avoid startup failures. I do not know what approach is generally preferred when making significant configuration changes, so I went for trying to preserve CasC compatibility for now.

We do probably want to keep the method around though so that we do not need to do coordinated releases of plugins that currently call this method, which are mentioned in the PR description.

Comment on lines +323 to +332
GHAppCreateTokenBuilder builder = appInstallation.createToken();
if (!repositories.isEmpty()) {
builder.repositories(repositories);
}
if (!permissions.isEmpty()) {
builder.permissions(permissions);
} else {
builder.permissions(appInstallation.getPermissions());
}
GHAppInstallationToken appInstallationToken = builder.create();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These new methods from https://github.com/hub4j/github-api are what actually change the accessible repositories and permissions for the generated tokens.

@@ -22,12 +22,21 @@
</f:entry>

<f:advanced>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if we should still hide these options behind the advanced dropdown or not. Any thoughts?

Comment on lines +91 to +93
// TODO: CasC plugin incorrectly oversimplifies the YAML export for new-specific-empty by
// fully removing the repositoryAccessStrategy configuration because its inner
// configuration is all empty, but that means it no longer round-trips.
Copy link
Member Author

@dwnusbaum dwnusbaum Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Essentially, if you have a Describable with multiple possible implementations, and a single implementation whose inner values are nullable or can be an empty list, a configuration like this:

outerContext:
  whatever: foo
  describable:
    myDescribable1:
      innerConfiguration: []

Will be exported as this:

outerContext:
  whatever: foo

Which is not good if describable is heterogeneous and has multiple possible implementations! We'd like for it to be exported as the following, which is what happens if myDescribable1 has no nested configuration (I think because it ends up as a SCALAR in ConfigurationAsCode.toYaml instead of a MAPPING):

outerContext:
  whatever: foo
  describable: myDescribable1

Note also that Jenkins users who have Job/Configure permission in a context where the credentials are available are considered trusted and can bypass these strategies by configuring jobs as desired.
In trusted contexts, the generated access tokens will have the same access as configured for the app installation in GitHub.

The following repository access strategies are available:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these strategies make sense? Do they work they way you would expect? Do you think the default is appropriate? Is there any other strategy that you think should be supported?

@dwnusbaum dwnusbaum marked this pull request as ready for review January 21, 2025 22:24
@dwnusbaum dwnusbaum requested a review from a team as a code owner January 21, 2025 22:24
@dwnusbaum
Copy link
Member Author

dwnusbaum commented Jan 30, 2025

Hmm, some of the changes in 755fec8 might make the migration admin monitor trigger even for brand new app credentials. If so, we might need to swap back to setting the default values of the new fields in the constructor.

Comment on lines +321 to +323
if (!repositories.isEmpty()) {
builder.repositories(repositories);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving repositories empty should be the same as using gitHubApp.getInstallation().listRepositories() to specify repositories, i.e. leaving the parameter blank means "allow access to all repositories accessible to this installation".

@jeromepochat
Copy link
Contributor

I performed manual tests with:

  • 2 GitHub Apps (A1 and A2)
  • 2 GitHub organizations (O1 and O2)
  • A1 installed on O1 (restricted list of repositories)
  • A2 installed on O1 (restricted list of repositories)
  • A2 installed on O2 (all repositories)

On Jenkins, I tested the 3 RepositoryAccessStrategy implementations with Multibranch Pipelines and Organization Folder for both A1 and A2: everything works as described, the restriction is applied to the list of repositories in each case.

AccessSpecifiedRepositories with empty list of repositories restricts the access to owner's repositories.

AccessInferredRepository raise error as expected when used from non-multibranch Pipeline.

[JENKINS-75058] Merge with `master`
@rsandell
Copy link
Member

@jeromepochat
Copy link
Contributor

Holding the merge of this until jenkinsci/kubernetes-credentials-provider-plugin#107 and https://github.com/jenkins-infra/jenkins.io/blob/7a7552272c829342368859c104d0efe9922b78c9/content/doc/book/security/securing-org-folders-and-multibranch-pipelines.adoc?plain=1#L78-L84 are ready as well as some upgrade tests.

Hi @rsandell! As discussed, the merge path is:

  1. This PR providing the new options for GitHub App credentials
  2. Downstream PR that needs the new options provided by this one

@jeromepochat jeromepochat merged commit 4a9883d into jenkinsci:master Aug 28, 2025
17 checks passed
@darinpope
Copy link

Looks like these changes are causing issues with doing a BOM release this week. For reference:

jenkinsci/bom#5607

tl;dr...two plugins that passed on the Tuesday weekly build are now failing on Friday.

kubernetes-credentials-provider (I notice that's noted above):

[ERROR] com.cloudbees.jenkins.plugins.kubernetes_credentials_provider.convertors.GitHubAppCredentialsConvertorTest.canConvertAValidSecretWithApiUri -- Time elapsed: 0.174 s <<< ERROR!
java.lang.IllegalStateException: Expected 1 instance of org.jenkinsci.plugins.github_branch_source.app_credentials.MigrationAdminMonitor but got 0
        at hudson.ExtensionList.lookupSingleton(ExtensionList.java:478)
        at org.jenkinsci.plugins.github_branch_source.app_credentials.MigrationAdminMonitor.addMigratedCredentialId(MigrationAdminMonitor.java:32)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.setOwner(GitHubAppCredentials.java:175)
        at com.cloudbees.jenkins.plugins.kubernetes_credentials_provider.convertors.GitHubAppCredentialsConvertor.convert(GitHubAppCredentialsConvertor.java:67)
        at com.cloudbees.jenkins.plugins.kubernetes_credentials_provider.convertors.GitHubAppCredentialsConvertorTest.canConvertAValidSecretWithApiUri(GitHubAppCredentialsConvertorTest.java:101)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)

[ERROR] com.cloudbees.jenkins.plugins.kubernetes_credentials_provider.convertors.GitHubAppCredentialsConvertorTest.canConvertAValidSecretWithOwner -- Time elapsed: 0.001 s <<< ERROR!
java.lang.IllegalStateException: Expected 1 instance of org.jenkinsci.plugins.github_branch_source.app_credentials.MigrationAdminMonitor but got 0
        at hudson.ExtensionList.lookupSingleton(ExtensionList.java:478)
        at org.jenkinsci.plugins.github_branch_source.app_credentials.MigrationAdminMonitor.addMigratedCredentialId(MigrationAdminMonitor.java:32)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.setOwner(GitHubAppCredentials.java:175)
        at com.cloudbees.jenkins.plugins.kubernetes_credentials_provider.convertors.GitHubAppCredentialsConvertor.convert(GitHubAppCredentialsConvertor.java:67)
        at com.cloudbees.jenkins.plugins.kubernetes_credentials_provider.convertors.GitHubAppCredentialsConvertorTest.canConvertAValidSecretWithOwner(GitHubAppCredentialsConvertorTest.java:81)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)

and github-checks (also noted above, but not sure if there is any work planned for it or not):

[ERROR] io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldLogChecksParametersIfExceptionHappensWhenPublishChecks[Freestyle (run)] -- Time elapsed: 7.146 s <<< ERROR!
java.lang.IllegalArgumentException: Found multiple installations for GitHub app ID app-id but none match credential owner "XiongKezhi". Configure the repository access strategy for the credential to use one of these owners: bogus
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.generateAppInstallationToken(GitHubAppCredentials.java:314)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.getToken(GitHubAppCredentials.java:386)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials$CredentialsTokenProvider.getEncodedAuthorization(GitHubAppCredentials.java:262)
        at org.kohsuke.github.GitHubClient.prepareConnectorRequest(GitHubClient.java:616)
        at org.kohsuke.github.GitHubClient.sendRequest(GitHubClient.java:455)
        at org.kohsuke.github.GitHubClient.fetch(GitHubClient.java:159)
        at org.kohsuke.github.GitHubClient.checkApiUrlValidity(GitHubClient.java:390)
        at org.kohsuke.github.GitHub.checkApiUrlValidity(GitHub.java:1321)
        at org.jenkinsci.plugins.github_branch_source.ApiRateLimitChecker.verifyConnection(ApiRateLimitChecker.java:192)
        at org.jenkinsci.plugins.github_branch_source.Connector$GitHubConnection.verifyConnection(Connector.java:738)
        at org.jenkinsci.plugins.github_branch_source.Connector.connect(Connector.java:435)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisher.publish(GitHubChecksPublisher.java:81)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldLogChecksParametersIfExceptionHappensWhenPublishChecks(GitHubChecksPublisherITest.java:253)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.jvnet.hudson.test.JenkinsRule$1.evaluate(JenkinsRule.java:658)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.lang.Thread.run(Thread.java:1583)

[ERROR] io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.testChecksPublisherUpdatesCorrectly[Freestyle (run)] -- Time elapsed: 1.596 s <<< FAILURE!
org.opentest4j.AssertionFailedError:

expected: "XiongKezhi"
 but was: null
        at io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.testChecksPublisherUpdatesCorrectly(GitHubChecksPublisherITest.java:345)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.jvnet.hudson.test.JenkinsRule$1.evaluate(JenkinsRule.java:658)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.lang.Thread.run(Thread.java:1583)

[ERROR] io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldPublishGitHubCheckRunCorrectly[Freestyle (run)] -- Time elapsed: 1.259 s <<< ERROR!
java.lang.IllegalArgumentException: Found multiple installations for GitHub app ID app-id but none match credential owner "XiongKezhi". Configure the repository access strategy for the credential to use one of these owners: bogus
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.generateAppInstallationToken(GitHubAppCredentials.java:314)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.getToken(GitHubAppCredentials.java:386)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials$CredentialsTokenProvider.getEncodedAuthorization(GitHubAppCredentials.java:262)
        at org.kohsuke.github.GitHubClient.prepareConnectorRequest(GitHubClient.java:616)
        at org.kohsuke.github.GitHubClient.sendRequest(GitHubClient.java:455)
        at org.kohsuke.github.GitHubClient.fetch(GitHubClient.java:159)
        at org.kohsuke.github.GitHubClient.checkApiUrlValidity(GitHubClient.java:390)
        at org.kohsuke.github.GitHub.checkApiUrlValidity(GitHub.java:1321)
        at org.jenkinsci.plugins.github_branch_source.ApiRateLimitChecker.verifyConnection(ApiRateLimitChecker.java:192)
        at org.jenkinsci.plugins.github_branch_source.Connector$GitHubConnection.verifyConnection(Connector.java:738)
        at org.jenkinsci.plugins.github_branch_source.Connector.connect(Connector.java:435)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisher.publish(GitHubChecksPublisher.java:81)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldPublishGitHubCheckRunCorrectly(GitHubChecksPublisherITest.java:217)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.jvnet.hudson.test.JenkinsRule$1.evaluate(JenkinsRule.java:658)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.lang.Thread.run(Thread.java:1583)

[ERROR] io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldLogChecksParametersIfExceptionHappensWhenPublishChecks[Freestyle (job)] -- Time elapsed: 1.585 s <<< ERROR!
java.lang.IllegalArgumentException: Found multiple installations for GitHub app ID app-id but none match credential owner "XiongKezhi". Configure the repository access strategy for the credential to use one of these owners: bogus
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.generateAppInstallationToken(GitHubAppCredentials.java:314)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.getToken(GitHubAppCredentials.java:386)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials$CredentialsTokenProvider.getEncodedAuthorization(GitHubAppCredentials.java:262)
        at org.kohsuke.github.GitHubClient.prepareConnectorRequest(GitHubClient.java:616)
        at org.kohsuke.github.GitHubClient.sendRequest(GitHubClient.java:455)
        at org.kohsuke.github.GitHubClient.fetch(GitHubClient.java:159)
        at org.kohsuke.github.GitHubClient.checkApiUrlValidity(GitHubClient.java:390)
        at org.kohsuke.github.GitHub.checkApiUrlValidity(GitHub.java:1321)
        at org.jenkinsci.plugins.github_branch_source.ApiRateLimitChecker.verifyConnection(ApiRateLimitChecker.java:192)
        at org.jenkinsci.plugins.github_branch_source.Connector$GitHubConnection.verifyConnection(Connector.java:738)
        at org.jenkinsci.plugins.github_branch_source.Connector.connect(Connector.java:435)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisher.publish(GitHubChecksPublisher.java:81)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldLogChecksParametersIfExceptionHappensWhenPublishChecks(GitHubChecksPublisherITest.java:253)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.jvnet.hudson.test.JenkinsRule$1.evaluate(JenkinsRule.java:658)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.lang.Thread.run(Thread.java:1583)

[ERROR] io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.testChecksPublisherUpdatesCorrectly[Freestyle (job)] -- Time elapsed: 1.282 s <<< FAILURE!
org.opentest4j.AssertionFailedError:

expected: "XiongKezhi"
 but was: null
        at io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.testChecksPublisherUpdatesCorrectly(GitHubChecksPublisherITest.java:345)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.jvnet.hudson.test.JenkinsRule$1.evaluate(JenkinsRule.java:658)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.lang.Thread.run(Thread.java:1583)

[ERROR] io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldPublishGitHubCheckRunCorrectly[Freestyle (job)] -- Time elapsed: 2.462 s <<< ERROR!
java.lang.IllegalArgumentException: Found multiple installations for GitHub app ID app-id but none match credential owner "XiongKezhi". Configure the repository access strategy for the credential to use one of these owners: bogus
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.generateAppInstallationToken(GitHubAppCredentials.java:314)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.getToken(GitHubAppCredentials.java:386)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials$CredentialsTokenProvider.getEncodedAuthorization(GitHubAppCredentials.java:262)
        at org.kohsuke.github.GitHubClient.prepareConnectorRequest(GitHubClient.java:616)
        at org.kohsuke.github.GitHubClient.sendRequest(GitHubClient.java:455)
        at org.kohsuke.github.GitHubClient.fetch(GitHubClient.java:159)
        at org.kohsuke.github.GitHubClient.checkApiUrlValidity(GitHubClient.java:390)
        at org.kohsuke.github.GitHub.checkApiUrlValidity(GitHub.java:1321)
        at org.jenkinsci.plugins.github_branch_source.ApiRateLimitChecker.verifyConnection(ApiRateLimitChecker.java:192)
        at org.jenkinsci.plugins.github_branch_source.Connector$GitHubConnection.verifyConnection(Connector.java:738)
        at org.jenkinsci.plugins.github_branch_source.Connector.connect(Connector.java:435)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisher.publish(GitHubChecksPublisher.java:81)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldPublishGitHubCheckRunCorrectly(GitHubChecksPublisherITest.java:217)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.jvnet.hudson.test.JenkinsRule$1.evaluate(JenkinsRule.java:658)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.lang.Thread.run(Thread.java:1583)

[ERROR] io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldLogChecksParametersIfExceptionHappensWhenPublishChecks[Pipeline (run)] -- Time elapsed: 1.730 s <<< ERROR!
java.lang.IllegalArgumentException: Found multiple installations for GitHub app ID app-id but none match credential owner "XiongKezhi". Configure the repository access strategy for the credential to use one of these owners: bogus
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.generateAppInstallationToken(GitHubAppCredentials.java:314)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.getToken(GitHubAppCredentials.java:386)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials$CredentialsTokenProvider.getEncodedAuthorization(GitHubAppCredentials.java:262)
        at org.kohsuke.github.GitHubClient.prepareConnectorRequest(GitHubClient.java:616)
        at org.kohsuke.github.GitHubClient.sendRequest(GitHubClient.java:455)
        at org.kohsuke.github.GitHubClient.fetch(GitHubClient.java:159)
        at org.kohsuke.github.GitHubClient.checkApiUrlValidity(GitHubClient.java:390)
        at org.kohsuke.github.GitHub.checkApiUrlValidity(GitHub.java:1321)
        at org.jenkinsci.plugins.github_branch_source.ApiRateLimitChecker.verifyConnection(ApiRateLimitChecker.java:192)
        at org.jenkinsci.plugins.github_branch_source.Connector$GitHubConnection.verifyConnection(Connector.java:738)
        at org.jenkinsci.plugins.github_branch_source.Connector.connect(Connector.java:435)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisher.publish(GitHubChecksPublisher.java:81)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldLogChecksParametersIfExceptionHappensWhenPublishChecks(GitHubChecksPublisherITest.java:253)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.jvnet.hudson.test.JenkinsRule$1.evaluate(JenkinsRule.java:658)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.lang.Thread.run(Thread.java:1583)

[ERROR] io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.testChecksPublisherUpdatesCorrectly[Pipeline (run)] -- Time elapsed: 1.411 s <<< FAILURE!
org.opentest4j.AssertionFailedError:

expected: "XiongKezhi"
 but was: null
        at io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.testChecksPublisherUpdatesCorrectly(GitHubChecksPublisherITest.java:345)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.jvnet.hudson.test.JenkinsRule$1.evaluate(JenkinsRule.java:658)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.lang.Thread.run(Thread.java:1583)

[ERROR] io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldPublishGitHubCheckRunCorrectly[Pipeline (run)] -- Time elapsed: 1.065 s <<< ERROR!
java.lang.IllegalArgumentException: Found multiple installations for GitHub app ID app-id but none match credential owner "XiongKezhi". Configure the repository access strategy for the credential to use one of these owners: bogus
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.generateAppInstallationToken(GitHubAppCredentials.java:314)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.getToken(GitHubAppCredentials.java:386)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials$CredentialsTokenProvider.getEncodedAuthorization(GitHubAppCredentials.java:262)
        at org.kohsuke.github.GitHubClient.prepareConnectorRequest(GitHubClient.java:616)
        at org.kohsuke.github.GitHubClient.sendRequest(GitHubClient.java:455)
        at org.kohsuke.github.GitHubClient.fetch(GitHubClient.java:159)
        at org.kohsuke.github.GitHubClient.checkApiUrlValidity(GitHubClient.java:390)
        at org.kohsuke.github.GitHub.checkApiUrlValidity(GitHub.java:1321)
        at org.jenkinsci.plugins.github_branch_source.ApiRateLimitChecker.verifyConnection(ApiRateLimitChecker.java:192)
        at org.jenkinsci.plugins.github_branch_source.Connector$GitHubConnection.verifyConnection(Connector.java:738)
        at org.jenkinsci.plugins.github_branch_source.Connector.connect(Connector.java:435)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisher.publish(GitHubChecksPublisher.java:81)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldPublishGitHubCheckRunCorrectly(GitHubChecksPublisherITest.java:217)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.jvnet.hudson.test.JenkinsRule$1.evaluate(JenkinsRule.java:658)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.lang.Thread.run(Thread.java:1583)

[ERROR] io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldLogChecksParametersIfExceptionHappensWhenPublishChecks[Pipeline (job)] -- Time elapsed: 2.270 s <<< ERROR!
java.lang.IllegalArgumentException: Found multiple installations for GitHub app ID app-id but none match credential owner "XiongKezhi". Configure the repository access strategy for the credential to use one of these owners: bogus
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.generateAppInstallationToken(GitHubAppCredentials.java:314)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.getToken(GitHubAppCredentials.java:386)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials$CredentialsTokenProvider.getEncodedAuthorization(GitHubAppCredentials.java:262)
        at org.kohsuke.github.GitHubClient.prepareConnectorRequest(GitHubClient.java:616)
        at org.kohsuke.github.GitHubClient.sendRequest(GitHubClient.java:455)
        at org.kohsuke.github.GitHubClient.fetch(GitHubClient.java:159)
        at org.kohsuke.github.GitHubClient.checkApiUrlValidity(GitHubClient.java:390)
        at org.kohsuke.github.GitHub.checkApiUrlValidity(GitHub.java:1321)
        at org.jenkinsci.plugins.github_branch_source.ApiRateLimitChecker.verifyConnection(ApiRateLimitChecker.java:192)
        at org.jenkinsci.plugins.github_branch_source.Connector$GitHubConnection.verifyConnection(Connector.java:738)
        at org.jenkinsci.plugins.github_branch_source.Connector.connect(Connector.java:435)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisher.publish(GitHubChecksPublisher.java:81)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldLogChecksParametersIfExceptionHappensWhenPublishChecks(GitHubChecksPublisherITest.java:253)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.jvnet.hudson.test.JenkinsRule$1.evaluate(JenkinsRule.java:658)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.lang.Thread.run(Thread.java:1583)

[ERROR] io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.testChecksPublisherUpdatesCorrectly[Pipeline (job)] -- Time elapsed: 1.009 s <<< FAILURE!
org.opentest4j.AssertionFailedError:

expected: "XiongKezhi"
 but was: null
        at io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.testChecksPublisherUpdatesCorrectly(GitHubChecksPublisherITest.java:345)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.jvnet.hudson.test.JenkinsRule$1.evaluate(JenkinsRule.java:658)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.lang.Thread.run(Thread.java:1583)

[ERROR] io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldPublishGitHubCheckRunCorrectly[Pipeline (job)] -- Time elapsed: 1.597 s <<< ERROR!
java.lang.IllegalArgumentException: Found multiple installations for GitHub app ID app-id but none match credential owner "XiongKezhi". Configure the repository access strategy for the credential to use one of these owners: bogus
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.generateAppInstallationToken(GitHubAppCredentials.java:314)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials.getToken(GitHubAppCredentials.java:386)
        at org.jenkinsci.plugins.github_branch_source.GitHubAppCredentials$CredentialsTokenProvider.getEncodedAuthorization(GitHubAppCredentials.java:262)
        at org.kohsuke.github.GitHubClient.prepareConnectorRequest(GitHubClient.java:616)
        at org.kohsuke.github.GitHubClient.sendRequest(GitHubClient.java:455)
        at org.kohsuke.github.GitHubClient.fetch(GitHubClient.java:159)
        at org.kohsuke.github.GitHubClient.checkApiUrlValidity(GitHubClient.java:390)
        at org.kohsuke.github.GitHub.checkApiUrlValidity(GitHub.java:1321)
        at org.jenkinsci.plugins.github_branch_source.ApiRateLimitChecker.verifyConnection(ApiRateLimitChecker.java:192)
        at org.jenkinsci.plugins.github_branch_source.Connector$GitHubConnection.verifyConnection(Connector.java:738)
        at org.jenkinsci.plugins.github_branch_source.Connector.connect(Connector.java:435)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisher.publish(GitHubChecksPublisher.java:81)
        at io.jenkins.plugins.checks.github.GitHubChecksPublisherITest.shouldPublishGitHubCheckRunCorrectly(GitHubChecksPublisherITest.java:217)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.jvnet.hudson.test.JenkinsRule$1.evaluate(JenkinsRule.java:658)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.lang.Thread.run(Thread.java:1583)

For the moment so I can get the BOM release out today, I'm going to revert the PR that put in 1844.v4a_9883d49126 and block any more changes to github-branch-source until these issues are resolved.

FWIW, the local BOM commands I'm running that are failing are:

  • LINE=weekly PLUGINS=kubernetes-credentials-provider bash local-test.sh
  • LINE=weekly PLUGINS=github-checks bash local-test.sh

As noted, when I locally go back to 1834.v857721ea_74c6, the above commands succeed.

@dwnusbaum
Copy link
Member Author

dwnusbaum commented Aug 29, 2025

Thanks @darinpope. The former I think just needs a release of jenkinsci/kubernetes-credentials-provider-plugin#107.

The latter failures I think are all related to the incompatibility mentioned in the release notes here. The tests are setting an owner XiongKezhi, but the WireMock responses for the app installation are returning a single owner named bogus here. This used to work fine as long as there was only one app installation, since that owner would be used even if it didn't match the configuration in Jenkins, but the new logic is stricter and the owner must match in this case. Either the WireMock mapping can be updated to return XiongKezhi, or the tests can be updated to use "Specify accessible repositories" with an empty owner field to use the single app installation from the WireMock mapping. @jeromepochat might be able to take a look at this next week, but if not, I will look into it.

@darinpope
Copy link

Feels like we need tests for both "Specify..." and a mapping update, since both are valid cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants