Skip to content

Commit

Permalink
[feat]: Implement Actions OIDC Client (#2828)
Browse files Browse the repository at this point in the history
implement actions OIDC client

Co-authored-by: Nick Floyd <139819+nickfloyd@users.noreply.github.com>
  • Loading branch information
SlyckLizzie and nickfloyd authored Jan 2, 2024
1 parent a2a4f09 commit f9c5b69
Show file tree
Hide file tree
Showing 15 changed files with 626 additions and 2 deletions.
5 changes: 5 additions & 0 deletions Octokit.Reactive/Clients/IObservableActionsClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ public interface IObservableActionsClient
/// </summary>
IObservableActionsCacheClient Cache { get; }

/// <summary>
/// Client for the OIDC API.
/// </summary>
IObservableActionsOidcClient Oidc { get; }

/// <summary>
/// Client for the Permissions API.
/// </summary>
Expand Down
58 changes: 58 additions & 0 deletions Octokit.Reactive/Clients/IObservableActionsOidcClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System;
using System.Reactive;
using System.Threading.Tasks;

namespace Octokit.Reactive
{
/// <summary>
/// A client for GitHub's Actions OIDC API.
/// </summary>
/// <remarks>
/// See the <a href="https://developer.github.com/v3/actions/oidc/">Actions OIDC API documentation</a> for more information.
/// </remarks>
public interface IObservableActionsOidcClient
{
/// <summary>
/// Get the customization template for an OIDC subject claim for an organization.
/// </summary>
/// <remarks>
/// https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#get-the-customization-template-for-an-oidc-subject-claim-for-an-organization
/// </remarks>
/// <param name="organization">The organization name.</param>
IObservable<OrganizationOidcSubjectClaim> GetOrganizationOidcSubjectClaim(string organization);


/// <summary>
/// Set the customization template for an OIDC subject claim for an organization.
/// </summary>
/// <remarks>
/// https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#set-the-customization-template-for-an-oidc-subject-claim-for-an-organization
/// </remarks>
/// <param name="organization">The organization name.</param>
/// <param name="oidcSubjectClaim">The OIDC subject claim to set for the organization.</param>
IObservable<Unit> SetOrganizationOidcSubjectClaim(string organization, OrganizationOidcSubjectClaimRequest oidcSubjectClaim);

/// <summary>
/// Get the customization template for an OIDC subject claim for a repository.
/// </summary>
/// <remarks>
/// https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#get-the-customization-template-for-an-oidc-subject-claim-for-a-repository
/// </remarks>
/// <param name="owner">The account owner of the repository.</param>
/// <param name="repository">The name of the repository.</param>
/// <returns></returns>
IObservable<RepositoryOidcSubjectClaim> GetRepositoryOidcSubjectClaim(string owner, string repository);

/// <summary>
///
/// </summary>
/// <remarks>
/// https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#set-the-customization-template-for-an-oidc-subject-claim-for-a-repository
/// </remarks>
/// <param name="owner">The account owner of the repository.</param>
/// <param name="repository">The name of the repository.</param>
/// <param name="oidcSubjectClaim">The OIDC subject claim to set for the repository.</param>
/// <returns></returns>
IObservable<Unit> SetRepositoryOidcSubjectClaim(string owner, string repository, RepositoryOidcSubjectClaimRequest oidcSubjectClaim);
}
}
7 changes: 7 additions & 0 deletions Octokit.Reactive/Clients/ObservableActionsClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public ObservableActionsClient(IGitHubClient client)

Artifacts = new ObservableActionsArtifactsClient(client);
Cache = new ObservableActionsCacheClient(client);
Oidc = new ObservableActionsOidcClient(client);
Permissions = new ObservableActionsPermissionsClient(client);
SelfHostedRunnerGroups = new ObservableActionsSelfHostedRunnerGroupsClient(client);
SelfHostedRunners = new ObservableActionsSelfHostedRunnersClient(client);
Expand All @@ -34,6 +35,12 @@ public ObservableActionsClient(IGitHubClient client)
/// </summary>
public IObservableActionsCacheClient Cache { get; private set; }


/// <summary>
/// Client for the OIDC API.
/// </summary>
public IObservableActionsOidcClient Oidc { get; private set; }

/// <summary>
/// Client for the Permissions API.
/// </summary>
Expand Down
66 changes: 66 additions & 0 deletions Octokit.Reactive/Clients/ObservableActionsOidcClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using System.Reactive;
using System.Reactive.Threading.Tasks;

namespace Octokit.Reactive
{

/// <summary>
/// A client for GitHub's Actions OIDC API.
/// </summary>
/// <remarks>
/// See the <a href="https://developer.github.com/v3/actions/oidc/">Actions OIDC API documentation</a> for more information.
/// </remarks>
public class ObservableActionsOidcClient : IObservableActionsOidcClient
{
readonly IActionsOidcClient _client;


/// <summary>
/// Initializes a new GitHub Actions OIDC API client
/// </summary>
/// <param name="client">A GitHub client.</param>
public ObservableActionsOidcClient(IGitHubClient client)
{
Ensure.ArgumentNotNull(client, nameof(client));

_client = client.Actions.Oidc;
}


/// <inheritdoc/>
public IObservable<OrganizationOidcSubjectClaim> GetOrganizationOidcSubjectClaim(string organization)
{
Ensure.ArgumentNotNullOrEmptyString(organization, nameof(organization));
return _client.GetOrganizationOidcSubjectClaim(organization).ToObservable();
}

/// <inheritdoc/>
public IObservable<Unit> SetOrganizationOidcSubjectClaim(string organization, OrganizationOidcSubjectClaimRequest oidcSubjectClaim)
{
Ensure.ArgumentNotNullOrEmptyString(organization, nameof(organization));
Ensure.ArgumentNotNull(oidcSubjectClaim, nameof(oidcSubjectClaim));

return _client.SetOrganizationOidcSubjectClaim(organization, oidcSubjectClaim).ToObservable();
}

/// <inheritdoc/>
public IObservable<RepositoryOidcSubjectClaim> GetRepositoryOidcSubjectClaim(string owner, string repository)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repository, nameof(repository));

return _client.GetRepositoryOidcSubjectClaim(owner, repository).ToObservable();
}

/// <inheritdoc/>
public IObservable<Unit> SetRepositoryOidcSubjectClaim(string owner, string repository, RepositoryOidcSubjectClaimRequest oidcSubjectClaim)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repository, nameof(repository));
Ensure.ArgumentNotNull(oidcSubjectClaim, nameof(oidcSubjectClaim));

