Add OpenSslLegacyShim to ensure OpenSSL 1.1 libraries are accessible on Linux
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

This commit introduces the OpenSslLegacyShim class, which sets the LD_LIBRARY_PATH environment variable to include the directory containing OpenSSL 1.1 native libraries. This is necessary for Mongo2Go to function correctly on Linux platforms that do not ship these libraries by default. The shim checks if the current operating system is Linux and whether the required directory exists before modifying the environment variable.
This commit is contained in:
master
2025-11-02 21:41:03 +02:00
parent f98cea3bcf
commit 1d962ee6fc
71 changed files with 3675 additions and 1255 deletions

View File

@@ -0,0 +1,13 @@
namespace StellaOps.AdvisoryAI.Abstractions;
public sealed record AdvisoryRetrievalRequest(
string AdvisoryKey,
IReadOnlyCollection<string>? PreferredSections = null,
int? MaxChunks = null)
{
public string AdvisoryKey { get; } = AdvisoryKey ?? throw new ArgumentNullException(nameof(AdvisoryKey));
public IReadOnlyCollection<string>? PreferredSections { get; } = PreferredSections;
public int? MaxChunks { get; } = MaxChunks;
}

View File

@@ -0,0 +1,38 @@
using System.Collections.Immutable;
using StellaOps.AdvisoryAI.Documents;
namespace StellaOps.AdvisoryAI.Abstractions;
public sealed class AdvisoryRetrievalResult
{
private AdvisoryRetrievalResult(
string advisoryKey,
IReadOnlyList<AdvisoryChunk> chunks,
IReadOnlyDictionary<string, string> metadata)
{
AdvisoryKey = advisoryKey;
Chunks = chunks;
Metadata = metadata;
}
public string AdvisoryKey { get; }
public IReadOnlyList<AdvisoryChunk> Chunks { get; }
public IReadOnlyDictionary<string, string> Metadata { get; }
public static AdvisoryRetrievalResult Create(
string advisoryKey,
IEnumerable<AdvisoryChunk> chunks,
IReadOnlyDictionary<string, string>? metadata = null)
{
ArgumentException.ThrowIfNullOrWhiteSpace(advisoryKey);
ArgumentNullException.ThrowIfNull(chunks);
var chunkList = chunks.ToImmutableArray();
return new AdvisoryRetrievalResult(
advisoryKey,
chunkList,
metadata is null ? ImmutableDictionary<string, string>.Empty : metadata.ToImmutableDictionary(StringComparer.Ordinal));
}
}

View File

@@ -0,0 +1,8 @@
using StellaOps.AdvisoryAI.Documents;
namespace StellaOps.AdvisoryAI.Abstractions;
public interface IAdvisoryDocumentProvider
{
Task<IReadOnlyList<AdvisoryDocument>> GetDocumentsAsync(string advisoryKey, CancellationToken cancellationToken);
}

View File

@@ -0,0 +1,6 @@
namespace StellaOps.AdvisoryAI.Abstractions;
public interface IAdvisoryStructuredRetriever
{
Task<AdvisoryRetrievalResult> RetrieveAsync(AdvisoryRetrievalRequest request, CancellationToken cancellationToken);
}

View File

@@ -0,0 +1,25 @@
namespace StellaOps.AdvisoryAI.Abstractions;
public interface IAdvisoryVectorRetriever
{
Task<IReadOnlyList<VectorRetrievalMatch>> SearchAsync(VectorRetrievalRequest request, CancellationToken cancellationToken);
}
public sealed record VectorRetrievalRequest(
AdvisoryRetrievalRequest Retrieval,
string Query,
int TopK = 5)
{
public AdvisoryRetrievalRequest Retrieval { get; } = Retrieval ?? throw new ArgumentNullException(nameof(Retrieval));
public string Query { get; } = Query ?? throw new ArgumentNullException(nameof(Query));
public int TopK { get; } = TopK;
}
public sealed record VectorRetrievalMatch(
string DocumentId,
string ChunkId,
string Text,
double Score,
IReadOnlyDictionary<string, string> Metadata);

View File

@@ -0,0 +1,26 @@
using StellaOps.AdvisoryAI.Documents;
namespace StellaOps.AdvisoryAI.Chunking;
internal sealed class DocumentChunkerFactory
{
private readonly IReadOnlyList<IDocumentChunker> _chunkers;
public DocumentChunkerFactory(IEnumerable<IDocumentChunker> chunkers)
{
_chunkers = chunkers.ToList();
}
public IDocumentChunker Resolve(DocumentFormat format)
{
foreach (var chunker in _chunkers)
{
if (chunker.CanHandle(format))
{
return chunker;
}
}
throw new NotSupportedException($"No chunker registered for format {format}.");
}
}

View File

@@ -0,0 +1,10 @@
using StellaOps.AdvisoryAI.Documents;
namespace StellaOps.AdvisoryAI.Chunking;
internal interface IDocumentChunker
{
bool CanHandle(DocumentFormat format);
IEnumerable<AdvisoryChunk> Chunk(AdvisoryDocument document);
}

