mirror of
https://dev.azure.com/effectory/Survey%20Software/_git/Cloud%20Engineering
synced 2026-02-27 18:52:18 +01:00
Merged PR 32477: Added Snyk API console app
Added Snyk API console app
This commit is contained in:
26
.vscode/launch.json
vendored
Normal file
26
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||
// Use hover for the description of the existing attributes
|
||||
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||
"name": ".NET Core Launch (console)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/ConsoleApps/AzureRestApi/AzureRestApi/bin/Debug/net6.0/AzureRestApi.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/ConsoleApps/AzureRestApi/AzureRestApi",
|
||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach"
|
||||
}
|
||||
]
|
||||
}
|
||||
41
.vscode/tasks.json
vendored
Normal file
41
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/ConsoleApps/AzureRestApi/AzureRestApi/AzureRestApi.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/ConsoleApps/AzureRestApi/AzureRestApi/AzureRestApi.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "watch",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"watch",
|
||||
"run",
|
||||
"--project",
|
||||
"${workspaceFolder}/ConsoleApps/AzureRestApi/AzureRestApi/AzureRestApi.csproj"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
||||
25
ConsoleApps/SnykRestApi/SnykRestApi.sln
Normal file
25
ConsoleApps/SnykRestApi/SnykRestApi.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32505.173
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SnykRestApi", "SnykRestApi\SnykRestApi.csproj", "{388306F9-E67B-4CD2-9876-ACAC06968015}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{388306F9-E67B-4CD2-9876-ACAC06968015}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{388306F9-E67B-4CD2-9876-ACAC06968015}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{388306F9-E67B-4CD2-9876-ACAC06968015}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{388306F9-E67B-4CD2-9876-ACAC06968015}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {BA8B2157-BFB1-4397-9DED-E4522D895591}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace SnykRestApi.Models.Parsed
|
||||
{
|
||||
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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SnykRestApi.Models.Raw
|
||||
{
|
||||
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; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
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; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SnykRestApi.Models.Raw
|
||||
{
|
||||
internal class OrganizationListResponse
|
||||
{
|
||||
[JsonPropertyName("orgs")]
|
||||
public List<OrganizationResponse> Orgs { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
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; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SnykRestApi.Models.Raw
|
||||
{
|
||||
internal class ProjectListResponse
|
||||
{
|
||||
[JsonPropertyName("org")]
|
||||
public OrganizationResponse Org { get; set; }
|
||||
[JsonPropertyName("projects")]
|
||||
public List<ProjectResponse> Projects { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SnykRestApi.Models.Raw
|
||||
{
|
||||
internal class ProjectResponse
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
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; }
|
||||
|
||||
}
|
||||
}
|
||||
11
ConsoleApps/SnykRestApi/SnykRestApi/Models/Settings.cs
Normal file
11
ConsoleApps/SnykRestApi/SnykRestApi/Models/Settings.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
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;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
40
ConsoleApps/SnykRestApi/SnykRestApi/Program.cs
Normal file
40
ConsoleApps/SnykRestApi/SnykRestApi/Program.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using SnykRestApi.Models;
|
||||
using SnykRestApi.Repositories;
|
||||
using SnykRestApi.Services;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace SnykRestApi
|
||||
{
|
||||
class Program
|
||||
{
|
||||
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();
|
||||
|
||||
Settings settings = config.GetRequiredSection("Settings").Get<Settings>();
|
||||
|
||||
services.AddSingleton<AccessTokenRepository>();
|
||||
services.AddSingleton(settings);
|
||||
|
||||
services.AddHttpClient<OrganizationRepository>();
|
||||
services.AddHttpClient<AuditLogRepository>();
|
||||
services.AddHttpClient<ProjectRepository>();
|
||||
services.AddHttpClient<UserRepository>();
|
||||
services.AddTransient<CsvRepository>();
|
||||
|
||||
services.AddScoped<AuditLogService>();
|
||||
|
||||
services.AddHostedService<OptionService>();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Azure.Identity;
|
||||
using Azure.Security.KeyVault.Secrets;
|
||||
using SnykRestApi.Models;
|
||||
|
||||
namespace SnykRestApi.Repositories
|
||||
{
|
||||
public class AccessTokenRepository
|
||||
{
|
||||
private readonly Settings _settings;
|
||||
private string? _authorizationToken = string.Empty;
|
||||
|
||||
public AccessTokenRepository(Settings settings)
|
||||
{
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using SnykRestApi.Models;
|
||||
using SnykRestApi.Models.Raw;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SnykRestApi.Repositories
|
||||
{
|
||||
public class AuditLogRepository
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly AccessTokenRepository _accessTokenRepository;
|
||||
private readonly Settings _settings;
|
||||
|
||||
public AuditLogRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository, Settings settings)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_accessTokenRepository = accessTokenRepository;
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using CsvHelper;
|
||||
using SnykRestApi.Models;
|
||||
using SnykRestApi.Models.Parsed;
|
||||
using System.Globalization;
|
||||
|
||||
namespace SnykRestApi.Repositories
|
||||
{
|
||||
public class CsvRepository
|
||||
{
|
||||
private readonly Settings _settings;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using SnykRestApi.Models;
|
||||
using SnykRestApi.Models.Raw;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SnykRestApi.Repositories
|
||||
{
|
||||
public class OrganizationRepository
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly AccessTokenRepository _accessTokenRepository;
|
||||
private readonly Settings _settings;
|
||||
|
||||
public OrganizationRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository, Settings settings)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_accessTokenRepository = accessTokenRepository;
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
internal async Task<List<OrganizationResponse>> GetAll()
|
||||
{
|
||||
var authorizationToken = await _accessTokenRepository.GetAuthorizationToken();
|
||||
|
||||
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);
|
||||
|
||||
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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using SnykRestApi.Models;
|
||||
using SnykRestApi.Models.Raw;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SnykRestApi.Repositories
|
||||
{
|
||||
public class ProjectRepository
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly AccessTokenRepository _accessTokenRepository;
|
||||
private readonly Settings _settings;
|
||||
|
||||
public ProjectRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository, Settings settings)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_accessTokenRepository = accessTokenRepository;
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
internal async Task<List<ProjectResponse>> GetAll(string organizationId)
|
||||
{
|
||||
var authorizationToken = await _accessTokenRepository.GetAuthorizationToken();
|
||||
|
||||
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);
|
||||
|
||||
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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using SnykRestApi.Models;
|
||||
using SnykRestApi.Models.Raw;
|
||||
using Spectre.Console;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SnykRestApi.Repositories
|
||||
{
|
||||
public class UserRepository
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly AccessTokenRepository _accessTokenRepository;
|
||||
private readonly Settings _settings;
|
||||
|
||||
public UserRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository, Settings settings)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_accessTokenRepository = accessTokenRepository;
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
internal async Task<List<UserResponse>> GetAll(List<string> ids)
|
||||
{
|
||||
var authorizationToken = await _accessTokenRepository.GetAuthorizationToken();
|
||||
List<UserResponse> result = new();
|
||||
UserResponse? responseItem;
|
||||
|
||||
foreach (var id in ids)
|
||||
{
|
||||
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);
|
||||
|
||||
var response = await _httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
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 }"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
109
ConsoleApps/SnykRestApi/SnykRestApi/Services/AuditLogService.cs
Normal file
109
ConsoleApps/SnykRestApi/SnykRestApi/Services/AuditLogService.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using SnykRestApi.Models.Parsed;
|
||||
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
|
||||
{
|
||||
public class AuditLogService
|
||||
{
|
||||
private readonly OrganizationRepository _organizationRepository;
|
||||
private readonly AuditLogRepository _auditLogRepository;
|
||||
private readonly ProjectRepository _projectRepository;
|
||||
private readonly UserRepository _userRepository;
|
||||
private readonly CsvRepository _csvRepository;
|
||||
|
||||
public AuditLogService(OrganizationRepository organizationRepository, AuditLogRepository auditLogRepostitory, ProjectRepository projectRepository, UserRepository userRepository, CsvRepository csvRepository)
|
||||
{
|
||||
_organizationRepository = organizationRepository;
|
||||
_auditLogRepository = auditLogRepostitory;
|
||||
_projectRepository = projectRepository;
|
||||
_userRepository = userRepository;
|
||||
_csvRepository = csvRepository;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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");
|
||||
|
||||
var log = new List<AuditLogResponse>();
|
||||
var projects = new List<ProjectResponse>();
|
||||
|
||||
foreach (var organization in organizations)
|
||||
{
|
||||
rule = new Rule($"[skyblue1]{organization.Name}[/]");
|
||||
rule.Alignment = Justify.Left;
|
||||
rule.Style = Style.Parse("skyblue1 dim");
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace SnykRestApi.Services
|
||||
{
|
||||
public class OptionService : IHostedService
|
||||
{
|
||||
private readonly ILogger<OptionService> _logger;
|
||||
private readonly AuditLogService _auditLogService;
|
||||
|
||||
public OptionService(ILogger<OptionService> logger, AuditLogService auditLogService)
|
||||
{
|
||||
_logger = logger;
|
||||
_auditLogService = auditLogService;
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
28
ConsoleApps/SnykRestApi/SnykRestApi/SnykRestApi.csproj
Normal file
28
ConsoleApps/SnykRestApi/SnykRestApi/SnykRestApi.csproj
Normal file
@@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.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" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
14
ConsoleApps/SnykRestApi/SnykRestApi/appsettings.json
Normal file
14
ConsoleApps/SnykRestApi/SnykRestApi/appsettings.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"Settings": {
|
||||
"KeyVaultName": "consoleapp",
|
||||
"CsvFolder": "c:\\temp\\",
|
||||
"SnykBaseUrl": "https://api.snyk.io/api/v1/"
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Warning",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "None"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user