From c2aee1ac54083ab51657042bdc245c0ff0b2571c Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Mon, 24 Jun 2024 12:24:45 -0500 Subject: [PATCH] [FEAT]: Create a GitHub App from a manifest * Create a GitHub App from a manifest * Add missing InstallationPermissions * observable and tests * Remove ManualRoute on Observable route --------- Co-authored-by: Nick Floyd <139819+nickfloyd@users.noreply.github.com> --- .../Clients/IObservableGitHubAppsClient.cs | 8 ++ .../Clients/ObservableGitHubAppsClient.cs | 13 +++ .../Clients/GitHubAppsClientTests.cs | 32 ++++++++ .../Models/GitHubAppFromManifestTests.cs | 81 +++++++++++++++++++ .../ObservableGitHubAppsClientTests.cs | 32 ++++++++ Octokit/Clients/GitHubAppsClient.cs | 14 ++++ Octokit/Clients/IGitHubAppsClient.cs | 10 ++- Octokit/Helpers/ApiUrls.cs | 9 +++ Octokit/Models/Response/GitHubApp.cs | 30 ++++--- .../Models/Response/GitHubAppFromManifest.cs | 45 +++++++++++ .../Response/InstallationPermissions.cs | 21 +++++ 11 files changed, 282 insertions(+), 13 deletions(-) create mode 100644 Octokit.Tests/Models/GitHubAppFromManifestTests.cs create mode 100644 Octokit/Models/Response/GitHubAppFromManifest.cs diff --git a/Octokit.Reactive/Clients/IObservableGitHubAppsClient.cs b/Octokit.Reactive/Clients/IObservableGitHubAppsClient.cs index 30a7e70d3f..089086bc50 100644 --- a/Octokit.Reactive/Clients/IObservableGitHubAppsClient.cs +++ b/Octokit.Reactive/Clients/IObservableGitHubAppsClient.cs @@ -110,5 +110,13 @@ public interface IObservableGitHubAppsClient /// https://developer.github.com/v3/apps/#find-user-installation /// The name of the user IObservable GetUserInstallationForCurrent(string user); + + /// + /// Creates a GitHub app by completing the handshake necessary when implementing the GitHub App Manifest flow. + /// https://docs.github.com/apps/sharing-github-apps/registering-a-github-app-from-a-manifest + /// + /// https://docs.github.com/rest/apps/apps#create-a-github-app-from-a-manifest + /// Temporary code in a code parameter. + IObservable CreateAppFromManifest(string code); } } diff --git a/Octokit.Reactive/Clients/ObservableGitHubAppsClient.cs b/Octokit.Reactive/Clients/ObservableGitHubAppsClient.cs index 8179baa5de..0077cd68fc 100644 --- a/Octokit.Reactive/Clients/ObservableGitHubAppsClient.cs +++ b/Octokit.Reactive/Clients/ObservableGitHubAppsClient.cs @@ -175,5 +175,18 @@ public IObservable GetUserInstallationForCurrent(string user) return _client.GetUserInstallationForCurrent(user).ToObservable(); } + + /// + /// Creates a GitHub app by completing the handshake necessary when implementing the GitHub App Manifest flow. + /// https://docs.github.com/apps/sharing-github-apps/registering-a-github-app-from-a-manifest + /// + /// https://docs.github.com/rest/apps/apps#create-a-github-app-from-a-manifest + /// Temporary code in a code parameter. + public IObservable CreateAppFromManifest(string code) + { + Ensure.ArgumentNotNullOrEmptyString(code, nameof(code)); + + return _client.CreateAppFromManifest(code).ToObservable(); + } } } diff --git a/Octokit.Tests/Clients/GitHubAppsClientTests.cs b/Octokit.Tests/Clients/GitHubAppsClientTests.cs index 5647679eb3..ee68fde391 100644 --- a/Octokit.Tests/Clients/GitHubAppsClientTests.cs +++ b/Octokit.Tests/Clients/GitHubAppsClientTests.cs @@ -273,5 +273,37 @@ public void GetsFromCorrectUrl() connection.Received().Get(Arg.Is(u => u.ToString() == "users/ducks/installation"), null); } } + + public class TheCreateAppFromManifestMethod + { + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new GitHubAppsClient(connection); + + await Assert.ThrowsAsync(() => client.CreateAppFromManifest(null)); + } + + [Fact] + public async Task EnsuresNonEmptyArguments() + { + var connection = Substitute.For(); + var client = new GitHubAppsClient(connection); + + await Assert.ThrowsAsync(() => client.CreateAppFromManifest("")); + } + + [Fact] + public void PostsFromCorrectUrl() + { + var connection = Substitute.For(); + var client = new GitHubAppsClient(connection); + + client.CreateAppFromManifest("abc123"); + + connection.Received().Post(Arg.Is(u => u.ToString() == "app-manifests/abc123/conversions")); + } + } } } diff --git a/Octokit.Tests/Models/GitHubAppFromManifestTests.cs b/Octokit.Tests/Models/GitHubAppFromManifestTests.cs new file mode 100644 index 0000000000..262a67202f --- /dev/null +++ b/Octokit.Tests/Models/GitHubAppFromManifestTests.cs @@ -0,0 +1,81 @@ +using Octokit.Internal; +using Xunit; + +namespace Octokit.Tests.Models +{ + public class GitHubAppFromManifestTests + { + [Fact] + public void CanBeDeserialized() + { + // from https://docs.github.com/rest/apps/apps#create-a-github-app-from-a-manifest + const string json = @"{ + ""id"": 1, + ""slug"": ""octoapp"", + ""node_id"": ""MDxOkludGVncmF0aW9uMQ=="", + ""owner"": { + ""login"": ""github"", + ""id"": 1, + ""node_id"": ""MDEyOk9yZ2FuaXphdGlvbjE="", + ""url"": ""https://api.github.com/orgs/github"", + ""repos_url"": ""https://api.github.com/orgs/github/repos"", + ""events_url"": ""https://api.github.com/orgs/github/events"", + ""avatar_url"": ""https://github.com/images/error/octocat_happy.gif"", + ""gravatar_id"": """", + ""html_url"": ""https://github.com/octocat"", + ""followers_url"": ""https://api.github.com/users/octocat/followers"", + ""following_url"": ""https://api.github.com/users/octocat/following{/other_user}"", + ""gists_url"": ""https://api.github.com/users/octocat/gists{/gist_id}"", + ""starred_url"": ""https://api.github.com/users/octocat/starred{/owner}{/repo}"", + ""subscriptions_url"": ""https://api.github.com/users/octocat/subscriptions"", + ""organizations_url"": ""https://api.github.com/users/octocat/orgs"", + ""received_events_url"": ""https://api.github.com/users/octocat/received_events"", + ""type"": ""User"", + ""site_admin"": true + }, + ""name"": ""Octocat App"", + ""description"": ""A short description of the app"", + ""external_url"": ""https://example.com"", + ""html_url"": ""https://github.com/apps/octoapp"", + ""created_at"": ""2017-07-08T16:18:44-04:00"", + ""updated_at"": ""2017-07-08T16:18:44-04:00"", + ""permissions"": { + ""metadata"": ""read"", + ""contents"": ""read"", + ""issues"": ""write"", + ""single_file"": ""write"" + }, + ""events"": [ + ""push"", + ""pull_request"" + ], + ""client_id"": ""Iv1.8a61f9b3a7aba766"", + ""client_secret"": ""1726be1638095a19edd134c77bde3aa2ece1e5d8"", + ""webhook_secret"": ""e340154128314309424b7c8e90325147d99fdafa"", + ""pem"": ""-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAuEPzOUE+kiEH1WLiMeBytTEF856j0hOVcSUSUkZxKvqczkWM\n9vo1gDyC7ZXhdH9fKh32aapba3RSsp4ke+giSmYTk2mGR538ShSDxh0OgpJmjiKP\nX0Bj4j5sFqfXuCtl9SkH4iueivv4R53ktqM+n6hk98l6hRwC39GVIblAh2lEM4L/\n6WvYwuQXPMM5OG2Ryh2tDZ1WS5RKfgq+9ksNJ5Q9UtqtqHkO+E63N5OK9sbzpUUm\noNaOl3udTlZD3A8iqwMPVxH4SxgATBPAc+bmjk6BMJ0qIzDcVGTrqrzUiywCTLma\nszdk8GjzXtPDmuBgNn+o6s02qVGpyydgEuqmTQIDAQABAoIBACL6AvkjQVVLn8kJ\ndBYznJJ4M8ECo+YEgaFwgAHODT0zRQCCgzd+Vxl4YwHmKV2Lr+y2s0drZt8GvYva\nKOK8NYYZyi15IlwFyRXmvvykF1UBpSXluYFDH7KaVroWMgRreHcIys5LqVSIb6Bo\ngDmK0yBLPp8qR29s2b7ScZRtLaqGJiX+j55rNzrZwxHkxFHyG9OG+u9IsBElcKCP\nkYCVE8ZdYexfnKOZbgn2kZB9qu0T/Mdvki8yk3I2bI6xYO24oQmhnT36qnqWoCBX\nNuCNsBQgpYZeZET8mEAUmo9d+ABmIHIvSs005agK8xRaP4+6jYgy6WwoejJRF5yd\nNBuF7aECgYEA50nZ4FiZYV0vcJDxFYeY3kYOvVuKn8OyW+2rg7JIQTremIjv8FkE\nZnwuF9ZRxgqLxUIfKKfzp/5l5LrycNoj2YKfHKnRejxRWXqG+ZETfxxlmlRns0QG\nJ4+BYL0CoanDSeA4fuyn4Bv7cy/03TDhfg/Uq0Aeg+hhcPE/vx3ebPsCgYEAy/Pv\neDLssOSdeyIxf0Brtocg6aPXIVaLdus+bXmLg77rJIFytAZmTTW8SkkSczWtucI3\nFI1I6sei/8FdPzAl62/JDdlf7Wd9K7JIotY4TzT7Tm7QU7xpfLLYIP1bOFjN81rk\n77oOD4LsXcosB/U6s1blPJMZ6AlO2EKs10UuR1cCgYBipzuJ2ADEaOz9RLWwi0AH\nPza2Sj+c2epQD9ZivD7Zo/Sid3ZwvGeGF13JyR7kLEdmAkgsHUdu1rI7mAolXMaB\n1pdrsHureeLxGbRM6za3tzMXWv1Il7FQWoPC8ZwXvMOR1VQDv4nzq7vbbA8z8c+c\n57+8tALQHOTDOgQIzwK61QKBgERGVc0EJy4Uag+VY8J4m1ZQKBluqo7TfP6DQ7O8\nM5MX73maB/7yAX8pVO39RjrhJlYACRZNMbK+v/ckEQYdJSSKmGCVe0JrGYDuPtic\nI9+IGfSorf7KHPoMmMN6bPYQ7Gjh7a++tgRFTMEc8956Hnt4xGahy9NcglNtBpVN\n6G8jAoGBAMCh028pdzJa/xeBHLLaVB2sc0Fe7993WlsPmnVE779dAz7qMscOtXJK\nfgtriltLSSD6rTA9hUAsL/X62rY0wdXuNdijjBb/qvrx7CAV6i37NK1CjABNjsfG\nZM372Ac6zc1EqSrid2IjET1YqyIW2KGLI1R2xbQc98UGlt48OdWu\n-----END RSA PRIVATE KEY-----\n"" +}"; + + var app = new SimpleJsonSerializer().Deserialize(json); + + Assert.Equal(1, app.Id); + Assert.Equal("octoapp", app.Slug); + Assert.Equal("MDxOkludGVncmF0aW9uMQ==", app.NodeId); + Assert.Equal("Octocat App", app.Name); + Assert.Equal("A short description of the app", app.Description); + Assert.Equal("https://example.com", app.ExternalUrl); + Assert.Equal("https://github.com/apps/octoapp", app.HtmlUrl); + Assert.Equal(InstallationReadWritePermissionLevel.Write, app.Permissions.SingleFile); + Assert.Contains("push", app.Events); + + Assert.Equal("Iv1.8a61f9b3a7aba766", app.ClientId); + Assert.Equal("1726be1638095a19edd134c77bde3aa2ece1e5d8", app.ClientSecret); + Assert.Equal("e340154128314309424b7c8e90325147d99fdafa", app.WebhookSecret); + Assert.Equal("-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAuEPzOUE+kiEH1WLiMeBytTEF856j0hOVcSUSUkZxKvqczkWM\n9vo1gDyC7ZXhdH9fKh32aapba3RSsp4ke+giSmYTk2mGR538ShSDxh0OgpJmjiKP\nX0Bj4j5sFqfXuCtl9SkH4iueivv4R53ktqM+n6hk98l6hRwC39GVIblAh2lEM4L/\n6WvYwuQXPMM5OG2Ryh2tDZ1WS5RKfgq+9ksNJ5Q9UtqtqHkO+E63N5OK9sbzpUUm\noNaOl3udTlZD3A8iqwMPVxH4SxgATBPAc+bmjk6BMJ0qIzDcVGTrqrzUiywCTLma\nszdk8GjzXtPDmuBgNn+o6s02qVGpyydgEuqmTQIDAQABAoIBACL6AvkjQVVLn8kJ\ndBYznJJ4M8ECo+YEgaFwgAHODT0zRQCCgzd+Vxl4YwHmKV2Lr+y2s0drZt8GvYva\nKOK8NYYZyi15IlwFyRXmvvykF1UBpSXluYFDH7KaVroWMgRreHcIys5LqVSIb6Bo\ngDmK0yBLPp8qR29s2b7ScZRtLaqGJiX+j55rNzrZwxHkxFHyG9OG+u9IsBElcKCP\nkYCVE8ZdYexfnKOZbgn2kZB9qu0T/Mdvki8yk3I2bI6xYO24oQmhnT36qnqWoCBX\nNuCNsBQgpYZeZET8mEAUmo9d+ABmIHIvSs005agK8xRaP4+6jYgy6WwoejJRF5yd\nNBuF7aECgYEA50nZ4FiZYV0vcJDxFYeY3kYOvVuKn8OyW+2rg7JIQTremIjv8FkE\nZnwuF9ZRxgqLxUIfKKfzp/5l5LrycNoj2YKfHKnRejxRWXqG+ZETfxxlmlRns0QG\nJ4+BYL0CoanDSeA4fuyn4Bv7cy/03TDhfg/Uq0Aeg+hhcPE/vx3ebPsCgYEAy/Pv\neDLssOSdeyIxf0Brtocg6aPXIVaLdus+bXmLg77rJIFytAZmTTW8SkkSczWtucI3\nFI1I6sei/8FdPzAl62/JDdlf7Wd9K7JIotY4TzT7Tm7QU7xpfLLYIP1bOFjN81rk\n77oOD4LsXcosB/U6s1blPJMZ6AlO2EKs10UuR1cCgYBipzuJ2ADEaOz9RLWwi0AH\nPza2Sj+c2epQD9ZivD7Zo/Sid3ZwvGeGF13JyR7kLEdmAkgsHUdu1rI7mAolXMaB\n1pdrsHureeLxGbRM6za3tzMXWv1Il7FQWoPC8ZwXvMOR1VQDv4nzq7vbbA8z8c+c\n57+8tALQHOTDOgQIzwK61QKBgERGVc0EJy4Uag+VY8J4m1ZQKBluqo7TfP6DQ7O8\nM5MX73maB/7yAX8pVO39RjrhJlYACRZNMbK+v/ckEQYdJSSKmGCVe0JrGYDuPtic\nI9+IGfSorf7KHPoMmMN6bPYQ7Gjh7a++tgRFTMEc8956Hnt4xGahy9NcglNtBpVN\n6G8jAoGBAMCh028pdzJa/xeBHLLaVB2sc0Fe7993WlsPmnVE779dAz7qMscOtXJK\nfgtriltLSSD6rTA9hUAsL/X62rY0wdXuNdijjBb/qvrx7CAV6i37NK1CjABNjsfG\nZM372Ac6zc1EqSrid2IjET1YqyIW2KGLI1R2xbQc98UGlt48OdWu\n-----END RSA PRIVATE KEY-----\n", app.Pem); + + Assert.Equal(1, app.Owner.Id); + Assert.Equal("github", app.Owner.Login); + Assert.Equal("https://api.github.com/orgs/github", app.Owner.Url); + Assert.Equal(AccountType.User, app.Owner.Type); + } + } +} diff --git a/Octokit.Tests/Reactive/ObservableGitHubAppsClientTests.cs b/Octokit.Tests/Reactive/ObservableGitHubAppsClientTests.cs index ca6f27ffd7..12758acd5f 100644 --- a/Octokit.Tests/Reactive/ObservableGitHubAppsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableGitHubAppsClientTests.cs @@ -287,5 +287,37 @@ public void GetsFromCorrectUrl() gitHubClient.GitHubApps.Received().GetUserInstallationForCurrent("ducks"); } } + + public class TheCreateAppFromManifestMethod + { + [Fact] + public void EnsuresNonNullArguments() + { + var gitHubClient = Substitute.For(); + var client = new ObservableGitHubAppsClient(gitHubClient); + + Assert.Throws(() => client.CreateAppFromManifest(null)); + } + + [Fact] + public void EnsuresNonEmptyArguments() + { + var gitHubClient = Substitute.For(); + var client = new ObservableGitHubAppsClient(gitHubClient); + + Assert.Throws(() => client.CreateAppFromManifest("")); + } + + [Fact] + public void GetsFromCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableGitHubAppsClient(gitHubClient); + + client.CreateAppFromManifest("abc123"); + + gitHubClient.GitHubApps.Received().CreateAppFromManifest("abc123"); + } + } } } diff --git a/Octokit/Clients/GitHubAppsClient.cs b/Octokit/Clients/GitHubAppsClient.cs index e9ee0ad2dd..4896c08637 100644 --- a/Octokit/Clients/GitHubAppsClient.cs +++ b/Octokit/Clients/GitHubAppsClient.cs @@ -192,5 +192,19 @@ public Task GetUserInstallationForCurrent(string user) return ApiConnection.Get(ApiUrls.UserInstallation(user), null); } + + /// + /// Creates a GitHub app by completing the handshake necessary when implementing the GitHub App Manifest flow. + /// https://docs.github.com/apps/sharing-github-apps/registering-a-github-app-from-a-manifest + /// + /// https://docs.github.com/rest/apps/apps#create-a-github-app-from-a-manifest + /// Temporary code in a code parameter. + [ManualRoute("POST", "/app-manifests/{code}/conversions")] + public Task CreateAppFromManifest(string code) + { + Ensure.ArgumentNotNullOrEmptyString(code, nameof(code)); + + return ApiConnection.Post(ApiUrls.AppManifestConversions(code)); + } } } diff --git a/Octokit/Clients/IGitHubAppsClient.cs b/Octokit/Clients/IGitHubAppsClient.cs index 4906a4fe9f..974e99cab5 100644 --- a/Octokit/Clients/IGitHubAppsClient.cs +++ b/Octokit/Clients/IGitHubAppsClient.cs @@ -112,5 +112,13 @@ public interface IGitHubAppsClient /// https://developer.github.com/v3/apps/#find-user-installation /// The name of the user Task GetUserInstallationForCurrent(string user); + + /// + /// Creates a GitHub app by completing the handshake necessary when implementing the GitHub App Manifest flow. + /// https://docs.github.com/apps/sharing-github-apps/registering-a-github-app-from-a-manifest + /// + /// https://docs.github.com/rest/apps/apps#create-a-github-app-from-a-manifest + /// Temporary code in a code parameter. + Task CreateAppFromManifest(string code); } -} \ No newline at end of file +} diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index 3e147ac7b8..1ca4b9c01c 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -403,6 +403,15 @@ public static Uri NotificationSubscription(int notificationId) return "notifications/threads/{0}/subscription".FormatUri(notificationId); } + /// + /// Returns the to complete the handshake necessary when implementing the GitHub App Manifest flow. + /// + /// Temporary code in a code parameter. + public static Uri AppManifestConversions(string code) + { + return "app-manifests/{0}/conversions".FormatUri(code); + } + /// /// Returns the for creating a new installation token. /// diff --git a/Octokit/Models/Response/GitHubApp.cs b/Octokit/Models/Response/GitHubApp.cs index f1dbc49c70..d9c817cbb6 100644 --- a/Octokit/Models/Response/GitHubApp.cs +++ b/Octokit/Models/Response/GitHubApp.cs @@ -13,10 +13,11 @@ public class GitHubApp { public GitHubApp() { } - public GitHubApp(long id, string slug, string name, User owner, string description, string externalUrl, string htmlUrl, DateTimeOffset createdAt, DateTimeOffset updatedAt, InstallationPermissions permissions, IReadOnlyList events) + public GitHubApp(long id, string slug, string nodeId, string name, User owner, string description, string externalUrl, string htmlUrl, DateTimeOffset createdAt, DateTimeOffset updatedAt, InstallationPermissions permissions, IReadOnlyList events) { Id = id; Slug = slug; + NodeId = nodeId; Name = name; Owner = owner; Description = description; @@ -31,57 +32,62 @@ public GitHubApp(long id, string slug, string name, User owner, string descripti /// /// The Id of the GitHub App. /// - public long Id { get; private set; } + public long Id { get; protected set; } /// /// The url-friendly version of the GitHub App name. /// - public string Slug { get; private set; } + public string Slug { get; protected set; } + + /// + /// GraphQL Node Id + /// + public string NodeId { get; protected set; } /// /// The Name of the GitHub App. /// - public string Name { get; private set; } + public string Name { get; protected set; } /// /// The Owner of the GitHub App. /// - public User Owner { get; private set; } + public User Owner { get; protected set; } /// /// The Description of the GitHub App. /// - public string Description { get; private set; } + public string Description { get; protected set; } /// /// The URL to the GitHub App's external website. /// - public string ExternalUrl { get; private set; } + public string ExternalUrl { get; protected set; } /// /// The URL to view the GitHub App on GitHub. /// - public string HtmlUrl { get; private set; } + public string HtmlUrl { get; protected set; } /// /// Date the GitHub App was created. /// - public DateTimeOffset CreatedAt { get; private set; } + public DateTimeOffset CreatedAt { get; protected set; } /// /// Date the GitHub App was last updated. /// - public DateTimeOffset UpdatedAt { get; private set; } + public DateTimeOffset UpdatedAt { get; protected set; } /// /// The Permissions granted to the Installation /// - public InstallationPermissions Permissions { get; private set; } + public InstallationPermissions Permissions { get; protected set; } /// /// The Events subscribed to by the Installation /// - public IReadOnlyList Events { get; private set; } + public IReadOnlyList Events { get; protected set; } internal string DebuggerDisplay { diff --git a/Octokit/Models/Response/GitHubAppFromManifest.cs b/Octokit/Models/Response/GitHubAppFromManifest.cs new file mode 100644 index 0000000000..8783d90fc8 --- /dev/null +++ b/Octokit/Models/Response/GitHubAppFromManifest.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Octokit +{ + /// + /// Represents a GitHub application from a manifest. + /// https://docs.github.com/rest/apps/apps#create-a-github-app-from-a-manifest + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class GitHubAppFromManifest : GitHubApp + { + public GitHubAppFromManifest() { } + + public GitHubAppFromManifest(long id, string slug, string nodeId, string name, User owner, string description, string externalUrl, string htmlUrl, DateTimeOffset createdAt, DateTimeOffset updatedAt, InstallationPermissions permissions, IReadOnlyList events, string clientId, string clientSecret, string webhookSecret, string pem) + : base(id, slug, nodeId, name, owner, description, externalUrl, htmlUrl, createdAt, updatedAt, permissions, events) + { + ClientId = clientId; + ClientSecret = clientSecret; + WebhookSecret = webhookSecret; + Pem = pem; + } + + /// + /// The Client Id of the GitHub App. + /// + public string ClientId { get; private set; } + + /// + /// The Client Secret of the GitHub App. + /// + public string ClientSecret { get; private set; } + + /// + /// The Webhook Secret of the GitHub App. + /// + public string WebhookSecret { get; private set; } + + /// + /// The PEM of the GitHub App. + /// + public string Pem { get; private set; } + } +} diff --git a/Octokit/Models/Response/InstallationPermissions.cs b/Octokit/Models/Response/InstallationPermissions.cs index 5e4baf3803..bdd8fdceee 100644 --- a/Octokit/Models/Response/InstallationPermissions.cs +++ b/Octokit/Models/Response/InstallationPermissions.cs @@ -24,6 +24,7 @@ public InstallationPermissions InstallationReadWritePermissionLevel? pages, InstallationReadWritePermissionLevel? pullRequests, InstallationReadWritePermissionLevel? repositoryAnnouncementBanners, + InstallationReadWritePermissionLevel? repositoryCustomProperties, InstallationReadWritePermissionLevel? repositoryHooks, InstallationReadWriteAdminPermissionLevel? repositoryProjects, InstallationReadWritePermissionLevel? secretScanningAlerts, @@ -35,6 +36,8 @@ public InstallationPermissions InstallationWritePermissionLevel? workflows, InstallationReadWritePermissionLevel? members, InstallationReadWritePermissionLevel? organizationAdministration, + InstallationReadWritePermissionLevel? organizationCopilotSeatManagement, + InstallationReadWriteAdminPermissionLevel? organizationCustomProperties, InstallationReadWritePermissionLevel? organizationCustomRoles, InstallationReadWritePermissionLevel? organizationAnnouncementBanners, InstallationReadWritePermissionLevel? organizationHooks, @@ -59,6 +62,7 @@ public InstallationPermissions Pages = pages; PullRequests = pullRequests; RepositoryAnnouncementBanners = repositoryAnnouncementBanners; + RepositoryCustomProperties = repositoryCustomProperties; RepositoryHooks = repositoryHooks; RepositoryProjects = repositoryProjects; SecretScanningAlerts = secretScanningAlerts; @@ -70,6 +74,8 @@ public InstallationPermissions Workflows = workflows; Members = members; OrganizationAdministration = organizationAdministration; + OrganizationCopilotSeatManagement = organizationCopilotSeatManagement; + OrganizationCustomProperties = organizationCustomProperties; OrganizationCustomRoles = organizationCustomRoles; OrganizationAnnouncementBanners = organizationAnnouncementBanners; OrganizationHooks = organizationHooks; @@ -142,6 +148,11 @@ public InstallationPermissions /// public StringEnum? RepositoryAnnouncementBanners { get; private set; } + /// + /// The level of permission to grant the access token to view and set values for a repository's custom properties, when allowed by the property. + /// + public StringEnum? RepositoryCustomProperties { get; private set; } + /// /// The level of permission to grant the access token to manage the post-receive hooks for a repository. /// @@ -197,6 +208,16 @@ public InstallationPermissions /// public StringEnum? OrganizationAdministration { get; private set; } + /// + /// The level of permission to grant the access token to manage access Copilot Business seats and settings. + /// + public StringEnum? OrganizationCopilotSeatManagement { get; private set; } + + /// + /// The level of permission to grant the access token to view custom properties, write repository values, and administer definitions. + /// + public StringEnum? OrganizationCustomProperties { get; private set; } + /// /// The level of permission to grant the access token for custom roles management. This property is in beta and is subject to change. ///