fix tests. new product advisories enhancements
This commit is contained in:
@@ -91,6 +91,12 @@ public sealed class LanguageComponentWriter
|
||||
_builder = builder ?? throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a writer for testing purposes. Components added to this writer will be discarded.
|
||||
/// </summary>
|
||||
public static LanguageComponentWriter CreateNull()
|
||||
=> new(new LanguageAnalyzerResultBuilder());
|
||||
|
||||
public void Add(LanguageComponentRecord record)
|
||||
=> _builder.Add(record);
|
||||
|
||||
|
||||
@@ -93,10 +93,14 @@ public sealed class SpdxLayerWriter : ILayerSbomWriter
|
||||
SbomTypes = new[] { "build" }.ToImmutableArray()
|
||||
};
|
||||
|
||||
var displayDigest = layerDigestShort.Length > 12
|
||||
? $"{layerDigestShort[..12]}..."
|
||||
: layerDigestShort;
|
||||
|
||||
return new SpdxDocument
|
||||
{
|
||||
DocumentNamespace = idBuilder.DocumentNamespace,
|
||||
Name = $"SBOM for layer {request.LayerOrder} ({layerDigestShort[..12]}...)",
|
||||
Name = $"SBOM for layer {request.LayerOrder} ({displayDigest})",
|
||||
CreationInfo = creationInfo,
|
||||
Sbom = sbom,
|
||||
Elements = packages.Cast<SpdxElement>().ToImmutableArray(),
|
||||
|
||||
@@ -237,14 +237,27 @@ public sealed class FuncProofBuilder
|
||||
/// Computes the content-addressable proof ID.
|
||||
/// Uses ICryptoHash for regional compliance (defaults to BLAKE3 in "world" profile).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The proof ID is computed over the structural content only (binary identity, sections,
|
||||
/// functions, traces) and excludes volatile fields (proofId, generatedAt, generatorVersion)
|
||||
/// to ensure deterministic output for identical inputs.
|
||||
/// </remarks>
|
||||
public static string ComputeProofId(FuncProof proof, ICryptoHash? cryptoHash = null)
|
||||
{
|
||||
// Create a version without proofId for hashing
|
||||
var forHashing = proof with { ProofId = string.Empty };
|
||||
// Create a version without volatile fields for hashing.
|
||||
// ProofId is excluded because it is the output.
|
||||
// GeneratedAt and GeneratorVersion are excluded because they are not
|
||||
// structural content and would break determinism across invocations.
|
||||
var forHashing = proof with
|
||||
{
|
||||
ProofId = string.Empty,
|
||||
GeneratedAt = default,
|
||||
GeneratorVersion = string.Empty
|
||||
};
|
||||
var json = JsonSerializer.Serialize(forHashing, CanonicalJsonOptions);
|
||||
var bytes = Encoding.UTF8.GetBytes(json);
|
||||
var hash = ComputeHashForGraph(bytes, cryptoHash);
|
||||
|
||||
|
||||
// Prefix indicates algorithm used (determined by compliance profile)
|
||||
var algorithmPrefix = cryptoHash is not null ? "graph" : "sha256";
|
||||
return $"{algorithmPrefix}:{hash}";
|
||||
|
||||
@@ -238,7 +238,7 @@ public sealed class SbomFuncProofLinker : ISbomFuncProofLinker
|
||||
}
|
||||
}
|
||||
|
||||
// Check externalReferences for FuncProof links
|
||||
// Check externalReferences for FuncProof links and merge with callflow data
|
||||
var externalRefs = targetComponent["externalReferences"] as JsonArray;
|
||||
if (externalRefs != null)
|
||||
{
|
||||
@@ -263,10 +263,13 @@ public sealed class SbomFuncProofLinker : ISbomFuncProofLinker
|
||||
{
|
||||
// Parse additional metadata from comment
|
||||
var metadata = ParseCommentMetadata(comment);
|
||||
var extProofId = metadata.TryGetValue("proofId", out var pid) ? pid : "unknown";
|
||||
|
||||
references.Add(new FuncProofEvidenceRef
|
||||
// Check if we already have a callflow entry for the same ProofId
|
||||
var existingIndex = references.FindIndex(r => r.ProofId == extProofId);
|
||||
var extRef2 = new FuncProofEvidenceRef
|
||||
{
|
||||
ProofId = metadata.TryGetValue("proofId", out var pid) ? pid : "unknown",
|
||||
ProofId = extProofId,
|
||||
BuildId = metadata.TryGetValue("buildId", out var bid) ? bid : "unknown",
|
||||
FileSha256 = metadata.TryGetValue("fileSha256", out var fsha) ? fsha : "unknown",
|
||||
ProofDigest = sha256Hash ?? "unknown",
|
||||
@@ -277,7 +280,18 @@ public sealed class SbomFuncProofLinker : ISbomFuncProofLinker
|
||||
TraceCount = int.TryParse(
|
||||
metadata.TryGetValue("traceCount", out var tc) ? tc : "0",
|
||||
out var tcInt) ? tcInt : 0
|
||||
});
|
||||
};
|
||||
|
||||
if (existingIndex >= 0)
|
||||
{
|
||||
// Merge: replace the callflow-only entry with the more complete
|
||||
// externalReferences entry (which has location and digest)
|
||||
references[existingIndex] = extRef2;
|
||||
}
|
||||
else
|
||||
{
|
||||
references.Add(extRef2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ public sealed class PostgresEpssSignalRepository : IEpssSignalRepository
|
||||
{
|
||||
SignalId = row.signal_id,
|
||||
TenantId = row.tenant_id,
|
||||
ModelDate = DateOnly.FromDateTime(row.model_date),
|
||||
ModelDate = row.model_date,
|
||||
CveId = row.cve_id,
|
||||
EventType = row.event_type,
|
||||
RiskBand = row.risk_band,
|
||||
@@ -370,7 +370,7 @@ public sealed class PostgresEpssSignalRepository : IEpssSignalRepository
|
||||
private readonly record struct SignalRow(
|
||||
long signal_id,
|
||||
Guid tenant_id,
|
||||
DateTime model_date,
|
||||
DateOnly model_date,
|
||||
string cve_id,
|
||||
string event_type,
|
||||
string? risk_band,
|
||||
|
||||
@@ -36,10 +36,12 @@ public sealed class PostgresScanManifestRepository : IScanManifestRepository
|
||||
created_at AS CreatedAt
|
||||
FROM {TableName}
|
||||
WHERE manifest_hash = @ManifestHash
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1
|
||||
""";
|
||||
|
||||
await using var connection = await _dataSource.OpenSystemConnectionAsync(cancellationToken).ConfigureAwait(false);
|
||||
return await connection.QuerySingleOrDefaultAsync<ScanManifestRow>(
|
||||
return await connection.QueryFirstOrDefaultAsync<ScanManifestRow>(
|
||||
new CommandDefinition(sql, new { ManifestHash = manifestHash }, cancellationToken: cancellationToken))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user