return _client.SetRepositoryOidcSubjectClaim(owner, repository, oidcSubjectClaim).ToObservable();
}
}
}
165 changes: 165 additions & 0 deletions Octokit.Tests/Clients/ActionsOidcClientTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
using NSubstitute;
using Octokit.Clients;
using System;
using System.Threading.Tasks;
using Xunit;


namespace Octokit.Tests.Clients
{
public class ActionsOidcClientTests
{
public class TheCtor
{
[Fact]
public void EnsuresNonNullArguments()
{
Assert.Throws<ArgumentNullException>(() => new ActionsOidcClient(null));
}
}

public class GetOrganizationOidcSubjectClaim_Method
{
[Fact]
public async Task RequestsCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new ActionsOidcClient(connection);

await client.GetOrganizationOidcSubjectClaim("fake");

connection.Received().Get<OrganizationOidcSubjectClaim>(
Arg.Is<Uri>(u => u.ToString() == "orgs/fake/actions/oidc/customization/sub"));
}

[Fact]
public async Task EnsuresNonNullArguments()
{
var connection = Substitute.For<IApiConnection>();
var client = new ActionsOidcClient(connection);

await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetOrganizationOidcSubjectClaim(null));
}

[Fact]
public async Task EnsuresNonEmptyArguments()
{
var connection = Substitute.For<IApiConnection>();
var client = new ActionsOidcClient(connection);

await Assert.ThrowsAsync<ArgumentException>(() => client.GetOrganizationOidcSubjectClaim(""));
}
}

public class SetOrganizationOidcSubjectClaim_Method
{
[Fact]
public async Task RequestsCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new ActionsOidcClient(connection);
var newClaims = new OrganizationOidcSubjectClaimRequest(new System.Collections.Generic.List<string> { "fake" });

await client.SetOrganizationOidcSubjectClaim("fake", newClaims);

connection.Received().Put(
Arg.Is<Uri>(u => u.ToString() == "orgs/fake/actions/oidc/customization/sub"), newClaims);
}

[Fact]
public async Task EnsuresNonNullArguments()
{
var connection = Substitute.For<IApiConnection>();
var client = new ActionsOidcClient(connection);
var newClaims = new OrganizationOidcSubjectClaimRequest(new System.Collections.Generic.List<string> { "fake" });

await Assert.ThrowsAsync<ArgumentNullException>(() => client.SetOrganizationOidcSubjectClaim(null, newClaims));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.SetOrganizationOidcSubjectClaim("fake", null));
}

