save progress
This commit is contained in:
@@ -81,9 +81,64 @@ public sealed class BundleBuilder : IBundleBuilder
|
||||
cryptoConfig.ExpiresAt));
|
||||
}
|
||||
|
||||
var ruleBundles = new List<RuleBundleComponent>();
|
||||
foreach (var ruleBundleConfig in request.RuleBundles)
|
||||
{
|
||||
// Validate relative path before combining
|
||||
var targetDir = PathValidation.SafeCombine(outputPath, ruleBundleConfig.RelativePath);
|
||||
Directory.CreateDirectory(targetDir);
|
||||
|
||||
var files = new List<RuleBundleFileComponent>();
|
||||
long bundleTotalSize = 0;
|
||||
var digestBuilder = new System.Text.StringBuilder();
|
||||
|
||||
// Copy all files from source directory
|
||||
if (Directory.Exists(ruleBundleConfig.SourceDirectory))
|
||||
{
|
||||
foreach (var sourceFile in Directory.GetFiles(ruleBundleConfig.SourceDirectory)
|
||||
.OrderBy(f => Path.GetFileName(f), StringComparer.Ordinal))
|
||||
{
|
||||
var fileName = Path.GetFileName(sourceFile);
|
||||
var targetFile = Path.Combine(targetDir, fileName);
|
||||
|
||||
await using (var input = File.OpenRead(sourceFile))
|
||||
await using (var output = File.Create(targetFile))
|
||||
{
|
||||
await input.CopyToAsync(output, ct).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await using var digestStream = File.OpenRead(targetFile);
|
||||
var hash = await SHA256.HashDataAsync(digestStream, ct).ConfigureAwait(false);
|
||||
var fileDigest = Convert.ToHexString(hash).ToLowerInvariant();
|
||||
|
||||
var fileInfo = new FileInfo(targetFile);
|
||||
files.Add(new RuleBundleFileComponent(fileName, fileDigest, fileInfo.Length));
|
||||
bundleTotalSize += fileInfo.Length;
|
||||
digestBuilder.Append(fileDigest);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute combined digest from all file digests
|
||||
var combinedDigest = Convert.ToHexString(
|
||||
SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(digestBuilder.ToString()))).ToLowerInvariant();
|
||||
|
||||
ruleBundles.Add(new RuleBundleComponent(
|
||||
ruleBundleConfig.BundleId,
|
||||
ruleBundleConfig.BundleType,
|
||||
ruleBundleConfig.Version,
|
||||
ruleBundleConfig.RelativePath,
|
||||
combinedDigest,
|
||||
bundleTotalSize,
|
||||
ruleBundleConfig.RuleCount,
|
||||
ruleBundleConfig.SignerKeyId,
|
||||
ruleBundleConfig.SignedAt,
|
||||
files.ToImmutableArray()));
|
||||
}
|
||||
|
||||
var totalSize = feeds.Sum(f => f.SizeBytes) +
|
||||
policies.Sum(p => p.SizeBytes) +
|
||||
cryptoMaterials.Sum(c => c.SizeBytes);
|
||||
cryptoMaterials.Sum(c => c.SizeBytes) +
|
||||
ruleBundles.Sum(r => r.SizeBytes);
|
||||
|
||||
var manifest = new BundleManifest
|
||||
{
|
||||
@@ -96,6 +151,7 @@ public sealed class BundleBuilder : IBundleBuilder
|
||||
Feeds = feeds.ToImmutableArray(),
|
||||
Policies = policies.ToImmutableArray(),
|
||||
CryptoMaterials = cryptoMaterials.ToImmutableArray(),
|
||||
RuleBundles = ruleBundles.ToImmutableArray(),
|
||||
TotalSizeBytes = totalSize
|
||||
};
|
||||
|
||||
@@ -138,7 +194,8 @@ public sealed record BundleBuildRequest(
|
||||
DateTimeOffset? ExpiresAt,
|
||||
IReadOnlyList<FeedBuildConfig> Feeds,
|
||||
IReadOnlyList<PolicyBuildConfig> Policies,
|
||||
IReadOnlyList<CryptoBuildConfig> CryptoMaterials);
|
||||
IReadOnlyList<CryptoBuildConfig> CryptoMaterials,
|
||||
IReadOnlyList<RuleBundleBuildConfig> RuleBundles);
|
||||
|
||||
public abstract record BundleComponentSource(string SourcePath, string RelativePath);
|
||||
|
||||
@@ -169,3 +226,24 @@ public sealed record CryptoBuildConfig(
|
||||
CryptoComponentType Type,
|
||||
DateTimeOffset? ExpiresAt)
|
||||
: BundleComponentSource(SourcePath, RelativePath);
|
||||
|
||||
/// <summary>
|
||||
/// Configuration for building a rule bundle component.
|
||||
/// </summary>
|
||||
/// <param name="BundleId">Bundle identifier (e.g., "secrets.ruleset").</param>
|
||||
/// <param name="BundleType">Bundle type (e.g., "secrets", "malware").</param>
|
||||
/// <param name="Version">Bundle version in YYYY.MM format.</param>
|
||||
/// <param name="SourceDirectory">Source directory containing the rule bundle files.</param>
|
||||
/// <param name="RelativePath">Relative path in the output bundle.</param>
|
||||
/// <param name="RuleCount">Number of rules in the bundle.</param>
|
||||
/// <param name="SignerKeyId">Key ID used to sign the bundle.</param>
|
||||
/// <param name="SignedAt">When the bundle was signed.</param>
|
||||
public sealed record RuleBundleBuildConfig(
|
||||
string BundleId,
|
||||
string BundleType,
|
||||
string Version,
|
||||
string SourceDirectory,
|
||||
string RelativePath,
|
||||
int RuleCount,
|
||||
string? SignerKeyId,
|
||||
DateTimeOffset? SignedAt);
|
||||
|
||||
Reference in New Issue
Block a user