texts fixes, search bar fixes, global menu fixes.

This commit is contained in:
master
2026-03-05 18:10:56 +02:00
parent 8e1cb9448d
commit a918d39a61
101 changed files with 3543 additions and 534 deletions

View File

@@ -55,13 +55,13 @@ public sealed class KnowledgeSearchOptions
public List<string> OpenApiRoots { get; set; } = ["src", "devops/compose"];
public string UnifiedFindingsSnapshotPath { get; set; } =
"src/AdvisoryAI/StellaOps.AdvisoryAI/UnifiedSearch/Snapshots/findings.snapshot.json";
"UnifiedSearch/Snapshots/findings.snapshot.json";
public string UnifiedVexSnapshotPath { get; set; } =
"src/AdvisoryAI/StellaOps.AdvisoryAI/UnifiedSearch/Snapshots/vex.snapshot.json";
"UnifiedSearch/Snapshots/vex.snapshot.json";
public string UnifiedPolicySnapshotPath { get; set; } =
"src/AdvisoryAI/StellaOps.AdvisoryAI/UnifiedSearch/Snapshots/policy.snapshot.json";
"UnifiedSearch/Snapshots/policy.snapshot.json";
public bool UnifiedAutoIndexEnabled { get; set; }

View File

@@ -13,7 +13,7 @@
<InternalsVisibleTo Include="StellaOps.AdvisoryAI.WebService" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Storage\Migrations\**\*.sql" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
<EmbeddedResource Include="Storage\Migrations\**\*.sql" />
<EmbeddedResource Include="UnifiedSearch\Synthesis\synthesis-system-prompt.txt" LogicalName="synthesis-system-prompt.txt" />
</ItemGroup>
<ItemGroup>
@@ -34,6 +34,18 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>models/all-MiniLM-L6-v2.onnx</TargetPath>
</None>
<None Update="UnifiedSearch/Snapshots/findings.snapshot.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>UnifiedSearch/Snapshots/findings.snapshot.json</TargetPath>
</None>
<None Update="UnifiedSearch/Snapshots/vex.snapshot.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>UnifiedSearch/Snapshots/vex.snapshot.json</TargetPath>
</None>
<None Update="UnifiedSearch/Snapshots/policy.snapshot.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>UnifiedSearch/Snapshots/policy.snapshot.json</TargetPath>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" />

View File

@@ -16,7 +16,7 @@ internal sealed class FindingsSearchAdapter : ISearchIngestionAdapter
{
private const string TenantHeader = "X-StellaOps-Tenant";
private const string HttpClientName = "scanner-internal";
private const string FindingsEndpoint = "/api/v1/scanner/security/findings";
private const string FindingsEndpoint = "/api/v1/security/findings";
private const int MaxPages = 20;
private const int PageSize = 100;

View File

@@ -12,16 +12,19 @@ namespace StellaOps.AdvisoryAI.UnifiedSearch;
internal sealed class UnifiedSearchIndexer : IUnifiedSearchIndexer
{
private readonly KnowledgeSearchOptions _options;
private readonly IKnowledgeSearchStore _store;
private readonly IEnumerable<ISearchIngestionAdapter> _adapters;
private readonly ILogger<UnifiedSearchIndexer> _logger;
public UnifiedSearchIndexer(
IOptions<KnowledgeSearchOptions> options,
IKnowledgeSearchStore store,
IEnumerable<ISearchIngestionAdapter> adapters,
ILogger<UnifiedSearchIndexer> logger)
{
ArgumentNullException.ThrowIfNull(options);
_options = options.Value ?? new KnowledgeSearchOptions();
_store = store ?? throw new ArgumentNullException(nameof(store));
_adapters = adapters ?? throw new ArgumentNullException(nameof(adapters));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
@@ -39,6 +42,8 @@ internal sealed class UnifiedSearchIndexer : IUnifiedSearchIndexer
return new UnifiedSearchIndexSummary(0, 0, 0);
}
await _store.EnsureSchemaAsync(cancellationToken).ConfigureAwait(false);
var stopwatch = Stopwatch.StartNew();
var domains = 0;
var chunks = 0;
@@ -131,6 +136,8 @@ internal sealed class UnifiedSearchIndexer : IUnifiedSearchIndexer
return new UnifiedSearchIndexSummary(0, 0, 0);
}
await _store.EnsureSchemaAsync(cancellationToken).ConfigureAwait(false);
var stopwatch = Stopwatch.StartNew();
var domains = 0;
var chunks = 0;
@@ -348,11 +355,17 @@ internal sealed class UnifiedSearchIndexer : IUnifiedSearchIndexer
UnifiedChunk chunk,
CancellationToken cancellationToken)
{
var sourceRef = ResolveSourceRef(chunk);
var sourcePath = ResolveSourcePath(chunk);
const string sql = """
INSERT INTO advisoryai.kb_doc
(doc_id, doc_type, product, version, source_ref, path, title, content_hash, metadata, indexed_at)
VALUES (@doc_id, @doc_type, @product, @version, @source_ref, @path, @title, @content_hash, '{}'::jsonb, NOW())
ON CONFLICT (doc_id) DO NOTHING;
ON CONFLICT (doc_id) DO UPDATE SET
title = EXCLUDED.title,
content_hash = EXCLUDED.content_hash,
indexed_at = NOW();
""";
await using var command = connection.CreateCommand();
@@ -362,14 +375,34 @@ internal sealed class UnifiedSearchIndexer : IUnifiedSearchIndexer
command.Parameters.AddWithValue("doc_type", chunk.Domain);
command.Parameters.AddWithValue("product", "stella-ops");
command.Parameters.AddWithValue("version", "local");
command.Parameters.AddWithValue("source_ref", chunk.Domain);
command.Parameters.AddWithValue("path", chunk.Kind);
command.Parameters.AddWithValue("source_ref", sourceRef);
command.Parameters.AddWithValue("path", sourcePath);
command.Parameters.AddWithValue("title", chunk.Title);
command.Parameters.AddWithValue("content_hash", KnowledgeSearchText.StableId(chunk.Body));
await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
}
private static string ResolveSourceRef(UnifiedChunk chunk)
{
if (!string.IsNullOrWhiteSpace(chunk.EntityKey))
{
return chunk.EntityKey.Trim();
}
return chunk.DocId;
}
private static string ResolveSourcePath(UnifiedChunk chunk)
{
if (!string.IsNullOrWhiteSpace(chunk.DocId))
{
return chunk.DocId;
}
return $"{chunk.Domain}/{chunk.Kind}";
}
private static IReadOnlyList<UnifiedChunk> DeduplicateChunks(IEnumerable<UnifiedChunk> chunks)
{
var byChunkId = new SortedDictionary<string, UnifiedChunk>(StringComparer.Ordinal);