View File

@@ -0,0 +1,64 @@
using System.Collections.Immutable;
namespace StellaOps.AdvisoryAI.Documents;
public sealed class AdvisoryChunk
{
private AdvisoryChunk(
string documentId,
string chunkId,
string section,
string paragraphId,
string text,
IReadOnlyDictionary<string, string>? metadata,
float[]? embedding)
{
DocumentId = documentId;
ChunkId = chunkId;
Section = section;
ParagraphId = paragraphId;
Text = text;
Metadata = metadata is null
? ImmutableDictionary<string, string>.Empty
: metadata.ToImmutableDictionary(StringComparer.Ordinal);
Embedding = embedding;
}
public string DocumentId { get; }
public string ChunkId { get; }
public string Section { get; }
public string ParagraphId { get; }
public string Text { get; }
public IReadOnlyDictionary<string, string> Metadata { get; }
public float[]? Embedding { get; private set; }
public AdvisoryChunk WithEmbedding(float[] embedding)
{
ArgumentNullException.ThrowIfNull(embedding);
Embedding = embedding;
return this;
}
public static AdvisoryChunk Create(
string documentId,
string chunkId,
string section,
string paragraphId,
string text,
IReadOnlyDictionary<string, string>? metadata = null)
{
ArgumentException.ThrowIfNullOrWhiteSpace(documentId);
ArgumentException.ThrowIfNullOrWhiteSpace(chunkId);
ArgumentException.ThrowIfNullOrWhiteSpace(section);
ArgumentException.ThrowIfNullOrWhiteSpace(paragraphId);
ArgumentNullException.ThrowIfNull(text);
return new AdvisoryChunk(documentId, chunkId, section, paragraphId, text, metadata, embedding: null);
}
}

View File

@@ -0,0 +1,46 @@
using System.Collections.Immutable;
namespace StellaOps.AdvisoryAI.Documents;
public sealed class AdvisoryDocument
{
private AdvisoryDocument(
string documentId,
DocumentFormat format,
string source,
string content,
IReadOnlyDictionary<string, string>? metadata)
{
DocumentId = documentId;
Format = format;
Source = source;
Content = content;
Metadata = metadata is null
? ImmutableDictionary<string, string>.Empty
: metadata.ToImmutableDictionary(StringComparer.Ordinal);
}
public string DocumentId { get; }
public DocumentFormat Format { get; }
public string Source { get; }
public string Content { get; }
public IReadOnlyDictionary<string, string> Metadata { get; }
public static AdvisoryDocument Create(
string documentId,
DocumentFormat format,
string source,
string content,
IReadOnlyDictionary<string, string>? metadata = null)
{
ArgumentException.ThrowIfNullOrWhiteSpace(documentId);
ArgumentException.ThrowIfNullOrWhiteSpace(source);
ArgumentNullException.ThrowIfNull(content);
return new AdvisoryDocument(documentId, format, source, content, metadata);
}
}

View File

@@ -0,0 +1,9 @@
namespace StellaOps.AdvisoryAI.Documents;
public enum DocumentFormat
{
Unknown = 0,
Csaf,
Osv,
Markdown,
}

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0-rc.2.25502.107" />
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.0-rc.2.25502.107" />
<PackageReference Include="System.Text.Json" Version="10.0.0-rc.2.25502.2" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
# Advisory AI Task Board — Epic 8
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|----|--------|----------|------------|-------------|---------------|
| AIAI-31-001 | TODO | Advisory AI Guild | CONCELIER-VULN-29-001, EXCITITOR-VULN-29-001 | Implement structured and vector retrievers for advisories/VEX with paragraph anchors and citation metadata. | Retrievers return deterministic chunks with source IDs/sections; unit tests cover CSAF/OSV/vendor formats. |
| AIAI-31-001 | DOING (2025-11-02) | Advisory AI Guild | CONCELIER-VULN-29-001, EXCITITOR-VULN-29-001 | Implement structured and vector retrievers for advisories/VEX with paragraph anchors and citation metadata. | Retrievers return deterministic chunks with source IDs/sections; unit tests cover CSAF/OSV/vendor formats. |
| AIAI-31-002 | TODO | Advisory AI Guild, SBOM Service Guild | SBOM-VULN-29-001 | Build SBOM context retriever (purl version timelines, dependency paths, env flags, blast radius estimator). | Retriever returns paths/metrics under SLA; tests cover ecosystems. |
| AIAI-31-003 | TODO | Advisory AI Guild | AIAI-31-001..002 | Implement deterministic toolset (version comparators, range checks, dependency analysis, policy lookup) exposed via orchestrator. | Tools validated with property tests; outputs cached; docs updated. |
| AIAI-31-004 | TODO | Advisory AI Guild | AIAI-31-001..003, AUTH-VULN-29-001 | Build orchestration pipeline for Summary/Conflict/Remediation tasks (prompt templates, tool calls, token budgets, caching). | Pipeline executes tasks deterministically; caches keyed by tuple+policy; integration tests cover tasks. |