From ac911d752f6a71a92f9fb06068df446f32c15bb1 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Wed, 8 May 2024 15:50:39 -0700 Subject: [PATCH 01/12] Initial commit of GitHub Apps installation demo --- GitHub.Octokit.sln | 2 ++ cli/Program.cs | 50 ++++++++++++++++++++++++++++++++++++++++++++++ cli/cli.csproj | 24 ++++++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 cli/Program.cs create mode 100644 cli/cli.csproj diff --git a/GitHub.Octokit.sln b/GitHub.Octokit.sln index e765f3a87..4397c1458 100644 --- a/GitHub.Octokit.sln +++ b/GitHub.Octokit.sln @@ -14,6 +14,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "test\Tests.csproj", "{7EF0200D-9F10-4A77-8F73-3E26D3EBD326}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cli", "cli\cli.csproj", "{3A6900D7-23D6-4AE5-B76A-76A05CD336F1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/cli/Program.cs b/cli/Program.cs new file mode 100644 index 000000000..b2d5917ed --- /dev/null +++ b/cli/Program.cs @@ -0,0 +1,50 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using GitHub; +using GitHub.Octokit.Authentication; +using GitHub.Octokit.Client; +using Org.BouncyCastle.Ocsp; + +// Use GitHubJwt library to create the GitHubApp Jwt Token using our private certificate PEM file +var generator = new GitHubJwt.GitHubJwtFactory( + new GitHubJwt.FilePrivateKeySource("/home/kfcampbell/github/dev/dotnet-sdk/kfcampbell-terraform-provider.2024-04-30.private-key.pem"), + new GitHubJwt.GitHubJwtFactoryOptions + { + AppIntegrationId = 131977, // The GitHub App Id + ExpirationSeconds = 600 // 10 minutes is the maximum time allowed + } +); +var jwtToken = generator.CreateEncodedJwtToken(); + +var installationId = 20570954; + +var client = new HttpClient(); +client.DefaultRequestHeaders.Add("Accept", "application/vnd.github+json"); +client.DefaultRequestHeaders.Add("X-GitHub-Api-Version", "2022-11-28"); +client.DefaultRequestHeaders.Add("User-Agent", "csharp-dummy-app-example"); +client.DefaultRequestHeaders.Add("Authorization", $"Bearer {jwtToken}"); + +var resp = await client.PostAsync($"https://api.github.com/app/installations/{installationId}/access_tokens", null); +var body = await resp.Content.ReadAsStringAsync(); + +if (!resp.IsSuccessStatusCode) { + Console.WriteLine($"Error: {resp.StatusCode}"); + Console.WriteLine($"Body: {body}"); + return; +} + +var respBody = JsonSerializer.Deserialize>(body); +var tokenElement = (JsonElement)respBody["token"]; +var token = tokenElement.ValueKind == JsonValueKind.String ? tokenElement.GetString() : ""; + +// var token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? ""; +var adapter = RequestAdapter.Create(new TokenAuthenticationProvider("Octokit.Gen", token)); +// adapter.BaseUrl = "http://api.github.localhost:1024"; +var gitHubClient = new GitHubClient(adapter); + +try { + var response = await gitHubClient.Installation.Repositories.GetAsync(); + response.Repositories.ForEach(repo => Console.WriteLine(repo.FullName)); +} catch (Exception e) { + Console.WriteLine(e.Message); +} diff --git a/cli/cli.csproj b/cli/cli.csproj new file mode 100644 index 000000000..b63e60156 --- /dev/null +++ b/cli/cli.csproj @@ -0,0 +1,24 @@ + + + Exe + net8.0 + enable + enable + + + $(RestoreSources);../src/bin/Debug;https://api.nuget.org/v3/index.json + + + + + + + + + + + + + + + From c9d8082c944864d81ab6e551621a58ec93700366 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Wed, 8 May 2024 15:57:09 -0700 Subject: [PATCH 02/12] Remove unncecessary using directive --- cli/Program.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/cli/Program.cs b/cli/Program.cs index b2d5917ed..aeb5aa588 100644 --- a/cli/Program.cs +++ b/cli/Program.cs @@ -1,9 +1,7 @@ using System.Text.Json; -using System.Text.Json.Serialization; using GitHub; using GitHub.Octokit.Authentication; using GitHub.Octokit.Client; -using Org.BouncyCastle.Ocsp; // Use GitHubJwt library to create the GitHubApp Jwt Token using our private certificate PEM file var generator = new GitHubJwt.GitHubJwtFactory( From a37d07c9fd905ae829f72b401aba484759fd988a Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 9 May 2024 11:01:27 -0700 Subject: [PATCH 03/12] Run dotnet format --- cli/Program.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cli/Program.cs b/cli/Program.cs index aeb5aa588..4d7dc648f 100644 --- a/cli/Program.cs +++ b/cli/Program.cs @@ -3,12 +3,11 @@ using GitHub.Octokit.Authentication; using GitHub.Octokit.Client; -// Use GitHubJwt library to create the GitHubApp Jwt Token using our private certificate PEM file var generator = new GitHubJwt.GitHubJwtFactory( new GitHubJwt.FilePrivateKeySource("/home/kfcampbell/github/dev/dotnet-sdk/kfcampbell-terraform-provider.2024-04-30.private-key.pem"), new GitHubJwt.GitHubJwtFactoryOptions { - AppIntegrationId = 131977, // The GitHub App Id + AppIntegrationId = 131977, // GitHub App Id ExpirationSeconds = 600 // 10 minutes is the maximum time allowed } ); @@ -25,7 +24,8 @@ var resp = await client.PostAsync($"https://api.github.com/app/installations/{installationId}/access_tokens", null); var body = await resp.Content.ReadAsStringAsync(); -if (!resp.IsSuccessStatusCode) { +if (!resp.IsSuccessStatusCode) +{ Console.WriteLine($"Error: {resp.StatusCode}"); Console.WriteLine($"Body: {body}"); return; @@ -40,9 +40,12 @@ // adapter.BaseUrl = "http://api.github.localhost:1024"; var gitHubClient = new GitHubClient(adapter); -try { +try +{ var response = await gitHubClient.Installation.Repositories.GetAsync(); response.Repositories.ForEach(repo => Console.WriteLine(repo.FullName)); -} catch (Exception e) { +} +catch (Exception e) +{ Console.WriteLine(e.Message); } From 0ffe620643311994a89ebec35e656bb06e8286d2 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 9 May 2024 11:01:55 -0700 Subject: [PATCH 04/12] Should fix CI build (while CLI is in place) --- .github/workflows/build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b6e0d1795..c7a520a61 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,6 +19,11 @@ jobs: with: dotnet-version: '8.x.x' + # This is a temporary step. Since the CLI references the main project locally, the main + # project must be built first. When the CLI is removed, this may be removed as well. + - name: Build main project + run: dotnet build src/GitHub.Octokit.SDK.csproj + - name: Format run: dotnet format --verify-no-changes From e3d536fe22c7f815c729e928ac1b49089d4a956a Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 9 May 2024 13:55:45 -0700 Subject: [PATCH 05/12] Initial sketch of ClientBuilder - Nothing is working/fully-implemented - Some refactoring is still needed after implementation - Auth options error handling in the Build method need to go in their own helper - Middleware defaults still need to be loaded - App token creation and refresh still need to be implemented --- cli/Program.cs | 2 +- .../TokenAuthenticationProvider.cs | 10 +- src/Client/ClientBuilder.cs | 142 ++++++++++++++++++ .../TokenAuthenticationProviderTest.cs | 11 +- test/Client/RequestAdaptorTest.cs | 6 +- 5 files changed, 149 insertions(+), 22 deletions(-) create mode 100644 src/Client/ClientBuilder.cs diff --git a/cli/Program.cs b/cli/Program.cs index 4d7dc648f..361255841 100644 --- a/cli/Program.cs +++ b/cli/Program.cs @@ -36,7 +36,7 @@ var token = tokenElement.ValueKind == JsonValueKind.String ? tokenElement.GetString() : ""; // var token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? ""; -var adapter = RequestAdapter.Create(new TokenAuthenticationProvider("Octokit.Gen", token)); +var adapter = RequestAdapter.Create(new TokenAuthenticationProvider(token)); // adapter.BaseUrl = "http://api.github.localhost:1024"; var gitHubClient = new GitHubClient(adapter); diff --git a/src/Authentication/TokenAuthenticationProvider.cs b/src/Authentication/TokenAuthenticationProvider.cs index 614e764bd..ec0ca5c65 100644 --- a/src/Authentication/TokenAuthenticationProvider.cs +++ b/src/Authentication/TokenAuthenticationProvider.cs @@ -18,11 +18,6 @@ public class TokenAuthenticationProvider : IAuthenticationProvider /// public IAuthenticationProvider TokenAuthProvider => this; - /// - /// Gets or sets the client identifier. - /// - public string ClientId { get; set; } - /// /// Gets or sets the token. /// @@ -34,12 +29,9 @@ public class TokenAuthenticationProvider : IAuthenticationProvider /// The client identifier to use. /// The token to use. /// - public TokenAuthenticationProvider(string clientId, string token) + public TokenAuthenticationProvider(string token) { - ArgumentException.ThrowIfNullOrEmpty(clientId); ArgumentException.ThrowIfNullOrEmpty(token); - - ClientId = clientId; Token = token; } diff --git a/src/Client/ClientBuilder.cs b/src/Client/ClientBuilder.cs new file mode 100644 index 000000000..0454f848d --- /dev/null +++ b/src/Client/ClientBuilder.cs @@ -0,0 +1,142 @@ + + +using System.Linq; +using System.Runtime.InteropServices; +using GitHub.Octokit.Authentication; + +namespace GitHub.Octokit.Client; + +public struct ClientOptions +{ + public string UserAgent { get; set; } + public string APIVersion { get; set; } + public string BaseURL { get; set; } + + public IList Middlewares { get; set; } + + // PersonalAccessToken should be left blank if GitHub App auth or an unauthenticated client is desired + public string PersonalAccessToken { get; set; } + + // GitHubAppPemFilePath should be left blank if token auth or an unauthenticated client is desired. + public string GitHubAppPemFilePath { get; set; } + + // GitHubAppID should be left blank if token auth or an unauthenticated client is desired. + public long GitHubAppID { get; set; } + + // GitHubAppInstallationID should be left blank if token auth or an unauthenticated client is desired. + public long GitHubAppInstallationID { get; set; } + +} + +public class ClientBuilder +{ + private ClientOptions _options; + + public ClientBuilder(ClientOptions? options = null) + { + if (options != null) { + _options = (ClientOptions)options; + } else { + // it's a little annoying that the defaults aren't applied if the user brings their own + // options struct. we can recommend users call GetDefaultClientOptions() before applying + // their own, but that's still not ideal. + _options = GetDefaultClientOptions(); + } + } + + public ClientOptions GetDefaultClientOptions() + { + return new ClientOptions + { + // TODO(kfcampbell): get version from assembly or tagged release + UserAgent = "octokit/dotnet-sdk@prerelease", + APIVersion = "2022-11-28", + }; + } + + public ClientBuilder WithUserAgent(string userAgent) + { + _options.UserAgent = userAgent; + return this; + } + + public ClientBuilder WithAPIVersion(string apiVersion) + { + _options.APIVersion = apiVersion; + return this; + } + + public ClientBuilder WithBaseURL(string baseURL) + { + _options.BaseURL = baseURL; + return this; + } + + public ClientBuilder WithTokenAuth(string personalAccessToken) + { + _options.PersonalAccessToken = personalAccessToken; + return this; + } + + public ClientBuilder WithGitHubAppAuth(string gitHubAppPemFilePath, long gitHubAppID, long gitHubAppInstallationID) + { + _options.GitHubAppPemFilePath = gitHubAppPemFilePath; + _options.GitHubAppID = gitHubAppID; + _options.GitHubAppInstallationID = gitHubAppInstallationID; + return this; + } + + public ClientBuilder WithMiddleware(HttpMessageHandler handler) + { + if (_options.Middlewares == null) + { + _options.Middlewares = new List(); + } + if (handler != null && !_options.Middlewares.Contains(handler)) + { + _options.Middlewares.Add(handler); + } + return this; + } + + public GitHubClient Build() + { + // TODO(kfcampbell): figure out how to chain together options here to implement the build method + // this is the crux of the thing, really + // can assume we have some default options set based on the constructor + + // TODO(kfcampbell): refactor auth options out into a helper method + // if token auth is configured and app ID isn't, build a token auth client + if (_options.PersonalAccessToken != null + && _options.GitHubAppPemFilePath == "" + && _options.GitHubAppID == 0 + && _options.GitHubAppInstallationID == 0) + { + var tokenProvider = new TokenAuthenticationProvider(_options.PersonalAccessToken); + } + // if app auth is configured and token isn't, build an app auth client + else if (_options.GitHubAppPemFilePath != null + && _options.GitHubAppID != 0 + && _options.GitHubAppInstallationID != 0 + && _options.PersonalAccessToken == "") + { + + } + // if some other combination of options is set, throw an error + else if (_options.PersonalAccessToken != null + && _options.GitHubAppPemFilePath != null + && _options.GitHubAppID != 0 + && _options.GitHubAppInstallationID != 0) + { + throw new ArgumentException("Cannot configure both token and app auth at the same time"); + } + else + { + throw new NotImplementedException("Keegan needs to get his act together and implement this"); + } + + // very basic non-working implementation to keep compiler happy + var requestAdapter = RequestAdapter.Create(new TokenAuthenticationProvider(""), null); + return new GitHubClient(requestAdapter); + } +} diff --git a/test/Authentication/TokenAuthenticationProviderTest.cs b/test/Authentication/TokenAuthenticationProviderTest.cs index 8ede85677..adb8656d3 100644 --- a/test/Authentication/TokenAuthenticationProviderTest.cs +++ b/test/Authentication/TokenAuthenticationProviderTest.cs @@ -6,25 +6,18 @@ public class TokenAuthenticationProviderTests { - private const string ValidClientId = "validClientId"; private const string ValidToken = "validToken"; private TokenAuthenticationProvider _provider; public TokenAuthenticationProviderTests() { - _provider = new TokenAuthenticationProvider(ValidClientId, ValidToken); - } - - [Fact] - public void Constructor_ThrowsException_WhenClientIdIsEmpty() - { - Assert.Throws(() => new TokenAuthenticationProvider("", ValidToken)); + _provider = new TokenAuthenticationProvider(ValidToken); } [Fact] public void Constructor_ThrowsException_WhenTokenIsEmpty() { - Assert.Throws(() => new TokenAuthenticationProvider(ValidClientId, "")); + Assert.Throws(() => new TokenAuthenticationProvider("")); } [Fact] diff --git a/test/Client/RequestAdaptorTest.cs b/test/Client/RequestAdaptorTest.cs index 2218829d3..6dd1224eb 100644 --- a/test/Client/RequestAdaptorTest.cs +++ b/test/Client/RequestAdaptorTest.cs @@ -9,7 +9,7 @@ public class RequestAdapterTests [Fact] public void Creates_RequestAdaptor_With_Defaults() { - var requestAdapter = RequestAdapter.Create(new TokenAuthenticationProvider("Octokit.Gen", "JRRTOLKIEN")); + var requestAdapter = RequestAdapter.Create(new TokenAuthenticationProvider("JRRTOLKIEN")); Assert.NotNull(requestAdapter); } @@ -17,7 +17,7 @@ public void Creates_RequestAdaptor_With_Defaults() public void Creates_RequestAdaptor_With_GenericHttpClient() { var httpClient = new HttpClient(); - var requestAdapter = RequestAdapter.Create(new TokenAuthenticationProvider("Octokit.Gen", "JRRTOLKIEN"), httpClient); + var requestAdapter = RequestAdapter.Create(new TokenAuthenticationProvider("JRRTOLKIEN"), httpClient); Assert.NotNull(requestAdapter); } @@ -25,7 +25,7 @@ public void Creates_RequestAdaptor_With_GenericHttpClient() public void Creates_RequestAdaptor_With_ClientFactory() { var clientFactory = ClientFactory.Create(); - var requestAdapter = RequestAdapter.Create(new TokenAuthenticationProvider("Octokit.Gen", "JRRTOLKIEN"), clientFactory); + var requestAdapter = RequestAdapter.Create(new TokenAuthenticationProvider("JRRTOLKIEN"), clientFactory); Assert.NotNull(requestAdapter); } } From b560cc2d9efa2598cef4128cfe57b7ca70f7c1cc Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 9 May 2024 15:17:52 -0700 Subject: [PATCH 06/12] Refactor GetAuthType and validation to separate method --- src/Client/ClientBuilder.cs | 67 ++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/src/Client/ClientBuilder.cs b/src/Client/ClientBuilder.cs index 0454f848d..cfaff3d6c 100644 --- a/src/Client/ClientBuilder.cs +++ b/src/Client/ClientBuilder.cs @@ -18,13 +18,13 @@ public struct ClientOptions public string PersonalAccessToken { get; set; } // GitHubAppPemFilePath should be left blank if token auth or an unauthenticated client is desired. - public string GitHubAppPemFilePath { get; set; } + public string GitHubAppPemFilePath { get; set; } - // GitHubAppID should be left blank if token auth or an unauthenticated client is desired. - public long GitHubAppID { get; set; } + // GitHubAppID should be left blank if token auth or an unauthenticated client is desired. + public long GitHubAppID { get; set; } - // GitHubAppInstallationID should be left blank if token auth or an unauthenticated client is desired. - public long GitHubAppInstallationID { get; set; } + // GitHubAppInstallationID should be left blank if token auth or an unauthenticated client is desired. + public long GitHubAppInstallationID { get; set; } } @@ -34,9 +34,12 @@ public class ClientBuilder public ClientBuilder(ClientOptions? options = null) { - if (options != null) { + if (options != null) + { _options = (ClientOptions)options; - } else { + } + else + { // it's a little annoying that the defaults aren't applied if the user brings their own // options struct. we can recommend users call GetDefaultClientOptions() before applying // their own, but that's still not ideal. @@ -105,26 +108,54 @@ public GitHubClient Build() // this is the crux of the thing, really // can assume we have some default options set based on the constructor - // TODO(kfcampbell): refactor auth options out into a helper method + var authType = GetAuthType(); + var token = ""; + if (authType == AuthType.PersonalAccessToken) + { + // build a token auth client + } + else if (authType == AuthType.GitHubApp) + { + // build an app auth client + } + else + { + // use an unauthenticated token provider + } + + // very basic non-working implementation to keep compiler happy + var requestAdapter = RequestAdapter.Create(new TokenAuthenticationProvider(token), null); + return new GitHubClient(requestAdapter); + } + + public enum AuthType + { + PersonalAccessToken, + GitHubApp + } + + // TODO(kfcampbell): flesh this out further and test it + private AuthType GetAuthType() + { // if token auth is configured and app ID isn't, build a token auth client - if (_options.PersonalAccessToken != null - && _options.GitHubAppPemFilePath == "" + if (!string.IsNullOrEmpty(_options.PersonalAccessToken) + && string.IsNullOrEmpty(_options.GitHubAppPemFilePath) && _options.GitHubAppID == 0 && _options.GitHubAppInstallationID == 0) { - var tokenProvider = new TokenAuthenticationProvider(_options.PersonalAccessToken); + return AuthType.PersonalAccessToken; } // if app auth is configured and token isn't, build an app auth client - else if (_options.GitHubAppPemFilePath != null + else if (!string.IsNullOrEmpty(_options.GitHubAppPemFilePath) && _options.GitHubAppID != 0 && _options.GitHubAppInstallationID != 0 - && _options.PersonalAccessToken == "") + && string.IsNullOrEmpty(_options.PersonalAccessToken)) { - + return AuthType.GitHubApp; } // if some other combination of options is set, throw an error - else if (_options.PersonalAccessToken != null - && _options.GitHubAppPemFilePath != null + else if (string.IsNullOrEmpty(_options.PersonalAccessToken) + && !string.IsNullOrEmpty(_options.GitHubAppPemFilePath) && _options.GitHubAppID != 0 && _options.GitHubAppInstallationID != 0) { @@ -134,9 +165,5 @@ public GitHubClient Build() { throw new NotImplementedException("Keegan needs to get his act together and implement this"); } - - // very basic non-working implementation to keep compiler happy - var requestAdapter = RequestAdapter.Create(new TokenAuthenticationProvider(""), null); - return new GitHubClient(requestAdapter); } } From e35c88e588a555e5a1df43dd174510ad3b6e2263 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 9 May 2024 15:52:21 -0700 Subject: [PATCH 07/12] Beginnings of tests for GetAuthType --- src/Client/ClientBuilder.cs | 27 ++++-- test/Client/ClientBuilderTest.cs | 152 +++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 7 deletions(-) create mode 100644 test/Client/ClientBuilderTest.cs diff --git a/src/Client/ClientBuilder.cs b/src/Client/ClientBuilder.cs index cfaff3d6c..8d782e53d 100644 --- a/src/Client/ClientBuilder.cs +++ b/src/Client/ClientBuilder.cs @@ -1,7 +1,3 @@ - - -using System.Linq; -using System.Runtime.InteropServices; using GitHub.Octokit.Authentication; namespace GitHub.Octokit.Client; @@ -113,6 +109,7 @@ public GitHubClient Build() if (authType == AuthType.PersonalAccessToken) { // build a token auth client + token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? ""; } else if (authType == AuthType.GitHubApp) { @@ -131,11 +128,13 @@ public GitHubClient Build() public enum AuthType { PersonalAccessToken, - GitHubApp + GitHubApp, + Unauthenticated } // TODO(kfcampbell): flesh this out further and test it - private AuthType GetAuthType() + // how to differentiate between an unauthenticated client and a client with misconfigured auth? + public AuthType GetAuthType() { // if token auth is configured and app ID isn't, build a token auth client if (!string.IsNullOrEmpty(_options.PersonalAccessToken) @@ -153,11 +152,25 @@ private AuthType GetAuthType() { return AuthType.GitHubApp; } + // if nothing is configured, return unauthenticated + else if (string.IsNullOrEmpty(_options.PersonalAccessToken) + && string.IsNullOrEmpty(_options.GitHubAppPemFilePath) + && _options.GitHubAppID == 0 + && _options.GitHubAppInstallationID == 0) + { + return AuthType.Unauthenticated; + } // if some other combination of options is set, throw an error + // empty access token, zero app ID, non-zero installation ID, non-empty app pem file else if (string.IsNullOrEmpty(_options.PersonalAccessToken) + && _options.GitHubAppID == 0 + && !string.IsNullOrEmpty(_options.GitHubAppPemFilePath) + && _options.GitHubAppInstallationID != 0) /*|| + // + (string.IsNullOrEmpty(_options.PersonalAccessToken) && !string.IsNullOrEmpty(_options.GitHubAppPemFilePath) && _options.GitHubAppID != 0 - && _options.GitHubAppInstallationID != 0) + && _options.GitHubAppInstallationID != 0)*/ { throw new ArgumentException("Cannot configure both token and app auth at the same time"); } diff --git a/test/Client/ClientBuilderTest.cs b/test/Client/ClientBuilderTest.cs new file mode 100644 index 000000000..f58d1a8bf --- /dev/null +++ b/test/Client/ClientBuilderTest.cs @@ -0,0 +1,152 @@ + +using GitHub.Octokit.Client; +using Xunit; + +public class ClientBuilderTests +{ + [Fact] + public void GetAuthType_WithNoAuthDefined_ReturnsUnauthenticated() + { + var options = new ClientOptions(); + var clientBuilder = new ClientBuilder(options); + Assert.Equal(ClientBuilder.AuthType.Unauthenticated, clientBuilder.GetAuthType()); + } + + [Fact] + public void GetAuthType_WithTokenDefined_ReturnsTokenType() + { + var options = new ClientOptions + { + PersonalAccessToken = "some_token", + }; + + var clientBuilder = new ClientBuilder(options); + Assert.Equal(ClientBuilder.AuthType.PersonalAccessToken, clientBuilder.GetAuthType()); + } + + [Fact] + public void GetAuthType_WithAppDefined_ReturnsAppType() + { + var options = new ClientOptions + { + GitHubAppID = 1, + GitHubAppInstallationID = 1, + GitHubAppPemFilePath = "some/path", + }; + + var clientBuilder = new ClientBuilder(options); + Assert.Equal(ClientBuilder.AuthType.GitHubApp, clientBuilder.GetAuthType()); + } + + [Fact] + public void GetAuthType_WithTokenAndAppIdDefined_ReturnsError() + { + var options = new ClientOptions + { + PersonalAccessToken = "some_token", + GitHubAppID = 1, + }; + var clientBuilder = new ClientBuilder(options); + Assert.Throws(() => clientBuilder.GetAuthType()); + } + + [Fact] + public void GetAuthType_WithTokenAndInstallationIdDefined_ReturnsError() + { + var options = new ClientOptions + { + PersonalAccessToken = "some_token", + GitHubAppInstallationID = 1, + }; + var clientBuilder = new ClientBuilder(options); + Assert.Throws(() => clientBuilder.GetAuthType()); + } + + [Fact] + public void GetAuthType_WithTokenAndPemFilePathDefined_ReturnsError() + { + var options = new ClientOptions + { + PersonalAccessToken = "some_token", + GitHubAppPemFilePath = "some/path", + }; + var clientBuilder = new ClientBuilder(options); + Assert.Throws(() => clientBuilder.GetAuthType()); + } + + [Fact] + public void GetAuthType_WithTokenAndAppIdAndPemFilePathDefined_ReturnsError() + { + var options = new ClientOptions + { + PersonalAccessToken = "some_token", + GitHubAppID = 1, + GitHubAppPemFilePath = "some/path", + }; + var clientBuilder = new ClientBuilder(options); + Assert.Throws(() => clientBuilder.GetAuthType()); + } + + [Fact] + public void GetAuthType_WithTokenAndAppIdAndInstallationIdDefined_ReturnsError() + { + var options = new ClientOptions + { + PersonalAccessToken = "some_token", + GitHubAppID = 1, + GitHubAppInstallationID = 1, + }; + var clientBuilder = new ClientBuilder(options); + Assert.Throws(() => clientBuilder.GetAuthType()); + } + + [Fact] + public void GetAuthType_WithTokenAndAppIdAndInstallationIdAndPemFilePathDefined_ReturnsError() + { + var options = new ClientOptions + { + PersonalAccessToken = "some_token", + GitHubAppID = 1, + GitHubAppInstallationID = 1, + GitHubAppPemFilePath = "some/path", + }; + var clientBuilder = new ClientBuilder(options); + Assert.Throws(() => clientBuilder.GetAuthType()); + } + + [Fact] + public void GetAuthType_WithOnlyAppIdAndInstallationIdDefined_ReturnsError() + { + var options = new ClientOptions + { + GitHubAppID = 1, + GitHubAppInstallationID = 1, + }; + var clientBuilder = new ClientBuilder(options); + Assert.Throws(() => clientBuilder.GetAuthType()); + } + + [Fact] + public void GetAuthType_WithOnlyAppIdAndPemFilePathDefined_ReturnsError() + { + var options = new ClientOptions + { + GitHubAppID = 1, + GitHubAppPemFilePath = "some/path", + }; + var clientBuilder = new ClientBuilder(options); + Assert.Throws(() => clientBuilder.GetAuthType()); + } + + [Fact] + public void GetAuthType_WithOnlyInstallationIdAndPemFilePathDefined_ReturnsError() + { + var options = new ClientOptions + { + GitHubAppInstallationID = 1, + GitHubAppPemFilePath = "some/path", + }; + var clientBuilder = new ClientBuilder(options); + Assert.Throws(() => clientBuilder.GetAuthType()); + } +} From a094dc0cfb4f5d41717344e661fef8c0f99a7119 Mon Sep 17 00:00:00 2001 From: Nick Floyd <139819+nickfloyd@users.noreply.github.com> Date: Mon, 13 May 2024 11:08:09 -0500 Subject: [PATCH 08/12] Updates the cli to make it easire to use across dev instances. Code now uses the more patform common package Microsoft.Identity.. --- .gitignore | 3 +- cli/Program.cs | 90 ++++++++++++++++++++++++++++++++------------------ cli/cli.csproj | 1 + 3 files changed, 61 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 457a68392..26bf0ef3a 100644 --- a/.gitignore +++ b/.gitignore @@ -108,4 +108,5 @@ node_modules/ testresults/ [Tt]est[Rr]esult*/ **/coverage.json -coverage/* \ No newline at end of file +coverage/* +*.pem \ No newline at end of file diff --git a/cli/Program.cs b/cli/Program.cs index 361255841..de75393b3 100644 --- a/cli/Program.cs +++ b/cli/Program.cs @@ -1,39 +1,20 @@ using System.Text.Json; +using System.Security.Cryptography; +using Microsoft.IdentityModel.JsonWebTokens; +using Microsoft.IdentityModel.Tokens; using GitHub; using GitHub.Octokit.Authentication; using GitHub.Octokit.Client; -var generator = new GitHubJwt.GitHubJwtFactory( - new GitHubJwt.FilePrivateKeySource("/home/kfcampbell/github/dev/dotnet-sdk/kfcampbell-terraform-provider.2024-04-30.private-key.pem"), - new GitHubJwt.GitHubJwtFactoryOptions - { - AppIntegrationId = 131977, // GitHub App Id - ExpirationSeconds = 600 // 10 minutes is the maximum time allowed - } -); -var jwtToken = generator.CreateEncodedJwtToken(); +var installationId = Environment.GetEnvironmentVariable("GITHUB_APP_INSTALLATION_ID") ?? ""; +var clientId = Environment.GetEnvironmentVariable("GITHUB_APP_CLIENT_ID") ?? ""; +var privateKey = File.ReadAllText(Environment.GetEnvironmentVariable("GITHUB_APP_PRIVATE_KEY_PATH") ?? ""); +var jwtToken = CreateJWT(clientId, privateKey); -var installationId = 20570954; +var client = BuildHttpClient(jwtToken); +var token = GetAppToken(client).Result; -var client = new HttpClient(); -client.DefaultRequestHeaders.Add("Accept", "application/vnd.github+json"); -client.DefaultRequestHeaders.Add("X-GitHub-Api-Version", "2022-11-28"); -client.DefaultRequestHeaders.Add("User-Agent", "csharp-dummy-app-example"); -client.DefaultRequestHeaders.Add("Authorization", $"Bearer {jwtToken}"); - -var resp = await client.PostAsync($"https://api.github.com/app/installations/{installationId}/access_tokens", null); -var body = await resp.Content.ReadAsStringAsync(); - -if (!resp.IsSuccessStatusCode) -{ - Console.WriteLine($"Error: {resp.StatusCode}"); - Console.WriteLine($"Body: {body}"); - return; -} - -var respBody = JsonSerializer.Deserialize>(body); -var tokenElement = (JsonElement)respBody["token"]; -var token = tokenElement.ValueKind == JsonValueKind.String ? tokenElement.GetString() : ""; +if (string.IsNullOrEmpty(token)) throw new Exception("Failed to get token"); // var token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? ""; var adapter = RequestAdapter.Create(new TokenAuthenticationProvider(token)); @@ -42,10 +23,55 @@ try { - var response = await gitHubClient.Installation.Repositories.GetAsync(); - response.Repositories.ForEach(repo => Console.WriteLine(repo.FullName)); + var response = await gitHubClient.Installation.Repositories.GetAsync(); + response?.Repositories?.ForEach(repo => Console.WriteLine(repo.FullName)); } catch (Exception e) { - Console.WriteLine(e.Message); + Console.WriteLine(e.Message); +} + +string CreateJWT(string clientId, string privateKey) +{ + var rsa = RSA.Create(); + rsa.ImportFromPem(privateKey); + + var now = DateTimeOffset.Now; + var tokenDescriptor = new SecurityTokenDescriptor + { + Issuer = clientId, + IssuedAt = now.UtcDateTime, + NotBefore = now.UtcDateTime, + Expires = now.AddMinutes(10).UtcDateTime, + SigningCredentials = new(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256) + }; + + return new JsonWebTokenHandler().CreateToken(tokenDescriptor); } + +HttpClient BuildHttpClient(string token) +{ + var client = new HttpClient(); + client.DefaultRequestHeaders.Add("Accept", "application/vnd.github+json"); + client.DefaultRequestHeaders.Add("X-GitHub-Api-Version", "2022-11-28"); + client.DefaultRequestHeaders.Add("User-Agent", "csharp-dummy-app-example"); + client.DefaultRequestHeaders.Add("Authorization", $"Bearer {jwtToken}"); + + return client; + +} + +async Task GetAppToken(HttpClient client) +{ + var resp = await client.PostAsync($"https://api.github.com/app/installations/{installationId}/access_tokens", null); + var body = await resp.Content.ReadAsStringAsync(); + + if (!resp.IsSuccessStatusCode) + { + throw new Exception($"Error: {resp.StatusCode}, Body: {body}"); + } + + var respBody = JsonSerializer.Deserialize>(body); + var tokenElement = (JsonElement?)respBody?["token"]; + return tokenElement?.ValueKind == JsonValueKind.String ? tokenElement?.GetString() : ""; +} \ No newline at end of file diff --git a/cli/cli.csproj b/cli/cli.csproj index b63e60156..d9f71fb62 100644 --- a/cli/cli.csproj +++ b/cli/cli.csproj @@ -10,6 +10,7 @@ + From bbdc88adc462356986e30797f2185c70c7bff388 Mon Sep 17 00:00:00 2001 From: Nick Floyd <139819+nickfloyd@users.noreply.github.com> Date: Mon, 13 May 2024 11:12:48 -0500 Subject: [PATCH 09/12] fixes whitespace issues --- cli/Program.cs | 62 +++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/cli/Program.cs b/cli/Program.cs index de75393b3..a3f200856 100644 --- a/cli/Program.cs +++ b/cli/Program.cs @@ -23,55 +23,55 @@ try { - var response = await gitHubClient.Installation.Repositories.GetAsync(); - response?.Repositories?.ForEach(repo => Console.WriteLine(repo.FullName)); + var response = await gitHubClient.Installation.Repositories.GetAsync(); + response?.Repositories?.ForEach(repo => Console.WriteLine(repo.FullName)); } catch (Exception e) { - Console.WriteLine(e.Message); + Console.WriteLine(e.Message); } string CreateJWT(string clientId, string privateKey) { - var rsa = RSA.Create(); - rsa.ImportFromPem(privateKey); + var rsa = RSA.Create(); + rsa.ImportFromPem(privateKey); - var now = DateTimeOffset.Now; - var tokenDescriptor = new SecurityTokenDescriptor - { - Issuer = clientId, - IssuedAt = now.UtcDateTime, - NotBefore = now.UtcDateTime, - Expires = now.AddMinutes(10).UtcDateTime, - SigningCredentials = new(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256) - }; + var now = DateTimeOffset.Now; + var tokenDescriptor = new SecurityTokenDescriptor + { + Issuer = clientId, + IssuedAt = now.UtcDateTime, + NotBefore = now.UtcDateTime, + Expires = now.AddMinutes(10).UtcDateTime, + SigningCredentials = new(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256) + }; - return new JsonWebTokenHandler().CreateToken(tokenDescriptor); + return new JsonWebTokenHandler().CreateToken(tokenDescriptor); } HttpClient BuildHttpClient(string token) { - var client = new HttpClient(); - client.DefaultRequestHeaders.Add("Accept", "application/vnd.github+json"); - client.DefaultRequestHeaders.Add("X-GitHub-Api-Version", "2022-11-28"); - client.DefaultRequestHeaders.Add("User-Agent", "csharp-dummy-app-example"); - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {jwtToken}"); + var client = new HttpClient(); + client.DefaultRequestHeaders.Add("Accept", "application/vnd.github+json"); + client.DefaultRequestHeaders.Add("X-GitHub-Api-Version", "2022-11-28"); + client.DefaultRequestHeaders.Add("User-Agent", "csharp-dummy-app-example"); + client.DefaultRequestHeaders.Add("Authorization", $"Bearer {jwtToken}"); - return client; + return client; } async Task GetAppToken(HttpClient client) { - var resp = await client.PostAsync($"https://api.github.com/app/installations/{installationId}/access_tokens", null); - var body = await resp.Content.ReadAsStringAsync(); + var resp = await client.PostAsync($"https://api.github.com/app/installations/{installationId}/access_tokens", null); + var body = await resp.Content.ReadAsStringAsync(); - if (!resp.IsSuccessStatusCode) - { - throw new Exception($"Error: {resp.StatusCode}, Body: {body}"); - } + if (!resp.IsSuccessStatusCode) + { + throw new Exception($"Error: {resp.StatusCode}, Body: {body}"); + } - var respBody = JsonSerializer.Deserialize>(body); - var tokenElement = (JsonElement?)respBody?["token"]; - return tokenElement?.ValueKind == JsonValueKind.String ? tokenElement?.GetString() : ""; -} \ No newline at end of file + var respBody = JsonSerializer.Deserialize>(body); + var tokenElement = (JsonElement?)respBody?["token"]; + return tokenElement?.ValueKind == JsonValueKind.String ? tokenElement?.GetString() : ""; +} From f10b319e74b5d2ddd40507664cf635cee9ef4ee4 Mon Sep 17 00:00:00 2001 From: Nick Floyd <139819+nickfloyd@users.noreply.github.com> Date: Mon, 13 May 2024 11:21:38 -0500 Subject: [PATCH 10/12] fixes usings order --- cli/Program.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/Program.cs b/cli/Program.cs index a3f200856..7e0d892f4 100644 --- a/cli/Program.cs +++ b/cli/Program.cs @@ -1,10 +1,10 @@ -using System.Text.Json; -using System.Security.Cryptography; -using Microsoft.IdentityModel.JsonWebTokens; -using Microsoft.IdentityModel.Tokens; +using System.Security.Cryptography; +using System.Text.Json; using GitHub; using GitHub.Octokit.Authentication; using GitHub.Octokit.Client; +using Microsoft.IdentityModel.JsonWebTokens; +using Microsoft.IdentityModel.Tokens; var installationId = Environment.GetEnvironmentVariable("GITHUB_APP_INSTALLATION_ID") ?? ""; var clientId = Environment.GetEnvironmentVariable("GITHUB_APP_CLIENT_ID") ?? ""; From 5f681e74de7037033807c06c562dbd8def2808db Mon Sep 17 00:00:00 2001 From: Nick Floyd <139819+nickfloyd@users.noreply.github.com> Date: Mon, 13 May 2024 11:31:14 -0500 Subject: [PATCH 11/12] refactored a little bit for readability --- src/Client/ClientBuilder.cs | 261 +++++++++++++++++------------------- 1 file changed, 122 insertions(+), 139 deletions(-) diff --git a/src/Client/ClientBuilder.cs b/src/Client/ClientBuilder.cs index 8d782e53d..c6f5652e8 100644 --- a/src/Client/ClientBuilder.cs +++ b/src/Client/ClientBuilder.cs @@ -4,179 +4,162 @@ namespace GitHub.Octokit.Client; public struct ClientOptions { - public string UserAgent { get; set; } - public string APIVersion { get; set; } - public string BaseURL { get; set; } + public string UserAgent { get; set; } + public string APIVersion { get; set; } + public string BaseURL { get; set; } - public IList Middlewares { get; set; } + public IList Middlewares { get; set; } - // PersonalAccessToken should be left blank if GitHub App auth or an unauthenticated client is desired - public string PersonalAccessToken { get; set; } + // PersonalAccessToken should be left blank if GitHub App auth or an unauthenticated client is desired + public string PersonalAccessToken { get; set; } - // GitHubAppPemFilePath should be left blank if token auth or an unauthenticated client is desired. - public string GitHubAppPemFilePath { get; set; } + // GitHubAppPemFilePath should be left blank if token auth or an unauthenticated client is desired. + public string GitHubAppPemFilePath { get; set; } - // GitHubAppID should be left blank if token auth or an unauthenticated client is desired. - public long GitHubAppID { get; set; } + // GitHubAppID should be left blank if token auth or an unauthenticated client is desired. + public long GitHubAppID { get; set; } - // GitHubAppInstallationID should be left blank if token auth or an unauthenticated client is desired. - public long GitHubAppInstallationID { get; set; } + // GitHubAppInstallationID should be left blank if token auth or an unauthenticated client is desired. + public long GitHubAppInstallationID { get; set; } } public class ClientBuilder { - private ClientOptions _options; + private ClientOptions _options; - public ClientBuilder(ClientOptions? options = null) + public ClientBuilder(ClientOptions? options = null) + { + if (options != null) { - if (options != null) - { - _options = (ClientOptions)options; - } - else - { - // it's a little annoying that the defaults aren't applied if the user brings their own - // options struct. we can recommend users call GetDefaultClientOptions() before applying - // their own, but that's still not ideal. - _options = GetDefaultClientOptions(); - } + _options = (ClientOptions)options; } - - public ClientOptions GetDefaultClientOptions() + else { - return new ClientOptions - { - // TODO(kfcampbell): get version from assembly or tagged release - UserAgent = "octokit/dotnet-sdk@prerelease", - APIVersion = "2022-11-28", - }; + // it's a little annoying that the defaults aren't applied if the user brings their own + // options struct. we can recommend users call GetDefaultClientOptions() before applying + // their own, but that's still not ideal. + _options = GetDefaultClientOptions(); } + } - public ClientBuilder WithUserAgent(string userAgent) + public ClientOptions GetDefaultClientOptions() + { + return new ClientOptions { - _options.UserAgent = userAgent; - return this; - } - - public ClientBuilder WithAPIVersion(string apiVersion) + // TODO(kfcampbell): get version from assembly or tagged release + UserAgent = "octokit/dotnet-sdk@prerelease", + APIVersion = "2022-11-28", + }; + } + + public ClientBuilder WithUserAgent(string userAgent) + { + _options.UserAgent = userAgent; + return this; + } + + public ClientBuilder WithAPIVersion(string apiVersion) + { + _options.APIVersion = apiVersion; + return this; + } + + public ClientBuilder WithBaseURL(string baseURL) + { + _options.BaseURL = baseURL; + return this; + } + + public ClientBuilder WithTokenAuth(string personalAccessToken) + { + _options.PersonalAccessToken = personalAccessToken; + return this; + } + + public ClientBuilder WithGitHubAppAuth(string gitHubAppPemFilePath, long gitHubAppID, long gitHubAppInstallationID) + { + _options.GitHubAppPemFilePath = gitHubAppPemFilePath; + _options.GitHubAppID = gitHubAppID; + _options.GitHubAppInstallationID = gitHubAppInstallationID; + return this; + } + + public ClientBuilder WithMiddleware(HttpMessageHandler handler) + { + if (_options.Middlewares == null) { - _options.APIVersion = apiVersion; - return this; + _options.Middlewares = new List(); } - - public ClientBuilder WithBaseURL(string baseURL) + if (handler != null && !_options.Middlewares.Contains(handler)) { - _options.BaseURL = baseURL; - return this; + _options.Middlewares.Add(handler); } - - public ClientBuilder WithTokenAuth(string personalAccessToken) + return this; + } + + public GitHubClient Build() + { + // TODO(kfcampbell): figure out how to chain together options here to implement the build method + // this is the crux of the thing, really + // can assume we have some default options set based on the constructor + + var authType = GetAuthType(); + var token = ""; + if (authType == AuthType.PersonalAccessToken) { - _options.PersonalAccessToken = personalAccessToken; - return this; + // build a token auth client + token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? ""; } - - public ClientBuilder WithGitHubAppAuth(string gitHubAppPemFilePath, long gitHubAppID, long gitHubAppInstallationID) + else if (authType == AuthType.GitHubApp) { - _options.GitHubAppPemFilePath = gitHubAppPemFilePath; - _options.GitHubAppID = gitHubAppID; - _options.GitHubAppInstallationID = gitHubAppInstallationID; - return this; + // build an app auth client } - - public ClientBuilder WithMiddleware(HttpMessageHandler handler) + else { - if (_options.Middlewares == null) - { - _options.Middlewares = new List(); - } - if (handler != null && !_options.Middlewares.Contains(handler)) - { - _options.Middlewares.Add(handler); - } - return this; + // use an unauthenticated token provider } - public GitHubClient Build() + // very basic non-working implementation to keep compiler happy + var requestAdapter = RequestAdapter.Create(new TokenAuthenticationProvider(token), null); + return new GitHubClient(requestAdapter); + } + + public enum AuthType + { + PersonalAccessToken, + GitHubApp, + Unauthenticated + } + + // TODO(kfcampbell): flesh this out further and test it + // how to differentiate between an unauthenticated client and a client with misconfigured auth? + public AuthType GetAuthType() + { + bool hasToken = !string.IsNullOrEmpty(_options.PersonalAccessToken); + bool hasAppCredentials = !string.IsNullOrEmpty(_options.GitHubAppPemFilePath) + && _options.GitHubAppID != 0 + && _options.GitHubAppInstallationID != 0; + + // Check for valid token authentication setup + if (hasToken && !hasAppCredentials) { - // TODO(kfcampbell): figure out how to chain together options here to implement the build method - // this is the crux of the thing, really - // can assume we have some default options set based on the constructor - - var authType = GetAuthType(); - var token = ""; - if (authType == AuthType.PersonalAccessToken) - { - // build a token auth client - token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? ""; - } - else if (authType == AuthType.GitHubApp) - { - // build an app auth client - } - else - { - // use an unauthenticated token provider - } - - // very basic non-working implementation to keep compiler happy - var requestAdapter = RequestAdapter.Create(new TokenAuthenticationProvider(token), null); - return new GitHubClient(requestAdapter); + return AuthType.PersonalAccessToken; } - public enum AuthType + // Check for valid GitHub app authentication setup + if (!hasToken && hasAppCredentials) { - PersonalAccessToken, - GitHubApp, - Unauthenticated + return AuthType.GitHubApp; } - // TODO(kfcampbell): flesh this out further and test it - // how to differentiate between an unauthenticated client and a client with misconfigured auth? - public AuthType GetAuthType() + // Check for unauthenticated setup + if (!hasToken && !hasAppCredentials) { - // if token auth is configured and app ID isn't, build a token auth client - if (!string.IsNullOrEmpty(_options.PersonalAccessToken) - && string.IsNullOrEmpty(_options.GitHubAppPemFilePath) - && _options.GitHubAppID == 0 - && _options.GitHubAppInstallationID == 0) - { - return AuthType.PersonalAccessToken; - } - // if app auth is configured and token isn't, build an app auth client - else if (!string.IsNullOrEmpty(_options.GitHubAppPemFilePath) - && _options.GitHubAppID != 0 - && _options.GitHubAppInstallationID != 0 - && string.IsNullOrEmpty(_options.PersonalAccessToken)) - { - return AuthType.GitHubApp; - } - // if nothing is configured, return unauthenticated - else if (string.IsNullOrEmpty(_options.PersonalAccessToken) - && string.IsNullOrEmpty(_options.GitHubAppPemFilePath) - && _options.GitHubAppID == 0 - && _options.GitHubAppInstallationID == 0) - { - return AuthType.Unauthenticated; - } - // if some other combination of options is set, throw an error - // empty access token, zero app ID, non-zero installation ID, non-empty app pem file - else if (string.IsNullOrEmpty(_options.PersonalAccessToken) - && _options.GitHubAppID == 0 - && !string.IsNullOrEmpty(_options.GitHubAppPemFilePath) - && _options.GitHubAppInstallationID != 0) /*|| - // - (string.IsNullOrEmpty(_options.PersonalAccessToken) - && !string.IsNullOrEmpty(_options.GitHubAppPemFilePath) - && _options.GitHubAppID != 0 - && _options.GitHubAppInstallationID != 0)*/ - { - throw new ArgumentException("Cannot configure both token and app auth at the same time"); - } - else - { - throw new NotImplementedException("Keegan needs to get his act together and implement this"); - } + return AuthType.Unauthenticated; } + + // If configurations are mixed or incorrect, throw an error + throw new ArgumentException("Invalid authentication configuration."); + } } From ed8b9fcbdc197fc744878abef471b369c729a866 Mon Sep 17 00:00:00 2001 From: Nick Floyd <139819+nickfloyd@users.noreply.github.com> Date: Tue, 14 May 2024 13:40:17 -0500 Subject: [PATCH 12/12] removes the unused ref --- cli/cli.csproj | 1 - src/GitHub.Octokit.SDK.csproj | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/cli.csproj b/cli/cli.csproj index d9f71fb62..0fd38cfb4 100644 --- a/cli/cli.csproj +++ b/cli/cli.csproj @@ -9,7 +9,6 @@ $(RestoreSources);../src/bin/Debug;https://api.nuget.org/v3/index.json - diff --git a/src/GitHub.Octokit.SDK.csproj b/src/GitHub.Octokit.SDK.csproj index 232d5ed16..41fffdbe8 100644 --- a/src/GitHub.Octokit.SDK.csproj +++ b/src/GitHub.Octokit.SDK.csproj @@ -33,6 +33,7 @@ +