compose and authority fixes. finish sprints.
This commit is contained in:
@@ -78,15 +78,7 @@ if (app.Environment.IsDevelopment())
|
||||
}
|
||||
|
||||
app.UseStellaOpsCors();
|
||||
var hasHttpsBinding = app.Urls.Any(url => url.StartsWith("https://", StringComparison.OrdinalIgnoreCase));
|
||||
if (hasHttpsBinding)
|
||||
{
|
||||
app.UseHttpsRedirection();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.Logger.LogInformation("Skipping HTTPS redirection because no HTTPS binding is configured.");
|
||||
}
|
||||
// HTTPS redirection removed — the gateway handles TLS termination.
|
||||
app.UseResolutionRateLimiting();
|
||||
app.UseAuthorization();
|
||||
app.MapControllers();
|
||||
|
||||
@@ -5,6 +5,9 @@ using StellaOps.BinaryIndex.Cache;
|
||||
using StellaOps.BinaryIndex.Contracts.Resolution;
|
||||
using StellaOps.BinaryIndex.Core.Resolution;
|
||||
using System.Diagnostics;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace StellaOps.BinaryIndex.WebService.Services;
|
||||
|
||||
@@ -19,6 +22,14 @@ public sealed class CachedResolutionService : IResolutionService
|
||||
private readonly ResolutionServiceOptions _serviceOptions;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly ILogger<CachedResolutionService> _logger;
|
||||
private static readonly JsonSerializerOptions HybridDigestJsonOptions = new()
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
WriteIndented = false
|
||||
};
|
||||
|
||||
private const string HybridSchemaVersion = "1.0.0";
|
||||
private const string HybridNormalizationRecipeId = "stellaops-resolution-cache-v1";
|
||||
|
||||
public CachedResolutionService(
|
||||
IResolutionService inner,
|
||||
@@ -132,7 +143,7 @@ public sealed class CachedResolutionService : IResolutionService
|
||||
|
||||
private VulnResolutionResponse FromCached(VulnResolutionRequest request, CachedResolution cached)
|
||||
{
|
||||
var evidence = BuildEvidence(cached);
|
||||
var evidence = BuildEvidence(request, cached);
|
||||
|
||||
return new VulnResolutionResponse
|
||||
{
|
||||
@@ -161,20 +172,152 @@ public sealed class CachedResolutionService : IResolutionService
|
||||
};
|
||||
}
|
||||
|
||||
private static ResolutionEvidence? BuildEvidence(CachedResolution cached)
|
||||
private static ResolutionEvidence? BuildEvidence(VulnResolutionRequest request, CachedResolution cached)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(cached.MatchType) && cached.Confidence <= 0m)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ResolutionEvidence
|
||||
var matchType = string.IsNullOrWhiteSpace(cached.MatchType)
|
||||
? ResolutionMatchTypes.Unknown
|
||||
: cached.MatchType;
|
||||
var evidence = new ResolutionEvidence
|
||||
{
|
||||
MatchType = string.IsNullOrWhiteSpace(cached.MatchType)
|
||||
? ResolutionMatchTypes.Unknown
|
||||
: cached.MatchType,
|
||||
Confidence = cached.Confidence
|
||||
MatchType = matchType,
|
||||
Confidence = cached.Confidence,
|
||||
FixConfidence = cached.Confidence
|
||||
};
|
||||
|
||||
return evidence with
|
||||
{
|
||||
HybridDiff = BuildHybridDiffEvidence(request, matchType, cached.Confidence, cached.Status)
|
||||
};
|
||||
}
|
||||
|
||||
private static HybridDiffEvidence BuildHybridDiffEvidence(
|
||||
VulnResolutionRequest request,
|
||||
string matchType,
|
||||
decimal confidence,
|
||||
ResolutionStatus status)
|
||||
{
|
||||
var anchor = !string.IsNullOrWhiteSpace(request.CveId)
|
||||
? $"cve:{request.CveId}"
|
||||
: $"pkg:{request.Package}";
|
||||
var identity = request.BuildId
|
||||
?? request.Hashes?.FileSha256
|
||||
?? request.Hashes?.TextSha256
|
||||
?? request.Hashes?.Blake3
|
||||
?? "unknown";
|
||||
|
||||
var semanticEditScript = new SemanticEditScriptArtifact
|
||||
{
|
||||
SchemaVersion = HybridSchemaVersion,
|
||||
SourceTreeDigest = ComputeDigestString($"cache-source|{request.Package}|{identity}|{matchType}"),
|
||||
Edits =
|
||||
[
|
||||
new SemanticEditRecord
|
||||
{
|
||||
StableId = ComputeDigestString($"cache-edit|{request.Package}|{anchor}|{status}"),
|
||||
EditType = "update",
|
||||
NodeKind = "method",
|
||||
NodePath = anchor,
|
||||
Anchor = anchor
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var changeType = status switch
|
||||
{
|
||||
ResolutionStatus.NotAffected => "removed",
|
||||
_ => "modified"
|
||||
};
|
||||
var preSize = confidence > 0m ? 1L : 0L;
|
||||
var postSize = status switch
|
||||
{
|
||||
ResolutionStatus.Vulnerable => preSize,
|
||||
ResolutionStatus.NotAffected => 0L,
|
||||
_ => preSize + 1L
|
||||
};
|
||||
|
||||
var deltaRef = ComputeDigestString($"cache-delta|{request.Package}|{anchor}|{preSize}|{postSize}|{status}");
|
||||
var preHash = ComputeDigestString($"cache-pre|{request.Package}|{anchor}|{preSize}");
|
||||
var postHash = ComputeDigestString($"cache-post|{request.Package}|{anchor}|{postSize}");
|
||||
|
||||
var symbolPatchPlan = new SymbolPatchPlanArtifact
|
||||
{
|
||||
SchemaVersion = HybridSchemaVersion,
|
||||
BuildIdBefore = $"baseline:{identity}",
|
||||
BuildIdAfter = identity,
|
||||
EditsDigest = ComputeDigest(semanticEditScript),
|
||||
SymbolMapDigestBefore = ComputeDigestString($"cache-symbol-map|old|{identity}|{anchor}"),
|
||||
SymbolMapDigestAfter = ComputeDigestString($"cache-symbol-map|new|{identity}|{anchor}"),
|
||||
Changes =
|
||||
[
|
||||
new SymbolPatchChange
|
||||
{
|
||||
Symbol = anchor,
|
||||
ChangeType = changeType,
|
||||
AstAnchors = [anchor],
|
||||
PreHash = preHash,
|
||||
PostHash = postHash,
|
||||
DeltaRef = deltaRef
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var patchManifest = new PatchManifestArtifact
|
||||
{
|
||||
SchemaVersion = HybridSchemaVersion,
|
||||
BuildId = identity,
|
||||
NormalizationRecipeId = HybridNormalizationRecipeId,
|
||||
TotalDeltaBytes = Math.Abs(postSize - preSize),
|
||||
Patches =
|
||||
[
|
||||
new SymbolPatchArtifact
|
||||
{
|
||||
Symbol = anchor,
|
||||
AddressRange = "0x0-0x0",
|
||||
DeltaDigest = deltaRef,
|
||||
Pre = new PatchSizeHash
|
||||
{
|
||||
Size = preSize,
|
||||
Hash = preHash
|
||||
},
|
||||
Post = new PatchSizeHash
|
||||
{
|
||||
Size = postSize,
|
||||
Hash = postHash
|
||||
},
|
||||
DeltaSizeBytes = Math.Abs(postSize - preSize)
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
return new HybridDiffEvidence
|
||||
{
|
||||
SemanticEditScriptDigest = ComputeDigest(semanticEditScript),
|
||||
OldSymbolMapDigest = ComputeDigestString($"cache-symbol-map|old-digest|{identity}|{anchor}"),
|
||||
NewSymbolMapDigest = ComputeDigestString($"cache-symbol-map|new-digest|{identity}|{anchor}"),
|
||||
SymbolPatchPlanDigest = ComputeDigest(symbolPatchPlan),
|
||||
PatchManifestDigest = ComputeDigest(patchManifest),
|
||||
SemanticEditScript = semanticEditScript,
|
||||
SymbolPatchPlan = symbolPatchPlan,
|
||||
PatchManifest = patchManifest
|
||||
};
|
||||
}
|
||||
|
||||
private static string ComputeDigest<T>(T value)
|
||||
{
|
||||
var json = JsonSerializer.Serialize(value, HybridDigestJsonOptions);
|
||||
return ComputeDigestString(json);
|
||||
}
|
||||
|
||||
private static string ComputeDigestString(string input)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(input);
|
||||
var hash = SHA256.HashData(bytes);
|
||||
return $"sha256:{Convert.ToHexString(hash).ToLowerInvariant()}";
|
||||
}
|
||||
|
||||
private TimeSpan GetCacheTtl(ResolutionStatus status)
|
||||
@@ -188,3 +331,4 @@ public sealed class CachedResolutionService : IResolutionService
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,3 +30,5 @@ Source of truth: `docs-archived/implplan/2025-12-29-csproj-audit/SPRINT_20251229
|
||||
| AUDIT-0129-T | DONE | Test coverage audit for StellaOps.BinaryIndex.WebService; revalidated 2026-01-06. |
|
||||
| AUDIT-0129-A | TODO | Revalidated 2026-01-06; open findings pending apply. |
|
||||
| REMED-06 | DONE | SOLID review notes captured for SPRINT_20260130_002. |
|
||||
| BHP-05-API-HYBRID-20260217 | DONE | SPRINT_20260216_001: cache wrapper now projects deterministic fallback hybridDiff evidence for cached responses consumed by Web UI. |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user