Skip to content

Commit

Permalink
align with the latest changes
Browse files Browse the repository at this point in the history
  • Loading branch information
anmalkov committed Mar 26, 2024
1 parent 1df8bc1 commit 0675926
Show file tree
Hide file tree
Showing 22 changed files with 459 additions and 138 deletions.
8 changes: 4 additions & 4 deletions src/Crisp.Core.Tests/Crisp.Core.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="Open-XML-SDK" Version="2.9.1" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PackageReference Include="xunit" Version="2.7.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<PackageReference Include="coverlet.collector" Version="6.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
2 changes: 1 addition & 1 deletion src/Crisp.Core/Crisp.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<PackageReference Include="ExcelDataReader" Version="3.6.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0" />
<PackageReference Include="Open-XML-SDK" Version="2.9.1" />
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.3" />
</ItemGroup>

</Project>
11 changes: 11 additions & 0 deletions src/Crisp.Core/Models/SecurityBenchmarkControl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Crisp.Core.Models;

public record SecurityBenchmarkControl(
string Id,
string Domain,
string Title,
string? Description,
string? Azure,
string? Aws,
string? Gcp
);
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ public interface ISecurityBenchmarksRepository
{
Task<IEnumerable<string>> GetAllResourceNamesAsync(string rootDirectoryPath);
Task<IEnumerable<SecurityBenchmark>> GetSecurityBenchmarksForResourceAsync(string resourceName, string rootDirectoryPath);
Task<IEnumerable<SecurityBenchmarkControl>> GetSecurityBenchmarkControlsAsync(string rootDirectoryPath);
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public async Task<IEnumerable<SecurityBenchmark>> GetSecurityBenchmarksForResour
return await GetAllSecurityBenchmarksAsync(fileFullName);
}

public Task<IEnumerable<SecurityBenchmarkControl>> GetSecurityBenchmarkControlsAsync(string rootDirectoryPath)
{
throw new NotImplementedException();
}


private static Task<IEnumerable<SecurityBenchmark>> GetAllSecurityBenchmarksAsync(string fileFullName)
{
Expand Down
5 changes: 5 additions & 0 deletions src/Crisp.Core/Repositories/SecurityBenchmarksV2Repository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public async Task<IEnumerable<SecurityBenchmark>> GetSecurityBenchmarksForResour
return await GetAllSecurityBenchmarksAsync(fileFullName);
}

public Task<IEnumerable<SecurityBenchmarkControl>> GetSecurityBenchmarkControlsAsync(string rootDirectoryPath)
{
throw new NotImplementedException();
}


