Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding in support for enterprise audit logs #2702

Merged
merged 7 commits into from
May 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using Octokit.Models.Request.Enterprise;
using System;
using System.Diagnostics.CodeAnalysis;

namespace Octokit.Reactive
{
/// <summary>
/// A client for GitHub's Enterprise Audit Log API
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log">Enterprise Audit Log API documentation</a> for more information.
///</remarks>
public interface IObservableEnterpriseAuditLogClient
{
/// <summary>
/// Gets GitHub Enterprise Audit Log Entries (must be Site Admin user).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <returns>The <see cref="AuditLogEvent"/> list.</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
IObservable<AuditLogEvent> GetAll(string enterprise);

/// <summary>
/// Gets GitHub Enterprise Audit Log Entries (must be Site Admin user).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <param name="request">Used to filter and sort the list of events returned</param>
/// <returns>The <see cref="AuditLogEvent"/> list.</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
IObservable<AuditLogEvent> GetAll(string enterprise, AuditLogRequest request);

/// <summary>
/// Gets GitHub Enterprise Audit Log Entries (must be Site Admin user).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <param name="auditLogApiOptions">Options for changing the API response</param>
/// <returns>The <see cref="AuditLogEvent"/> list.</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
IObservable<AuditLogEvent> GetAll(string enterprise, AuditLogApiOptions auditLogApiOptions);

/// <summary>
/// Gets GitHub Enterprise Audit Log Entries (must be Site Admin user).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <param name="request">Used to filter and sort the list of events returned</param>
/// <param name="auditLogApiOptions">Options for changing the API response</param>
/// <returns>The <see cref="AuditLogEvent"/> list.</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
IObservable<AuditLogEvent> GetAll(string enterprise, AuditLogRequest request, AuditLogApiOptions auditLogApiOptions);

/// <summary>
/// Gets GitHub Enterprise Audit Log Entries as raw Json (must be Site Admin user).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <returns>The <see cref="AuditLogEvent"/> list.</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
IObservable<object> GetAllJson(string enterprise);

/// <summary>
/// Gets GitHub Enterprise Audit Log Entries as raw Json (must be Site Admin user).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <param name="request">Used to filter and sort the list of events returned</param>
/// <returns>The <see cref="AuditLogEvent"/> list.</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
IObservable<object> GetAllJson(string enterprise, AuditLogRequest request);

/// <summary>
/// Gets GitHub Enterprise Audit Log Entries as raw Json (must be Site Admin user).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <param name="auditLogApiOptions">Options for changing the API response</param>
/// <returns>The <see cref="AuditLogEvent"/> list.</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
IObservable<object> GetAllJson(string enterprise, AuditLogApiOptions auditLogApiOptions);

/// <summary>
/// Gets GitHub Enterprise Audit Log Entries as raw Json (must be Site Admin user).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <param name="request">Used to filter and sort the list of issues returned</param>
/// <param name="auditLogApiOptions">Options for changing the API response</param>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
[ManualRoute("GET", "/enterprise/audit-log")]
IObservable<object> GetAllJson(string enterprise, AuditLogRequest request, AuditLogApiOptions auditLogApiOptions);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ public interface IObservableEnterpriseClient
/// </remarks>
IObservableEnterpriseAdminStatsClient AdminStats { get; }

/// <summary>
/// A client for GitHub's Enterprise Audit Log API
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log">Enterprise Audit Log API documentation</a> for more information.
/// </remarks>
IObservableEnterpriseAuditLogClient AuditLog { get; }

/// <summary>
/// A client for GitHub's Enterprise LDAP API
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
using Octokit.Models.Request.Enterprise;
using Octokit.Reactive.Internal;
using System;
using System.Collections.Generic;
using System.Reactive.Threading.Tasks;
using System.Threading.Tasks;

namespace Octokit.Reactive
{
/// <summary>
/// A client for GitHub's Enterprise Admin Stats API
/// </summary>
/// <remarks>
/// See the <a href="https://developer.github.com/v3/enterprise/admin_stats/">Enterprise Admin Stats API documentation</a> for more information.
///</remarks>
public class ObservableEnterpriseAuditLogClient : IObservableEnterpriseAuditLogClient
{
readonly IConnection _connection;

public ObservableEnterpriseAuditLogClient(IGitHubClient client)
{
Ensure.ArgumentNotNull(client, "client");

_connection = client.Connection;
}

/// <summary>
/// Gets GitHub Enterprise Audit Log Entries (must be Site Admin user). Note: Defaults to 100 entries per page (max count).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <returns>The <see cref="AuditLogEvent"/> list.</returns>
public IObservable<AuditLogEvent> GetAll(string enterprise)
{
Ensure.ArgumentNotNull(enterprise, nameof(enterprise));

return GetAll(enterprise, new AuditLogRequest(), new AuditLogApiOptions());
}

/// <summary>
/// Gets GitHub Enterprise Audit Log Entries (must be Site Admin user). Note: Defaults to 100 entries per page (max count).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <param name="request">Used to filter and sort the list of issues returned</param>
/// <returns>The <see cref="AuditLogEvent"/> list.</returns>
public IObservable<AuditLogEvent> GetAll(string enterprise, AuditLogRequest request)
{
Ensure.ArgumentNotNull(enterprise, nameof(enterprise));
Ensure.ArgumentNotNull(request, nameof(request));

return GetAll(enterprise, request, new AuditLogApiOptions());
}

/// <summary>
/// Gets GitHub Enterprise Audit Log Entries (must be Site Admin user).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <param name="auditLogApiOptions">Options for changing the API response</param>
/// <returns>The <see cref="AuditLogEvent"/> list.</returns>
public IObservable<AuditLogEvent> GetAll(string enterprise, AuditLogApiOptions auditLogApiOptions)
{
Ensure.ArgumentNotNull(enterprise, nameof(enterprise));
Ensure.ArgumentNotNull(auditLogApiOptions, nameof(auditLogApiOptions));

return GetAll(enterprise, new AuditLogRequest(), auditLogApiOptions);
}

/// <summary>
/// Gets GitHub Enterprise Audit Log Entries (must be Site Admin user).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <param name="request">Used to filter and sort the list of events returned</param>
/// <param name="auditLogApiOptions">Options for changing the API response</param>
/// <returns>The <see cref="AuditLogEvent"/> list.</returns>
public IObservable<AuditLogEvent> GetAll(string enterprise, AuditLogRequest request, AuditLogApiOptions auditLogApiOptions)
{
Ensure.ArgumentNotNull(enterprise, nameof(enterprise));

ApiOptionsExtended options = new ApiOptionsExtended()
{
PageSize = auditLogApiOptions.PageSize
};


return _connection.GetAndFlattenAllPages<AuditLogEvent>(ApiUrls.EnterpriseAuditLog(enterprise), request.ToParametersDictionary(), null, options, GeneratePreProcessFunction(auditLogApiOptions, options));
}

/// <summary>
/// Gets GitHub Enterprise Audit Log Entries as raw Json (must be Site Admin user). Note: Defaults to 100 entries per page (max count).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <returns>The <see cref="AuditLogEvent"/> list.</returns>
public IObservable<object> GetAllJson(string enterprise)
{
Ensure.ArgumentNotNull(enterprise, nameof(enterprise));

return GetAllJson(enterprise, new AuditLogRequest(), new AuditLogApiOptions());
}

/// <summary>
/// Gets GitHub Enterprise Audit Log Entries as raw Json (must be Site Admin user). Note: Defaults to 100 entries per page (max count).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <param name="request">Used to filter and sort the list of events returned</param>
/// <returns>The <see cref="AuditLogEvent"/> list.</returns>
public IObservable<object> GetAllJson(string enterprise, AuditLogRequest request)
{
Ensure.ArgumentNotNull(enterprise, nameof(enterprise));

return GetAllJson(enterprise, request, new AuditLogApiOptions());
}

/// <summary>
/// Gets GitHub Enterprise Audit Log Entries as raw Json (must be Site Admin user).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <param name="auditLogApiOptions">Options for changing the API response</param>
/// <returns>The <see cref="AuditLogEvent"/> list.</returns>
public IObservable<object> GetAllJson(string enterprise, AuditLogApiOptions auditLogApiOptions)
{
Ensure.ArgumentNotNull(enterprise, nameof(enterprise));

return GetAllJson(enterprise, new AuditLogRequest(), auditLogApiOptions);
}

/// <summary>
/// Gets GitHub Enterprise Audit Log Entries as raw Json (must be Site Admin user).
/// </summary>
/// <remarks>
/// https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log/#get-the-audit-log-for-an-enterprise
/// </remarks>
/// <param name="enterprise">Name of enterprise</param>
/// <param name="request">Used to filter and sort the list of events returned</param>
/// <param name="auditLogApiOptions">Options for changing the API response</param>
/// <returns>The <see cref="AuditLogEvent"/> list.</returns>
public IObservable<object> GetAllJson(string enterprise, AuditLogRequest request, AuditLogApiOptions auditLogApiOptions)
{
Ensure.ArgumentNotNull(enterprise, nameof(enterprise));

ApiOptionsExtended options = new ApiOptionsExtended()
{
PageSize = auditLogApiOptions.PageSize
};

return _connection.GetAndFlattenAllPages<AuditLogEvent>(ApiUrls.EnterpriseAuditLog(enterprise), request.ToParametersDictionary(), null, options, GeneratePreProcessFunction(auditLogApiOptions, options));
}

private static Func<object, object> GeneratePreProcessFunction(AuditLogApiOptions auditLogApiOptions, ApiOptionsExtended options)
{
Func<object, object> preProcessResponseBody = null;
if (string.IsNullOrEmpty(auditLogApiOptions?.StopWhenFound))
preProcessResponseBody = (r) =>
{
if (r is string body)
r = body.Replace("_document_id", "document_id").Replace("@timestamp", "timestamp");

return r;
};
else
preProcessResponseBody = (r) =>
{
if (r is string body)
{
if (body.Contains(auditLogApiOptions.StopWhenFound))
options.IsDone = true;

r = body.Replace("_document_id", "document_id").Replace("@timestamp", "timestamp");
}
return r;
};

return preProcessResponseBody;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public ObservableEnterpriseClient(IGitHubClient client)
Ensure.ArgumentNotNull(client, nameof(client));

AdminStats = new ObservableEnterpriseAdminStatsClient(client);
AuditLog = new ObservableEnterpriseAuditLogClient(client);
Ldap = new ObservableEnterpriseLdapClient(client);
License = new ObservableEnterpriseLicenseClient(client);
ManagementConsole = new ObservableEnterpriseManagementConsoleClient(client);
Expand All @@ -30,6 +31,14 @@ public ObservableEnterpriseClient(IGitHubClient client)
/// </remarks>
public IObservableEnterpriseAdminStatsClient AdminStats { get; private set; }

/// <summary>
/// A client for GitHub's Enterprise Audit Log API
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/audit-log">Enterprise Audit Log API documentation</a> for more information.
/// </remarks>
public IObservableEnterpriseAuditLogClient AuditLog { get; }

/// <summary>
/// A client for GitHub's Enterprise LDAP API
/// </summary>
Expand Down
25 changes: 25 additions & 0 deletions Octokit.Reactive/Helpers/ConnectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ public static IObservable<T> GetAndFlattenAllPages<T>(this IConnection connectio
});
}

public static IObservable<T> GetAndFlattenAllPages<T>(this IConnection connection, Uri url, IDictionary<string, string> parameters, string accepts, ApiOptions options, Func<object, object> preprocessResponseBody)
{
return GetPagesWithOptionsAndCallback(url, parameters, options, preprocessResponseBody, (pageUrl, pageParams, o, preprocess) =>
{
var passingParameters = Pagination.Setup(parameters, options);
return connection.Get<List<T>>(pageUrl, passingParameters, accepts).ToObservable();
});
}

static IObservable<T> GetPages<T>(Uri uri, IDictionary<string, string> parameters,
Func<Uri, IDictionary<string, string>, IObservable<IApiResponse<List<T>>>> getPageFunc)
{
Expand Down Expand Up @@ -75,5 +84,21 @@ static IObservable<T> GetPagesWithOptions<T>(Uri uri, IDictionary<string, string
.Where(resp => resp != null)
.SelectMany(resp => resp.Body);
}

static IObservable<T> GetPagesWithOptionsAndCallback<T>(Uri uri, IDictionary<string, string> parameters, ApiOptions options, Func<object, object> preprocessResponseBody, Func<Uri, IDictionary<string, string>, ApiOptions, Func<object, object>, IObservable<IApiResponse<List<T>>>> getPageFunc)
{
return getPageFunc(uri, parameters, options, preprocessResponseBody).Expand(resp =>
{
var nextPageUrl = resp.HttpResponse.ApiInfo.GetNextPageUrl();

var shouldContinue = Pagination.ShouldContinue(nextPageUrl, options);

return shouldContinue
? Observable.Defer(() => getPageFunc(nextPageUrl, null, null, preprocessResponseBody))
: Observable.Empty<IApiResponse<List<T>>>();
})
.Where(resp => resp != null)
.SelectMany(resp => resp.Body);
}
}
}
2 changes: 1 addition & 1 deletion Octokit.Reactive/Octokit.Reactive.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
</PropertyGroup>

<ItemGroup>
<Compile Include="..\Octokit\Helpers\Ensure.cs;..\Octokit\Helpers\Pagination.cs" />
<Compile Include="..\Octokit\Helpers\Ensure.cs;..\Octokit\Helpers\Pagination.cs;..\Octokit\Models\Request\Enterprise\ApiOptionsExtended.cs" />
<None Include="app.config" />
</ItemGroup>

Expand Down
Loading