mirror of
https://dev.azure.com/effectory/Survey%20Software/_git/Cloud%20Engineering
synced 2026-02-27 18:52:18 +01:00
Merged PR 63702: Add Sonar Client to update permissions and tags in Sonar Projects to new team structure
Add Sonar Client to update permissions and tags in Sonar Projects to new team structure Related work items: #125680
This commit is contained in:
@@ -1,15 +1,14 @@
|
||||
namespace SnykRestApi.Models.Parsed
|
||||
namespace SnykRestApi.Models.Parsed;
|
||||
|
||||
public class AuditLog
|
||||
{
|
||||
public class AuditLog
|
||||
{
|
||||
public string GroupId { get; set; }
|
||||
public string OrganizationId { get; set; }
|
||||
public string OrganizationName { get; set; }
|
||||
public string UserId { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string ProjectId { get; set; }
|
||||
public string ProjectName { get; set; }
|
||||
public string Event { get; set; }
|
||||
public DateTime Created { get; set; }
|
||||
}
|
||||
}
|
||||
public string GroupId { get; set; }
|
||||
public string OrganizationId { get; set; }
|
||||
public string OrganizationName { get; set; }
|
||||
public string UserId { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string ProjectId { get; set; }
|
||||
public string ProjectName { get; set; }
|
||||
public string Event { get; set; }
|
||||
public DateTime Created { get; set; }
|
||||
}
|
||||
@@ -1,24 +1,23 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SnykRestApi.Models.Raw
|
||||
namespace SnykRestApi.Models.Raw;
|
||||
|
||||
internal class AuditLogResponse
|
||||
{
|
||||
internal class AuditLogResponse
|
||||
{
|
||||
[JsonPropertyName("groupId")]
|
||||
public string GroupId { get; set; }
|
||||
[JsonPropertyName("orgId")]
|
||||
public string OrgId { get; set; }
|
||||
[JsonPropertyName("userId")]
|
||||
public string UserId { get; set; }
|
||||
[JsonPropertyName("projectId")]
|
||||
public string ProjectId { get; set; }
|
||||
[JsonPropertyName("event")]
|
||||
public string Event { get; set; }
|
||||
//[JsonPropertyName("content")]
|
||||
//public string Content { get; set; }
|
||||
[JsonPropertyName("created")]
|
||||
public DateTime Created { get; set; }
|
||||
[JsonPropertyName("groupId")]
|
||||
public string GroupId { get; set; }
|
||||
[JsonPropertyName("orgId")]
|
||||
public string OrgId { get; set; }
|
||||
[JsonPropertyName("userId")]
|
||||
public string UserId { get; set; }
|
||||
[JsonPropertyName("projectId")]
|
||||
public string ProjectId { get; set; }
|
||||
[JsonPropertyName("event")]
|
||||
public string Event { get; set; }
|
||||
//[JsonPropertyName("content")]
|
||||
//public string Content { get; set; }
|
||||
[JsonPropertyName("created")]
|
||||
public DateTime Created { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SnykRestApi.Models.Raw
|
||||
{
|
||||
internal class GroupResponse
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; }
|
||||
namespace SnykRestApi.Models.Raw;
|
||||
|
||||
}
|
||||
}
|
||||
internal class GroupResponse
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SnykRestApi.Models.Raw
|
||||
namespace SnykRestApi.Models.Raw;
|
||||
|
||||
internal class OrganizationListResponse
|
||||
{
|
||||
internal class OrganizationListResponse
|
||||
{
|
||||
[JsonPropertyName("orgs")]
|
||||
public List<OrganizationResponse> Orgs { get; set; }
|
||||
}
|
||||
}
|
||||
[JsonPropertyName("orgs")]
|
||||
public List<OrganizationResponse> Orgs { get; set; }
|
||||
}
|
||||
@@ -1,19 +1,18 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SnykRestApi.Models.Raw
|
||||
{
|
||||
internal class OrganizationResponse
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; }
|
||||
[JsonPropertyName("slug")]
|
||||
public string Slug { get; set; }
|
||||
[JsonPropertyName("url")]
|
||||
public string Url { get; set; }
|
||||
[JsonPropertyName("group")]
|
||||
public GroupResponse Group { get; set; }
|
||||
namespace SnykRestApi.Models.Raw;
|
||||
|
||||
}
|
||||
}
|
||||
internal class OrganizationResponse
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; }
|
||||
[JsonPropertyName("slug")]
|
||||
public string Slug { get; set; }
|
||||
[JsonPropertyName("url")]
|
||||
public string Url { get; set; }
|
||||
[JsonPropertyName("group")]
|
||||
public GroupResponse Group { get; set; }
|
||||
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SnykRestApi.Models.Raw
|
||||
namespace SnykRestApi.Models.Raw;
|
||||
|
||||
internal class ProjectListResponse
|
||||
{
|
||||
internal class ProjectListResponse
|
||||
{
|
||||
[JsonPropertyName("org")]
|
||||
public OrganizationResponse Org { get; set; }
|
||||
[JsonPropertyName("projects")]
|
||||
public List<ProjectResponse> Projects { get; set; }
|
||||
}
|
||||
}
|
||||
[JsonPropertyName("org")]
|
||||
public OrganizationResponse Org { get; set; }
|
||||
[JsonPropertyName("projects")]
|
||||
public List<ProjectResponse> Projects { get; set; }
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SnykRestApi.Models.Raw
|
||||
namespace SnykRestApi.Models.Raw;
|
||||
|
||||
internal class ProjectResponse
|
||||
{
|
||||
internal class ProjectResponse
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
}
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SnykRestApi.Models.Raw
|
||||
{
|
||||
internal class UserResponse
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; }
|
||||
[JsonPropertyName("username")]
|
||||
public string UserName { get; set; }
|
||||
[JsonPropertyName("email")]
|
||||
public string Email { get; set; }
|
||||
namespace SnykRestApi.Models.Raw;
|
||||
|
||||
}
|
||||
}
|
||||
internal class UserResponse
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; }
|
||||
[JsonPropertyName("username")]
|
||||
public string UserName { get; set; }
|
||||
[JsonPropertyName("email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
namespace SnykRestApi.Models
|
||||
{
|
||||
public class Settings
|
||||
{
|
||||
public string KeyVaultName { get; set; } = string.Empty;
|
||||
public string CsvFolder { get; set; } = string.Empty;
|
||||
public string SnykBaseUrl { get; set; } = string.Empty;
|
||||
namespace SnykRestApi.Models;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
public class Settings
|
||||
{
|
||||
public string KeyVaultName { get; set; } = string.Empty;
|
||||
public string CsvFolder { get; set; } = string.Empty;
|
||||
public string SnykBaseUrl { get; set; } = string.Empty;
|
||||
|
||||
|
||||
}
|
||||
@@ -5,36 +5,35 @@ using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace SnykRestApi
|
||||
namespace SnykRestApi;
|
||||
|
||||
class Program
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static Task Main(string[] args) =>
|
||||
CreateHostBuilder(args).Build().RunAsync();
|
||||
static Task Main(string[] args) =>
|
||||
CreateHostBuilder(args).Build().RunAsync();
|
||||
|
||||
static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureServices((builder, services) =>
|
||||
{
|
||||
IConfiguration config = new ConfigurationBuilder()
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddEnvironmentVariables()
|
||||
.Build();
|
||||
static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureServices((builder, services) =>
|
||||
{
|
||||
IConfiguration config = new ConfigurationBuilder()
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddEnvironmentVariables()
|
||||
.Build();
|
||||
|
||||
Settings settings = config.GetRequiredSection("Settings").Get<Settings>();
|
||||
Settings settings = config.GetRequiredSection("Settings").Get<Settings>();
|
||||
|
||||
services.AddSingleton<AccessTokenRepository>();
|
||||
services.AddSingleton(settings);
|
||||
services.AddSingleton<AccessTokenRepository>();
|
||||
services.AddSingleton(settings);
|
||||
|
||||
services.AddHttpClient<OrganizationRepository>();
|
||||
services.AddHttpClient<AuditLogRepository>();
|
||||
services.AddHttpClient<ProjectRepository>();
|
||||
services.AddHttpClient<UserRepository>();
|
||||
services.AddTransient<CsvRepository>();
|
||||
services.AddHttpClient<OrganizationRepository>();
|
||||
services.AddHttpClient<AuditLogRepository>();
|
||||
services.AddHttpClient<ProjectRepository>();
|
||||
services.AddHttpClient<UserRepository>();
|
||||
services.AddTransient<CsvRepository>();
|
||||
|
||||
services.AddScoped<AuditLogService>();
|
||||
services.AddScoped<AuditLogService>();
|
||||
|
||||
services.AddHostedService<OptionService>();
|
||||
});
|
||||
}
|
||||
services.AddHostedService<OptionService>();
|
||||
});
|
||||
}
|
||||
@@ -2,28 +2,21 @@
|
||||
using Azure.Security.KeyVault.Secrets;
|
||||
using SnykRestApi.Models;
|
||||
|
||||
namespace SnykRestApi.Repositories
|
||||
namespace SnykRestApi.Repositories;
|
||||
|
||||
public class AccessTokenRepository(Settings settings)
|
||||
{
|
||||
public class AccessTokenRepository
|
||||
private string? _authorizationToken = string.Empty;
|
||||
|
||||
public async Task<string> GetAuthorizationToken()
|
||||
{
|
||||
private readonly Settings _settings;
|
||||
private string? _authorizationToken = string.Empty;
|
||||
if (!string.IsNullOrWhiteSpace(_authorizationToken)) return _authorizationToken;
|
||||
|
||||
public AccessTokenRepository(Settings settings)
|
||||
{
|
||||
_settings = settings;
|
||||
}
|
||||
var keyvaultUri = "https://" + settings.KeyVaultName + ".vault.azure.net";
|
||||
var credential = new DefaultAzureCredential();
|
||||
var client = new SecretClient(new Uri(keyvaultUri), credential);
|
||||
_authorizationToken = (await client.GetSecretAsync("SnykKey")).Value.Value;
|
||||
|
||||
public async Task<string> GetAuthorizationToken()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_authorizationToken)) return _authorizationToken;
|
||||
|
||||
var keyvaultUri = "https://" + _settings.KeyVaultName + ".vault.azure.net";
|
||||
var credential = new DefaultAzureCredential();
|
||||
var client = new SecretClient(new Uri(keyvaultUri), credential);
|
||||
_authorizationToken = (await client.GetSecretAsync("SnykKey")).Value.Value;
|
||||
|
||||
return _authorizationToken;
|
||||
}
|
||||
return _authorizationToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,47 +3,35 @@ using SnykRestApi.Models.Raw;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SnykRestApi.Repositories
|
||||
namespace SnykRestApi.Repositories;
|
||||
|
||||
public class AuditLogRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository, Settings settings)
|
||||
{
|
||||
public class AuditLogRepository
|
||||
internal async Task<List<AuditLogResponse>> GetByOrganizationId(string organizationId)
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly AccessTokenRepository _accessTokenRepository;
|
||||
private readonly Settings _settings;
|
||||
var authorizationToken = await accessTokenRepository.GetAuthorizationToken();
|
||||
List<AuditLogResponse> result = [];
|
||||
List<AuditLogResponse> responseItems;
|
||||
|
||||
public AuditLogRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository, Settings settings)
|
||||
var page = 0;
|
||||
|
||||
do
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_accessTokenRepository = accessTokenRepository;
|
||||
_settings = settings;
|
||||
HttpRequestMessage request = new(HttpMethod.Post, $"{settings.SnykBaseUrl}org/{organizationId}/audit?from=2022-07-01&page={++page}");
|
||||
request.Headers.Accept.Clear();
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("token", authorizationToken);
|
||||
|
||||
var response = await httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
responseItems = JsonSerializer.Deserialize<List<AuditLogResponse>>(responseString) ?? new List<AuditLogResponse>();
|
||||
result.AddRange(responseItems);
|
||||
}
|
||||
while (responseItems.Count == 100);
|
||||
|
||||
internal async Task<List<AuditLogResponse>> GetByOrganizationId(string origanizationId)
|
||||
{
|
||||
var authorizationToken = await _accessTokenRepository.GetAuthorizationToken();
|
||||
List<AuditLogResponse> result = new();
|
||||
List<AuditLogResponse> responseItems;
|
||||
|
||||
int page = 0;
|
||||
|
||||
do
|
||||
{
|
||||
HttpRequestMessage request = new(HttpMethod.Post, $"{_settings.SnykBaseUrl}org/{origanizationId}/audit?from=2022-07-01&page={++page}");
|
||||
request.Headers.Accept.Clear();
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("token", authorizationToken);
|
||||
|
||||
var response = await _httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
responseItems = JsonSerializer.Deserialize<List<AuditLogResponse>>(responseString) ?? new List<AuditLogResponse>();
|
||||
result.AddRange(responseItems);
|
||||
}
|
||||
while (responseItems.Count == 100);
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,30 +3,17 @@ using SnykRestApi.Models;
|
||||
using SnykRestApi.Models.Parsed;
|
||||
using System.Globalization;
|
||||
|
||||
namespace SnykRestApi.Repositories
|
||||
namespace SnykRestApi.Repositories;
|
||||
|
||||
public class CsvRepository(Settings settings)
|
||||
{
|
||||
public class CsvRepository
|
||||
public async Task WriteAll (List<AuditLog> log)
|
||||
{
|
||||
private readonly Settings _settings;
|
||||
var t = DateTime.Now;
|
||||
var fileName = $"{settings.CsvFolder}SnykAuditLog_{t:yyyy}{t:MM}{t:dd}_{t:HH}{t:mm}{t:ss}_{t:FFF}.csv";
|
||||
|
||||
public CsvRepository(Settings settings)
|
||||
{
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
public async Task WriteAll (List<AuditLog> log)
|
||||
{
|
||||
var t = DateTime.Now;
|
||||
var fileName = $"{_settings.CsvFolder}SnykAuditLog_{t:yyyy}{t:MM}{t:dd}_{t:HH}{t:mm}{t:ss}_{t:FFF}.csv";
|
||||
|
||||
using (var writer = new StreamWriter(fileName))
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
await csv.WriteRecordsAsync(log);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
await using var writer = new StreamWriter(fileName);
|
||||
await using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
|
||||
await csv.WriteRecordsAsync(log);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,38 +3,26 @@ using SnykRestApi.Models.Raw;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SnykRestApi.Repositories
|
||||
namespace SnykRestApi.Repositories;
|
||||
|
||||
public class OrganizationRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository, Settings settings)
|
||||
{
|
||||
public class OrganizationRepository
|
||||
internal async Task<List<OrganizationResponse>> GetAll()
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly AccessTokenRepository _accessTokenRepository;
|
||||
private readonly Settings _settings;
|
||||
var authorizationToken = await accessTokenRepository.GetAuthorizationToken();
|
||||
|
||||
public OrganizationRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository, Settings settings)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_accessTokenRepository = accessTokenRepository;
|
||||
_settings = settings;
|
||||
}
|
||||
var uri = $"{settings.SnykBaseUrl}orgs";
|
||||
HttpRequestMessage request = new(HttpMethod.Get, uri);
|
||||
request.Headers.Accept.Clear();
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("token", authorizationToken);
|
||||
|
||||
internal async Task<List<OrganizationResponse>> GetAll()
|
||||
{
|
||||
var authorizationToken = await _accessTokenRepository.GetAuthorizationToken();
|
||||
var response = await httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
|
||||
var uri = $"{_settings.SnykBaseUrl}orgs";
|
||||
HttpRequestMessage request = new(HttpMethod.Get, uri);
|
||||
request.Headers.Accept.Clear();
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("token", authorizationToken);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var response = await _httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var result = JsonSerializer.Deserialize<OrganizationListResponse>(responseString)?.Orgs;
|
||||
return result ?? new List<OrganizationResponse>();
|
||||
}
|
||||
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var result = JsonSerializer.Deserialize<OrganizationListResponse>(responseString)?.Orgs;
|
||||
return result ?? [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,38 +3,26 @@ using SnykRestApi.Models.Raw;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SnykRestApi.Repositories
|
||||
namespace SnykRestApi.Repositories;
|
||||
|
||||
public class ProjectRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository, Settings settings)
|
||||
{
|
||||
public class ProjectRepository
|
||||
internal async Task<List<ProjectResponse>> GetAll(string organizationId)
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly AccessTokenRepository _accessTokenRepository;
|
||||
private readonly Settings _settings;
|
||||
var authorizationToken = await accessTokenRepository.GetAuthorizationToken();
|
||||
|
||||
public ProjectRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository, Settings settings)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_accessTokenRepository = accessTokenRepository;
|
||||
_settings = settings;
|
||||
}
|
||||
var uri = $"{settings.SnykBaseUrl}org/{organizationId}/projects";
|
||||
HttpRequestMessage request = new(HttpMethod.Post, uri);
|
||||
request.Headers.Accept.Clear();
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("token", authorizationToken);
|
||||
|
||||
internal async Task<List<ProjectResponse>> GetAll(string organizationId)
|
||||
{
|
||||
var authorizationToken = await _accessTokenRepository.GetAuthorizationToken();
|
||||
var response = await httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
|
||||
var uri = $"{_settings.SnykBaseUrl}org/{organizationId}/projects";
|
||||
HttpRequestMessage request = new(HttpMethod.Post, uri);
|
||||
request.Headers.Accept.Clear();
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("token", authorizationToken);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var response = await _httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var result = JsonSerializer.Deserialize<ProjectListResponse>(responseString)?.Projects;
|
||||
return result ?? new List<ProjectResponse>();
|
||||
}
|
||||
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var result = JsonSerializer.Deserialize<ProjectListResponse>(responseString)?.Projects;
|
||||
return result ?? [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,62 +4,49 @@ using Spectre.Console;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SnykRestApi.Repositories
|
||||
namespace SnykRestApi.Repositories;
|
||||
|
||||
public class UserRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository, Settings settings)
|
||||
{
|
||||
public class UserRepository
|
||||
internal async Task<List<UserResponse>> GetAll(List<string> ids)
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly AccessTokenRepository _accessTokenRepository;
|
||||
private readonly Settings _settings;
|
||||
var authorizationToken = await accessTokenRepository.GetAuthorizationToken();
|
||||
List<UserResponse> result = new();
|
||||
|
||||
public UserRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository, Settings settings)
|
||||
foreach (var id in ids)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_accessTokenRepository = accessTokenRepository;
|
||||
_settings = settings;
|
||||
}
|
||||
HttpRequestMessage request = new(HttpMethod.Get, $"{settings.SnykBaseUrl}user/{id}");
|
||||
request.Headers.Accept.Clear();
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("token", authorizationToken);
|
||||
|
||||
internal async Task<List<UserResponse>> GetAll(List<string> ids)
|
||||
{
|
||||
var authorizationToken = await _accessTokenRepository.GetAuthorizationToken();
|
||||
List<UserResponse> result = new();
|
||||
UserResponse? responseItem;
|
||||
var response = await httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
|
||||
foreach (var id in ids)
|
||||
try
|
||||
{
|
||||
HttpRequestMessage request = new(HttpMethod.Get, $"{_settings.SnykBaseUrl}user/{id}");
|
||||
request.Headers.Accept.Clear();
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("token", authorizationToken);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var response = await _httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var responseItem = JsonSerializer.Deserialize<UserResponse>(responseString);
|
||||
|
||||
try
|
||||
if (responseItem != null)
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
responseItem = JsonSerializer.Deserialize<UserResponse>(responseString);
|
||||
|
||||
if (responseItem != null)
|
||||
{
|
||||
result.Add(responseItem);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[red bold]Could not find user with id '{id}'[/]");
|
||||
result.Add(new()
|
||||
{
|
||||
Id = id,
|
||||
Name = "{ Unknown user }",
|
||||
UserName = "{ Unknown user }",
|
||||
Email = "{ Unknown user }"
|
||||
});
|
||||
result.Add(responseItem);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
catch
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[red bold]Could not find user with id '{id}'[/]");
|
||||
result.Add(new()
|
||||
{
|
||||
Id = id,
|
||||
Name = "{ Unknown user }",
|
||||
UserName = "{ Unknown user }",
|
||||
Email = "{ Unknown user }"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,108 +2,96 @@
|
||||
using SnykRestApi.Models.Raw;
|
||||
using SnykRestApi.Repositories;
|
||||
using Spectre.Console;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SnykRestApi.Services
|
||||
namespace SnykRestApi.Services;
|
||||
|
||||
public class AuditLogService(
|
||||
OrganizationRepository organizationRepository,
|
||||
AuditLogRepository auditLogRepository,
|
||||
ProjectRepository projectRepository,
|
||||
UserRepository userRepository,
|
||||
CsvRepository csvRepository)
|
||||
{
|
||||
public class AuditLogService
|
||||
public async Task CreateAuditLog ()
|
||||
{
|
||||
private readonly OrganizationRepository _organizationRepository;
|
||||
private readonly AuditLogRepository _auditLogRepository;
|
||||
private readonly ProjectRepository _projectRepository;
|
||||
private readonly UserRepository _userRepository;
|
||||
private readonly CsvRepository _csvRepository;
|
||||
var rule = new Rule("[skyblue1]Creating Snyk Audit Log CSV[/]");
|
||||
rule.Justification = Justify.Left;
|
||||
rule.Style = Style.Parse("skyblue1");
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
public AuditLogService(OrganizationRepository organizationRepository, AuditLogRepository auditLogRepostitory, ProjectRepository projectRepository, UserRepository userRepository, CsvRepository csvRepository)
|
||||
{
|
||||
_organizationRepository = organizationRepository;
|
||||
_auditLogRepository = auditLogRepostitory;
|
||||
_projectRepository = projectRepository;
|
||||
_userRepository = userRepository;
|
||||
_csvRepository = csvRepository;
|
||||
}
|
||||
await AnsiConsole.Status()
|
||||
.AutoRefresh(true)
|
||||
.Spinner(Spinner.Known.Default)
|
||||
.StartAsync("Retrieving organizations...", async ctx =>
|
||||
{
|
||||
var organizations = await organizationRepository.GetAll();
|
||||
if (organizations == null || !organizations.Any()) throw new Exception("No organizations found");
|
||||
|
||||
public async Task CreateAuditLog ()
|
||||
{
|
||||
var rule = new Rule("[skyblue1]Creating Snyk Audit Log CSV[/]");
|
||||
rule.Alignment = Justify.Left;
|
||||
rule.Style = Style.Parse("skyblue1");
|
||||
AnsiConsole.Write(rule);
|
||||
var log = new List<AuditLogResponse>();
|
||||
var projects = new List<ProjectResponse>();
|
||||
|
||||
await AnsiConsole.Status()
|
||||
.AutoRefresh(true)
|
||||
.Spinner(Spinner.Known.Default)
|
||||
.StartAsync("Retrieving organizations...", async ctx =>
|
||||
foreach (var organization in organizations)
|
||||
{
|
||||
var organizations = await _organizationRepository.GetAll();
|
||||
if (organizations == null || !organizations.Any()) throw new Exception("No organizations found");
|
||||
rule = new Rule($"[skyblue1]{organization.Name}[/]");
|
||||
rule.Justification = Justify.Left;
|
||||
rule.Style = Style.Parse("skyblue1 dim");
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
var log = new List<AuditLogResponse>();
|
||||
var projects = new List<ProjectResponse>();
|
||||
ctx.Status($"Getting the projects for organization '{organization.Name}'");
|
||||
var orgProjects = await projectRepository.GetAll(organization.Id);
|
||||
projects.AddRange(orgProjects);
|
||||
AnsiConsole.WriteLine($"Got {orgProjects.Count} projects.");
|
||||
|
||||
foreach (var organization in organizations)
|
||||
ctx.Status($"Getting the audit log for organization '{organization.Name}'");
|
||||
var orgLogs = await auditLogRepository.GetByOrganizationId(organization.Id);
|
||||
log.AddRange(orgLogs);
|
||||
AnsiConsole.WriteLine($"Got {orgLogs.Count} log records.");
|
||||
}
|
||||
|
||||
rule = new Rule("[skyblue1]Retrieving users[/]")
|
||||
{
|
||||
Justification = Justify.Left,
|
||||
Style = Style.Parse("skyblue1 dim")
|
||||
};
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
ctx.Status($"Getting users");
|
||||
var userIds = log.Select(l => l.UserId).Distinct().ToList();
|
||||
|
||||
var users = await userRepository.GetAll(userIds);
|
||||
AnsiConsole.WriteLine($"Got {users.Count} users of {userIds.Count} user ids.");
|
||||
|
||||
rule = new Rule("[skyblue1]Creating CSV[/]")
|
||||
{
|
||||
Justification = Justify.Left,
|
||||
Style = Style.Parse("skyblue1 dim")
|
||||
};
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
ctx.Status($"Combining all information");
|
||||
var result = (from l in log
|
||||
join o in organizations on l.OrgId equals o.Id into gjO
|
||||
from subO in gjO.DefaultIfEmpty()
|
||||
join u in users on l.UserId equals u.Id into gjU
|
||||
from subU in gjU.DefaultIfEmpty()
|
||||
join p in projects on l.ProjectId equals p.Id into gjP
|
||||
from subP in gjP.DefaultIfEmpty()
|
||||
select new AuditLog
|
||||
{
|
||||
rule = new Rule($"[skyblue1]{organization.Name}[/]");
|
||||
rule.Alignment = Justify.Left;
|
||||
rule.Style = Style.Parse("skyblue1 dim");
|
||||
AnsiConsole.Write(rule);
|
||||
GroupId = l.GroupId,
|
||||
OrganizationId = l.OrgId,
|
||||
OrganizationName = subO?.Name,
|
||||
ProjectId = l.ProjectId,
|
||||
ProjectName = subP?.Name,
|
||||
UserId = l.UserId,
|
||||
UserName = subU?.Name,
|
||||
Event = l.Event,
|
||||
Created = l.Created
|
||||
}).ToList();
|
||||
AnsiConsole.WriteLine($"Prepared {result.Count} lines to export of {log.Count} audit log records.");
|
||||
|
||||
ctx.Status($"Getting the projects for organization '{organization.Name}'");
|
||||
var orgProjects = await _projectRepository.GetAll(organization.Id);
|
||||
projects.AddRange(orgProjects);
|
||||
AnsiConsole.WriteLine($"Got {orgProjects.Count} projects.");
|
||||
|
||||
ctx.Status($"Getting the audit log for organization '{organization.Name}'");
|
||||
var orgLogs = await _auditLogRepository.GetByOrganizationId(organization.Id);
|
||||
log.AddRange(orgLogs);
|
||||
AnsiConsole.WriteLine($"Got {orgLogs.Count} log records.");
|
||||
}
|
||||
|
||||
rule = new Rule($"[skyblue1]Retrieving users[/]");
|
||||
rule.Alignment = Justify.Left;
|
||||
rule.Style = Style.Parse("skyblue1 dim");
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
ctx.Status($"Getting users");
|
||||
var userIds = log.Select(l => l.UserId).Distinct().ToList();
|
||||
|
||||
var users = await _userRepository.GetAll(userIds);
|
||||
AnsiConsole.WriteLine($"Got {users.Count} users of {userIds.Count} user ids.");
|
||||
|
||||
rule = new Rule($"[skyblue1]Creating CSV[/]");
|
||||
rule.Alignment = Justify.Left;
|
||||
rule.Style = Style.Parse("skyblue1 dim");
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
ctx.Status($"Combining all information");
|
||||
var result = (from l in log
|
||||
join o in organizations on l.OrgId equals o.Id into gjO
|
||||
from subO in gjO.DefaultIfEmpty()
|
||||
join u in users on l.UserId equals u.Id into gjU
|
||||
from subU in gjU.DefaultIfEmpty()
|
||||
join p in projects on l.ProjectId equals p.Id into gjP
|
||||
from subP in gjP.DefaultIfEmpty()
|
||||
select new AuditLog()
|
||||
{
|
||||
GroupId = l.GroupId,
|
||||
OrganizationId = l.OrgId,
|
||||
OrganizationName = subO?.Name,
|
||||
ProjectId = l.ProjectId,
|
||||
ProjectName = subP?.Name,
|
||||
UserId = l.UserId,
|
||||
UserName = subU?.Name,
|
||||
Event = l.Event,
|
||||
Created = l.Created
|
||||
}).ToList();
|
||||
AnsiConsole.WriteLine($"Prepared {result.Count} lines to export of {log.Count} audit log records.");
|
||||
|
||||
ctx.Status($"Writing CSV");
|
||||
await _csvRepository.WriteAll(result);
|
||||
});
|
||||
}
|
||||
ctx.Status("Writing CSV");
|
||||
await csvRepository.WriteAll(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,55 +2,47 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace SnykRestApi.Services
|
||||
namespace SnykRestApi.Services;
|
||||
|
||||
public class OptionService(AuditLogService auditLogService)
|
||||
: IHostedService
|
||||
{
|
||||
public class OptionService : IHostedService
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
private readonly ILogger<OptionService> _logger;
|
||||
private readonly AuditLogService _auditLogService;
|
||||
var rule = new Rule("[yellow]Cloud Egineering Console App[/]");
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
public OptionService(ILogger<OptionService> logger, AuditLogService auditLogService)
|
||||
|
||||
Console.WriteLine("-- This couldn't be done in the Snyk UI, so here we are.... ");
|
||||
Console.WriteLine();
|
||||
|
||||
var choices = new[]
|
||||
{
|
||||
_logger = logger;
|
||||
_auditLogService = auditLogService;
|
||||
}
|
||||
"Create Audit log CSV.",
|
||||
"Exit"
|
||||
};
|
||||
var result = AnsiConsole.Prompt(new SelectionPrompt<string>()
|
||||
.Title("Select what you want to do:")
|
||||
.PageSize(10)
|
||||
.MoreChoicesText("[grey](Move up and down to reveal more choices)[/]")
|
||||
.AddChoices(choices));
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
if (result == choices[0])
|
||||
{
|
||||
var rule = new Rule("[yellow]Cloud Egineering Console App[/]");
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
|
||||
Console.WriteLine("-- This couldn't be done in the Snyk UI, so here we are.... ");
|
||||
Console.WriteLine();
|
||||
|
||||
var choices = new[]
|
||||
{
|
||||
"Create Audit log CSV.",
|
||||
"Exit"
|
||||
};
|
||||
var result = AnsiConsole.Prompt(new SelectionPrompt<string>()
|
||||
.Title("Select what you want to do:")
|
||||
.PageSize(10)
|
||||
.MoreChoicesText("[grey](Move up and down to reveal more choices)[/]")
|
||||
.AddChoices(choices));
|
||||
|
||||
if (result == choices[0])
|
||||
{
|
||||
await _auditLogService.CreateAuditLog();
|
||||
}
|
||||
//else if (result == choices[1])
|
||||
//{
|
||||
// // Do something
|
||||
//}
|
||||
|
||||
rule = new Rule("[yellow]Done. Bye.[/]");
|
||||
AnsiConsole.Write(rule);
|
||||
await auditLogService.CreateAuditLog();
|
||||
}
|
||||
//else if (result == choices[1])
|
||||
//{
|
||||
// // Do something
|
||||
//}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
rule = new Rule("[yellow]Done. Bye.[/]");
|
||||
AnsiConsole.Write(rule);
|
||||
}
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -2,21 +2,21 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.Identity" Version="1.6.1" />
|
||||
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.3.0" />
|
||||
<PackageReference Include="CsvHelper" Version="28.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||
<PackageReference Include="Spectre.Console" Version="0.44.0" />
|
||||
<PackageReference Include="Azure.Identity" Version="1.17.0" />
|
||||
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.8.0" />
|
||||
<PackageReference Include="CsvHelper" Version="33.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
|
||||
<PackageReference Include="Spectre.Console" Version="0.53.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user