private static Task<IEnumerable<SecurityBenchmark>> GetAllSecurityBenchmarksAsync(string fileFullName)
{
Expand Down
62 changes: 58 additions & 4 deletions src/Crisp.Core/Repositories/SecurityBenchmarksV3Repository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public class SecurityBenchmarksV3Repository : ISecurityBenchmarksRepository
private const string SecurityBaselineVersion = "3";
private const string SecurityBaselineFileSuffix = $"-azure-security-benchmark-v{SecurityBaselineVersion}-latest-security-baseline.xlsx";


public Task<IEnumerable<string>> GetAllResourceNamesAsync(string rootDirectoryPath)
{
return Task.Run<IEnumerable<string>>(() =>
Expand All @@ -37,6 +38,18 @@ public async Task<IEnumerable<SecurityBenchmark>> GetSecurityBenchmarksForResour
return await GetAllSecurityBenchmarksAsync(fileFullName);
}

public async Task<IEnumerable<SecurityBenchmarkControl>> GetSecurityBenchmarkControlsAsync(string rootDirectoryPath)
{
var benchmarkControlsFileName = Path.Combine(rootDirectoryPath, "Microsoft Cloud Security Benchmark", "Microsoft_cloud_security_benchmark_v1.xlsx");
if (!File.Exists(benchmarkControlsFileName))
{
return Enumerable.Empty<SecurityBenchmarkControl>();
}

var benchmarkControls = await GetAllSecurityBenchmarkControlsAsync(benchmarkControlsFileName);
return benchmarkControls;
}


private static Task<IEnumerable<SecurityBenchmark>> GetAllSecurityBenchmarksAsync(string fileFullName)
{
Expand All @@ -47,10 +60,8 @@ private static Task<IEnumerable<SecurityBenchmark>> GetAllSecurityBenchmarksAsyn
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
using var stream = File.Open(fileFullName, FileMode.Open, FileAccess.Read);
using var reader = ExcelReaderFactory.CreateReader(stream);
// Skip the first sheet and move to the second one
reader.NextResult();
// Skip the header row
reader.Read();
reader.NextResult(); // Skip the first sheet and move to the second one
reader.Read(); // Skip the header row
while (reader.Read())
{
var title = reader.GetValue(2)?.ToString();
Expand Down Expand Up @@ -89,6 +100,49 @@ private static Task<IEnumerable<SecurityBenchmark>> GetAllSecurityBenchmarksAsyn
});
}

private static Task<IEnumerable<SecurityBenchmarkControl>> GetAllSecurityBenchmarkControlsAsync(string fileFullName)
{
return Task.Run<IEnumerable<SecurityBenchmarkControl>>(() => {
var controls = new List<SecurityBenchmarkControl>();
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); // Register the code pages to support ExcelDataReader on non-Windows systems
using var stream = File.Open(fileFullName, FileMode.Open, FileAccess.Read);
using var reader = ExcelReaderFactory.CreateReader(stream);
reader.NextResult(); // Skip the first sheet and move to the second one
do {
reader.Read(); // Skip the header row
while (reader.Read())
{
var fieldCount = reader.FieldCount;
var azureGuidance = reader.GetValue(8)?.ToString();
var azureImplementation = reader.GetValue(9)?.ToString();
var awsGuidance = (string)null;// reader.GetValue(10)?.ToString();
var awsImplementation = (string)null;// reader.GetValue(11)?.ToString();

var azure = azureGuidance is null && azureImplementation is null
? null
: $"{azureGuidance}{((azureGuidance is not null && azureImplementation is not null) ? Environment.NewLine + Environment.NewLine : "")}{azureImplementation}";

var aws = awsGuidance is null && awsImplementation is null
? null
: $"{awsGuidance}{((awsGuidance is not null && awsImplementation is not null) ? Environment.NewLine + Environment.NewLine : "")}{awsImplementation}";

controls.Add(new SecurityBenchmarkControl(
reader.GetValue(0)?.ToString() ?? "",
reader.GetValue(1)?.ToString() ?? "",
reader.GetValue(6)?.ToString() ?? "",
reader.GetValue(7)?.ToString(),
azure,
aws,
null
));
}
}
while (reader.NextResult());
return controls;
});
}


private static string GetFileFullNameForResource(string rootDirectoryPath, string resourceName)
{
return Path.Combine(GetBenchmarksDirectory(rootDirectoryPath), GetSecurityBaselineFileName(resourceName));
Expand Down
1 change: 1 addition & 0 deletions src/Crisp.Core/Services/IRecommendationsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ public interface IRecommendationsService
Task<IEnumerable<string>> GetResourcesAsync();
Task<Category> GetRecommendationsAsync(IEnumerable<string> resources);
Task<IEnumerable<SecurityBenchmark>> GetBenchmarksAsync(string resourceName);
Task<Category> GetBenchmarkControlsAsync();
}
79 changes: 78 additions & 1 deletion src/Crisp.Core/Services/RecommendationsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ public async Task<Category> GetRecommendationsAsync(IEnumerable<string> resource
var repositoryDirectoryPath = await gitHubRepository.CloneAsync(GitHubAccountName, GitHubRepositoryName);

var benchmarks = await securityBenchmarksRepository.GetSecurityBenchmarksForResourceAsync(resourceName, repositoryDirectoryPath);

return benchmarks;
}

Expand All @@ -59,6 +58,12 @@ public async Task<IEnumerable<string>> GetResourcesAsync()
return await securityBenchmarksRepository.GetAllResourceNamesAsync(repositoryDirectoryPath);
}

public async Task<Category> GetBenchmarkControlsAsync()
{
var repositoryDirectoryPath = await gitHubRepository.CloneAsync(GitHubAccountName, GitHubRepositoryName);
return MapBenchmarkControlsToCategory(await securityBenchmarksRepository.GetSecurityBenchmarkControlsAsync(repositoryDirectoryPath));
}


private Category MapBenchmarksToCategory(string resourceName, IEnumerable<SecurityBenchmark> benchmarks)
{
Expand Down Expand Up @@ -126,6 +131,45 @@ private Category MapBenchmarksToCategory(string resourceName, IEnumerable<Securi
Recommendations: Enumerable.Empty<Recommendation>());
}

