Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-73388

Allow alternative implementation for GitHub App credentials

XMLWordPrintable

      We need to implement alternative GitHub App credentials that retrieve its properties (appId, privateKey, owner) from an external system. This alternative implementation contains information to read properties from the external system. After the properties are read from the external system, the business logic must be the same than the existing GitHubAppCredentials implementation.

      To avoid code duplication, it would be nice to reuse the business logic from existing GitHubAppCredentials implementation with properties read from the external system instead of the local credentials storage.

      1. Our first attempt was to use delegation pattern: AlternativeGitHubAppCredentials reads the properties from the external system, creates GitHubAppCredentials using these properties, and delegates the business logic to that GitHubAppCredentials instance.

      Pseudo code:

      class AlternativeGitHubAppCredentials implements StandardUsernamePasswordCredentials {
      
          private transient GitHubAppCredentials delegate;
      
          public String getAppID() {
              return getDelegate().getAppID();
          }
      
          public String getPrivateKey() {
              return getDelegate().getPrivateKey();
          }
      
          private GitHubAppCredentials getDelegate() {
              if (delegate == null) {
                  String appID = readFromExternalSystem("appId");
                  String privateKey = readFromExternalSystem("privateKey");
                  delegate = new GitHubAppCredentials(appID, privateKey);
              }
              return delegate;
          }
      } 

      This is currently not working because existing plugins downcast to GitHubAppCredentials, making some features not supported for alternative implementation. For example, the current Connector class supports GitHub App credentials with strong type constraint. In case of GitHub App credentials alternative implementation that cannot extends GitHubAppCredentials, the check for scan considers it as non GitHub App authentication and fails with "Resource not accessible by integration" error:

      org.kohsuke.github.HttpException: {"message":"Resource not accessible by integration","documentation_url":"https://docs.github.com/rest/users/users#get-the-authenticated-user"}
      at org.kohsuke.github.GitHubConnectorResponseErrorHandler$1.onError(GitHubConnectorResponseErrorHandler.java:62)
      at org.kohsuke.github.GitHubClient.detectKnownErrors(GitHubClient.java:504)
      at org.kohsuke.github.GitHubClient.sendRequest(GitHubClient.java:464)
      at org.kohsuke.github.GitHubClient.sendRequest(GitHubClient.java:427)
      at org.kohsuke.github.Requester.fetch(Requester.java:85)
      at org.kohsuke.github.GitHub.setMyself(GitHub.java:583)
      at org.kohsuke.github.GitHub.getMyself(GitHub.java:577)
      at org.jenkinsci.plugins.github_branch_source.GitHubSCMNavigator.visitSources(GitHubSCMNavigator.java:1005)
      at jenkins.branch.OrganizationFolder.computeChildren(OrganizationFolder.java:535)
      at com.cloudbees.hudson.plugins.folder.computed.ComputedFolder.updateChildren(ComputedFolder.java:269)
      at com.cloudbees.hudson.plugins.folder.computed.FolderComputation.run(FolderComputation.java:167)
      at jenkins.branch.OrganizationFolder$OrganizationScan.run(OrganizationFolder.java:920)
      at hudson.model.ResourceController.execute(ResourceController.java:101)
      at hudson.model.Executor.run(Executor.java:443) 

      2. Another approach would be to extends the current implementation to read properties from the external system instead of return field values.

      Pseudo code:

      class AlternativeGitHubAppCredentials extends GitHubAppCredentials {
      
          @Override
          public String getAppID() {
              return readFromExternalSystem("appId");
          }
      
          @Override
          public String getPrivateKey() {
              return readFromExternalSystem("privateKey");
          }
      } 

      This is currently not possible as GitHubAppCredentials does not strongly encapsulate its fields.

            jpochat Jérôme Pochat
            jpochat Jérôme Pochat
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: