This commit is contained in:
StellaOps Bot
2025-12-14 23:20:14 +02:00
parent 3411e825cd
commit b058dbe031
356 changed files with 68310 additions and 1108 deletions

View File

@@ -1,10 +1,11 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
@@ -71,9 +72,46 @@ internal sealed class CallgraphIngestionService : ICallgraphIngestionService
: normalized.SchemaVersion;
var analyzerMeta = request.Analyzer ?? normalized.Analyzer;
parseStream.Position = 0;
var artifactHash = ComputeSha256(artifactBytes);
var graphHash = ComputeGraphHash(normalized);
var document = new CallgraphDocument
{
Language = parser.Language,
LanguageType = CallgraphLanguage.Unknown,
Component = request.Component,
Version = request.Version,
Nodes = new List<CallgraphNode>(normalized.Nodes),
Edges = new List<CallgraphEdge>(normalized.Edges),
Roots = new List<CallgraphRoot>(normalized.Roots),
Entrypoints = normalized.Entrypoints is null
? new List<CallgraphEntrypoint>()
: new List<CallgraphEntrypoint>(normalized.Entrypoints),
Metadata = request.Metadata is null
? null
: new Dictionary<string, string?>(request.Metadata, StringComparer.OrdinalIgnoreCase),
Artifact = new CallgraphArtifactMetadata
{
ContentType = request.ArtifactContentType
},
IngestedAt = timeProvider.GetUtcNow()
};
document.Metadata ??= new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);
document.Metadata["formatVersion"] = normalized.FormatVersion;
document.Metadata["schemaVersion"] = schemaVersion;
if (analyzerMeta is not null)
{
foreach (var kv in analyzerMeta)
{
document.Metadata[$"analyzer.{kv.Key}"] = kv.Value;
}
}
document.SchemaVersion = schemaVersion;
document = CallgraphSchemaMigrator.EnsureV1(document);
var graphHash = ComputeGraphHash(document);
document.GraphHash = graphHash;
var manifest = new CallgraphManifest
{
@@ -83,9 +121,9 @@ internal sealed class CallgraphIngestionService : ICallgraphIngestionService
ArtifactHash = artifactHash,
GraphHash = graphHash,
SchemaVersion = schemaVersion,
NodeCount = normalized.Nodes.Count,
EdgeCount = normalized.Edges.Count,
RootCount = normalized.Roots.Count,
NodeCount = document.Nodes.Count,
EdgeCount = document.Edges.Count,
RootCount = document.Roots?.Count ?? 0,
CreatedAt = timeProvider.GetUtcNow()
};
@@ -106,43 +144,14 @@ internal sealed class CallgraphIngestionService : ICallgraphIngestionService
parseStream,
cancellationToken).ConfigureAwait(false);
var document = new CallgraphDocument
{
Language = parser.Language,
Component = request.Component,
Version = request.Version,
Nodes = new List<CallgraphNode>(normalized.Nodes),
Edges = new List<CallgraphEdge>(normalized.Edges),
Roots = new List<CallgraphRoot>(normalized.Roots),
Metadata = request.Metadata is null
? null
: new Dictionary<string, string?>(request.Metadata, StringComparer.OrdinalIgnoreCase),
Artifact = new CallgraphArtifactMetadata
{
Path = artifactMetadata.Path,
Hash = artifactMetadata.Hash,
CasUri = artifactMetadata.CasUri,
ManifestPath = artifactMetadata.ManifestPath,
ManifestCasUri = artifactMetadata.ManifestCasUri,
GraphHash = graphHash,
ContentType = artifactMetadata.ContentType,
Length = artifactMetadata.Length
},
IngestedAt = timeProvider.GetUtcNow()
};
document.Metadata ??= new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);
document.Metadata["formatVersion"] = normalized.FormatVersion;
document.Metadata["schemaVersion"] = schemaVersion;
if (analyzerMeta is not null)
{
foreach (var kv in analyzerMeta)
{
document.Metadata[$"analyzer.{kv.Key}"] = kv.Value;
}
}
document.GraphHash = graphHash;
document.SchemaVersion = schemaVersion;
document.Artifact.Path = artifactMetadata.Path;
document.Artifact.Hash = artifactMetadata.Hash;
document.Artifact.CasUri = artifactMetadata.CasUri;
document.Artifact.ManifestPath = artifactMetadata.ManifestPath;
document.Artifact.ManifestCasUri = artifactMetadata.ManifestCasUri;
document.Artifact.GraphHash = graphHash;
document.Artifact.ContentType = artifactMetadata.ContentType;
document.Artifact.Length = artifactMetadata.Length;
document = await repository.UpsertAsync(document, cancellationToken).ConfigureAwait(false);
@@ -166,7 +175,7 @@ internal sealed class CallgraphIngestionService : ICallgraphIngestionService
document.Artifact.Path,
document.Artifact.Hash,
document.Artifact.CasUri,
graphHash,
document.GraphHash,
document.Artifact.ManifestCasUri,
schemaVersion,
document.Nodes.Count,
@@ -216,13 +225,14 @@ internal sealed class CallgraphIngestionService : ICallgraphIngestionService
return Convert.ToHexString(hash);
}
private static string ComputeGraphHash(CallgraphParseResult result)
private static string ComputeGraphHash(CallgraphDocument document)
{
var builder = new StringBuilder();
builder.Append("schema|").Append(result.SchemaVersion).AppendLine();
builder.Append("schema|").Append(document.Schema).AppendLine();
builder.Append("language|").Append(document.LanguageType).Append('|').Append(document.Language).AppendLine();
foreach (var node in result.Nodes.OrderBy(n => n.Id, StringComparer.Ordinal))
foreach (var node in document.Nodes.OrderBy(n => n.Id, StringComparer.Ordinal))
{
builder
.Append(node.Id).Append('|')
@@ -236,29 +246,62 @@ internal sealed class CallgraphIngestionService : ICallgraphIngestionService
.Append(node.BuildId).Append('|')
.Append(node.CodeId).Append('|')
.Append(node.Language).Append('|')
.Append(node.SymbolKey).Append('|')
.Append(node.ArtifactKey).Append('|')
.Append(node.Visibility).Append('|')
.Append(node.IsEntrypointCandidate).Append('|')
.Append(node.Flags).Append('|')
.Append(Join(node.Evidence)).Append('|')
.Append(JoinDict(node.Analyzer))
.Append(JoinDict(node.Analyzer)).Append('|')
.Append(JoinDict(node.Attributes))
.AppendLine();
}
foreach (var edge in result.Edges.OrderBy(e => e.SourceId, StringComparer.Ordinal).ThenBy(e => e.TargetId, StringComparer.Ordinal))
foreach (var edge in document.Edges
.OrderBy(e => e.SourceId, StringComparer.Ordinal)
.ThenBy(e => e.TargetId, StringComparer.Ordinal)
.ThenBy(e => e.Type, StringComparer.Ordinal)
.ThenBy(e => e.Offset ?? -1))
{
builder
.Append(edge.SourceId).Append("->").Append(edge.TargetId).Append('|')
.Append(edge.Type).Append('|')
.Append(edge.Kind).Append('|')
.Append(edge.Reason).Append('|')
.Append(edge.Weight.ToString("G17", CultureInfo.InvariantCulture)).Append('|')
.Append(edge.Offset?.ToString(CultureInfo.InvariantCulture) ?? string.Empty).Append('|')
.Append(edge.IsResolved).Append('|')
.Append(edge.Provenance).Append('|')
.Append(edge.Purl).Append('|')
.Append(edge.SymbolDigest).Append('|')
.Append(edge.Confidence?.ToString() ?? string.Empty).Append('|')
.Append(edge.Confidence?.ToString("G17", CultureInfo.InvariantCulture) ?? string.Empty).Append('|')
.Append(Join(edge.Candidates)).Append('|')
.Append(Join(edge.Evidence))
.AppendLine();
}
foreach (var root in result.Roots.OrderBy(r => r.Id, StringComparer.Ordinal))
foreach (var root in (document.Roots ?? new List<CallgraphRoot>()).OrderBy(r => r.Id, StringComparer.Ordinal))
{
builder.Append("root|").Append(root.Id).Append('|').Append(root.Phase).Append('|').Append(root.Source).AppendLine();
}
foreach (var entrypoint in document.Entrypoints
.OrderBy(e => (int)e.Phase)
.ThenBy(e => e.Order)
.ThenBy(e => e.NodeId, StringComparer.Ordinal))
{
builder
.Append("entrypoint|").Append(entrypoint.NodeId).Append('|')
.Append(entrypoint.Kind).Append('|')
.Append(entrypoint.Framework).Append('|')
.Append(entrypoint.Phase).Append('|')
.Append(entrypoint.Route).Append('|')
.Append(entrypoint.HttpMethod).Append('|')
.Append(entrypoint.Source).Append('|')
.Append(entrypoint.Order.ToString(CultureInfo.InvariantCulture))
.AppendLine();
}
return ComputeSha256(Encoding.UTF8.GetBytes(builder.ToString()));
}
@@ -286,6 +329,21 @@ internal sealed class CallgraphIngestionService : ICallgraphIngestionService
}
return ordered.ToString();
}
private static string JoinDict(IReadOnlyDictionary<string, string>? values)
{
if (values is null)
{
return string.Empty;
}
var ordered = new StringBuilder();
foreach (var kv in values.OrderBy(k => k.Key, StringComparer.Ordinal))
{
ordered.Append(kv.Key).Append('=').Append(kv.Value).Append(';');
}
return ordered.ToString();
}
}
/// <summary>