private Category MapBenchmarkControlsToCategory(IEnumerable<SecurityBenchmarkControl> controls)
{
var domainsOrder = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
{
{"Network Security", 1},
{"Identity Management", 2},
{"Privileged Access", 3},
{"Data Protection", 4},
{"Asset Management", 5},
{"Logging and Threat Detection", 6},
{"Incident Response", 7},
{"Posture and Vulnerability Management", 8},
{"Endpoint Security", 9},
{"Backup and Recovery", 10},
{"DevOps Security", 11},
{"Governance and Strategy", 12}
};

var sortedControlsGroups = controls.Where(b => domainsOrder.ContainsKey(b.Domain)).GroupBy(b => b.Domain).OrderBy(g => domainsOrder[g.Key]).ToList();
var categories = new List<Category>();
foreach (var group in sortedControlsGroups)
{
var recommendations = group.Select(MapSecurityBenchmarkControlToRecommendation).ToArray();
categories.Add(new Category(
GenerateIdFor(group.Key),
group.Key,
Description: null,
Children: Enumerable.Empty<Category>(),
recommendations));
}

return new Category(
GenerateIdFor("Cloud Security Benchmark"),
"Cloud Security Benchmark",
Description: null,
categories,
Recommendations: Enumerable.Empty<Recommendation>());
}

private Recommendation MapSecurityBenchmarkToRecommendation(string resourceName, SecurityBenchmark benchmark)
{
if (benchmark.ControlTitle is null)
Expand Down Expand Up @@ -175,6 +219,39 @@ private Recommendation MapSecurityBenchmarkToRecommendation(string resourceName,
}
}

private Recommendation MapSecurityBenchmarkControlToRecommendation(SecurityBenchmarkControl benchmarkControl)
{
var description = "";
if (benchmarkControl.Azure is not null)
{
if (benchmarkControl.Description is not null && benchmarkControl.Description.ToLower().Trim() != "n/a")
{
description = $"{benchmarkControl.Description}{Environment.NewLine}{Environment.NewLine}**Azure Guidance:**{Environment.NewLine}{Environment.NewLine}";
}
description += benchmarkControl.Azure;
}
else
{
description = $"{benchmarkControl.Description}";
}

if (!string.IsNullOrWhiteSpace(description))
{
var match = Regex.Matches(description, "https://[^\\s]+");
foreach (Match m in match)
{
var url = m.Value.Trim();
description = description.Replace(m.Value, $" [{url}]({url})");
}
}
return new Recommendation(
benchmarkControl.Id,
$"{benchmarkControl.Id}: {benchmarkControl.Title!}",
description,
null
);
}

private static string GenerateIdFor(string text)
{
return string.Join("", (SHA1.HashData(Encoding.UTF8.GetBytes(text))).Select(b => b.ToString("x2")));
Expand Down
5 changes: 5 additions & 0 deletions src/Crisp.Ui/ClientApp/src/AppRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import AddThreatModel from "./components/AddThreatModel";
import ThreatModelReport from "./components/ThreatModelReport";
import Recommendations from "./components/Recommendations";
import Resources from "./components/Resources";
import ThreatsMapping from "./components/ThreatMapping";

const AppRoutes = [
{
Expand All @@ -29,6 +30,10 @@ const AppRoutes = [
{
path: '/resources',
element: <Resources />
},
{
path: '/map',
element: <ThreatsMapping />
}
];

Expand Down
2 changes: 1 addition & 1 deletion src/Crisp.Ui/ClientApp/src/components/AddThreatModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ const AddThreatModel = () => {
</FormGroup>
{selectedRecommendationsCount > 0 ? (
<FormGroup switch className="mb-3">
<Input className="form-check-input me-3" type="switch" role="switch" checked={addResourcesRecommendations} onChange={() => setAddResourcesRecommendations(!addResourcesRecommendations)} /> Add resources recommendations to threats (preview)
<Input className="form-check-input me-3" type="switch" role="switch" checked={addResourcesRecommendations} onChange={() => setAddResourcesRecommendations(!addResourcesRecommendations)} /> Add resources recommendations to threats
</FormGroup>
) : null}
{addResourcesRecommendations ? (
Expand Down
Loading

0 comments on commit 0675926

Please sign in to comment.