[Fact]
public async Task EnsuresNonEmptyArguments()
{
var connection = Substitute.For<IApiConnection>();
var client = new ActionsOidcClient(connection);
var newClaims = new OrganizationOidcSubjectClaimRequest(new System.Collections.Generic.List<string> { "fake" });

await Assert.ThrowsAsync<ArgumentException>(() => client.SetOrganizationOidcSubjectClaim("", newClaims));
}
}

public class GetRepositoryOidcSubjectClaim_Method
{
[Fact]
public async Task RequestsCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new ActionsOidcClient(connection);

await client.GetRepositoryOidcSubjectClaim("fake", "abc");

connection.Received().Get<RepositoryOidcSubjectClaim>(
Arg.Is<Uri>(u => u.ToString() == "repos/fake/abc/actions/oidc/customization/sub"));
}

[Fact]
public async Task EnsuresNonNullArguments()
{
var connection = Substitute.For<IApiConnection>();
var client = new ActionsOidcClient(connection);

await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetRepositoryOidcSubjectClaim(null, "repo"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetRepositoryOidcSubjectClaim("owner", null));
}

[Fact]
public async Task EnsuresNonEmptyArguments()
{
var connection = Substitute.For<IApiConnection>();
var client = new ActionsOidcClient(connection);

await Assert.ThrowsAsync<ArgumentException>(() => client.GetRepositoryOidcSubjectClaim("", "repo"));
await Assert.ThrowsAsync<ArgumentException>(() => client.GetRepositoryOidcSubjectClaim("owner", ""));
}
}

public class SetRepositoryOidcSubjectClaim_Method
{
[Fact]
public async Task RequestsCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new ActionsOidcClient(connection);
var newClaims = new RepositoryOidcSubjectClaimRequest(false, new System.Collections.Generic.List<string> { "fake" });

await client.SetRepositoryOidcSubjectClaim("fake", "abc", newClaims);

connection.Received().Put(
Arg.Is<Uri>(u => u.ToString() == "repos/fake/abc/actions/oidc/customization/sub"), newClaims);
}

[Fact]
public async Task EnsuresNonNullArguments()
{
var connection = Substitute.For<IApiConnection>();
var client = new ActionsOidcClient(connection);
var newClaims = new RepositoryOidcSubjectClaimRequest(false, new System.Collections.Generic.List<string> { "fake" });

await Assert.ThrowsAsync<ArgumentNullException>(() => client.SetRepositoryOidcSubjectClaim(null, "repo", newClaims));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.SetRepositoryOidcSubjectClaim("owner", null, newClaims));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.SetRepositoryOidcSubjectClaim("owner", "repo", null));
}

[Fact]
public async Task EnsuresNonEmptyArguments()
{
var connection = Substitute.For<IApiConnection>();
var client = new ActionsOidcClient(connection);
var newClaims = new RepositoryOidcSubjectClaimRequest(false, new System.Collections.Generic.List<string> { "fake" });

await Assert.ThrowsAsync<ArgumentException>(() => client.SetRepositoryOidcSubjectClaim("", "repo", newClaims));
await Assert.ThrowsAsync<ArgumentException>(() => client.SetRepositoryOidcSubjectClaim("owner", "", newClaims));
}
}
}
}
10 changes: 9 additions & 1 deletion Octokit/Clients/ActionsClient.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Octokit
using Octokit.Clients;

namespace Octokit
{
/// <summary>
/// A client for GitHub's Actions API.
Expand All @@ -17,6 +19,7 @@ public ActionsClient(IApiConnection apiConnection)
{
Artifacts = new ActionsArtifactsClient(apiConnection);
Cache = new ActionsCacheClient(apiConnection);
Oidc = new ActionsOidcClient(apiConnection);
Permissions = new ActionsPermissionsClient(apiConnection);
SelfHostedRunnerGroups = new ActionsSelfHostedRunnerGroupsClient(apiConnection);
SelfHostedRunners = new ActionsSelfHostedRunnersClient(apiConnection);
Expand All @@ -33,6 +36,11 @@ public ActionsClient(IApiConnection apiConnection)
/// </summary>
public IActionsCacheClient Cache { get; private set; }

/// <summary>
/// Client for the OIDC API.
/// </summary>
public IActionsOidcClient Oidc { get; private set; }

/// <summary>
/// Client for the Permissions API.
/// </summary>
Expand Down
Loading

0 comments on commit f9c5b69

Please sign in to comment.