Refactor and enhance LDAP plugin configuration and validation
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Updated `LdapPluginOptions` to enforce TLS and client certificate requirements. - Added validation checks for TLS configuration in `LdapPluginOptionsTests`. - Improved error handling in `DirectoryServicesLdapConnectionFactory` for StartTLS negotiation. - Enhanced logging in `LdapCredentialStore` to include detailed audit properties for credential verification. - Introduced `StubStructuredRetriever` and `StubVectorRetriever` for testing in `ToolsetServiceCollectionExtensionsTests`. - Refactored `AdvisoryGuardrailPipelineTests` to improve test clarity and structure. - Added `FileSystemAdvisoryTaskQueueTests` for testing queue functionality. - Updated JSON test data for consistency with new requirements. - Modified `AdvisoryPipelineOrchestratorTests` to reflect changes in metadata keys.
This commit is contained in:
@@ -59,8 +59,8 @@ public static class ToolsetServiceCollectionExtensions
|
||||
services.TryAddSingleton<IAdvisoryPipelineExecutor, AdvisoryPipelineExecutor>();
|
||||
services.AddOptions<AdvisoryGuardrailOptions>();
|
||||
|
||||
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<AdvisoryPlanCacheOptions>, ConfigureOptions<AdvisoryPlanCacheOptions>>(
|
||||
_ => options =>
|
||||
services.AddOptions<AdvisoryPlanCacheOptions>()
|
||||
.Configure(options =>
|
||||
{
|
||||
if (options.DefaultTimeToLive <= TimeSpan.Zero)
|
||||
{
|
||||
@@ -71,10 +71,10 @@ public static class ToolsetServiceCollectionExtensions
|
||||
{
|
||||
options.CleanupInterval = TimeSpan.FromMinutes(5);
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<AdvisoryTaskQueueOptions>, ConfigureOptions<AdvisoryTaskQueueOptions>>(
|
||||
_ => options =>
|
||||
services.AddOptions<AdvisoryTaskQueueOptions>()
|
||||
.Configure(options =>
|
||||
{
|
||||
if (options.Capacity <= 0)
|
||||
{
|
||||
@@ -85,7 +85,7 @@ public static class ToolsetServiceCollectionExtensions
|
||||
{
|
||||
options.DequeueWaitInterval = TimeSpan.FromSeconds(1);
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ public sealed record AdvisoryGuardrailResult(
|
||||
public static AdvisoryGuardrailResult Allowed(string sanitizedPrompt, ImmutableDictionary<string, string>? metadata = null)
|
||||
=> new(false, sanitizedPrompt, ImmutableArray<AdvisoryGuardrailViolation>.Empty, metadata ?? ImmutableDictionary<string, string>.Empty);
|
||||
|
||||
public static AdvisoryGuardrailResult Blocked(string sanitizedPrompt, IEnumerable<AdvisoryGuardrailViolation> violations, ImmutableDictionary<string, string>? metadata = null)
|
||||
public static AdvisoryGuardrailResult Reject(string sanitizedPrompt, IEnumerable<AdvisoryGuardrailViolation> violations, ImmutableDictionary<string, string>? metadata = null)
|
||||
=> new(true, sanitizedPrompt, violations.ToImmutableArray(), metadata ?? ImmutableDictionary<string, string>.Empty);
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ internal sealed class AdvisoryGuardrailPipeline : IAdvisoryGuardrailPipeline
|
||||
if (blocked)
|
||||
{
|
||||
_logger?.LogWarning("Guardrail blocked prompt for cache key {CacheKey}", prompt.CacheKey);
|
||||
return Task.FromResult(AdvisoryGuardrailResult.Blocked(sanitized, violations, metadata));
|
||||
return Task.FromResult(AdvisoryGuardrailResult.Reject(sanitized, violations, metadata));
|
||||
}
|
||||
|
||||
return Task.FromResult(AdvisoryGuardrailResult.Allowed(sanitized, metadata));
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace StellaOps.AdvisoryAI.Orchestration;
|
||||
|
||||
/// <summary>
|
||||
/// Queue payload sent to workers to execute a pipeline plan.
|
||||
/// </summary>
|
||||
public sealed class AdvisoryPipelineExecutionMessage
|
||||
{
|
||||
public AdvisoryPipelineExecutionMessage(
|
||||
string planCacheKey,
|
||||
AdvisoryTaskRequest request,
|
||||
IReadOnlyDictionary<string, string> planMetadata)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(planCacheKey);
|
||||
PlanCacheKey = planCacheKey;
|
||||
Request = request ?? throw new ArgumentNullException(nameof(request));
|
||||
PlanMetadata = planMetadata ?? throw new ArgumentNullException(nameof(planMetadata));
|
||||
}
|
||||
|
||||
public string PlanCacheKey { get; }
|
||||
|
||||
public AdvisoryTaskRequest Request { get; }
|
||||
|
||||
public IReadOnlyDictionary<string, string> PlanMetadata { get; }
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -118,8 +120,9 @@ internal sealed class AdvisoryPipelineOrchestrator : IAdvisoryPipelineOrchestrat
|
||||
.RetrieveAsync(sbomRequest, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var analysis = _toolset.AnalyzeDependencies(context);
|
||||
return (context, analysis);
|
||||
var sanitizedContext = SanitizeContext(context, configuration);
|
||||
var analysis = _toolset.AnalyzeDependencies(sanitizedContext);
|
||||
return (sanitizedContext, analysis);
|
||||
}
|
||||
|
||||
private static ImmutableDictionary<string, string> BuildMetadata(
|
||||
@@ -133,7 +136,7 @@ internal sealed class AdvisoryPipelineOrchestrator : IAdvisoryPipelineOrchestrat
|
||||
builder["task_type"] = request.TaskType.ToString();
|
||||
builder["advisory_key"] = request.AdvisoryKey;
|
||||
builder["profile"] = request.Profile;
|
||||
builder["structured_chunk_count"] = structured.Chunks.Count.ToString(CultureInfo.InvariantCulture);
|
||||
builder["structured_chunk_count"] = structured.Chunks.Count().ToString(CultureInfo.InvariantCulture);
|
||||
builder["vector_query_count"] = vectors.Length.ToString(CultureInfo.InvariantCulture);
|
||||
builder["vector_match_count"] = vectors.Sum(result => result.Matches.Length).ToString(CultureInfo.InvariantCulture);
|
||||
builder["includes_sbom"] = (sbom is not null).ToString();
|
||||
@@ -147,8 +150,8 @@ internal sealed class AdvisoryPipelineOrchestrator : IAdvisoryPipelineOrchestrat
|
||||
|
||||
if (sbom is not null)
|
||||
{
|
||||
builder["sbom_version_count"] = sbom.VersionTimeline.Count.ToString(CultureInfo.InvariantCulture);
|
||||
builder["sbom_dependency_path_count"] = sbom.DependencyPaths.Count.ToString(CultureInfo.InvariantCulture);
|
||||
builder["sbom_version_count"] = sbom.VersionTimeline.Length.ToString(CultureInfo.InvariantCulture);
|
||||
builder["sbom_dependency_path_count"] = sbom.DependencyPaths.Length.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (!sbom.EnvironmentFlags.IsEmpty)
|
||||
{
|
||||
@@ -197,6 +200,34 @@ internal sealed class AdvisoryPipelineOrchestrator : IAdvisoryPipelineOrchestrat
|
||||
return builder.ToImmutable();
|
||||
}
|
||||
|
||||
private static SbomContextResult SanitizeContext(
|
||||
SbomContextResult context,
|
||||
AdvisoryTaskConfiguration configuration)
|
||||
{
|
||||
if ((configuration.IncludeEnvironmentFlags || context.EnvironmentFlags.IsEmpty)
|
||||
&& (configuration.IncludeBlastRadius || context.BlastRadius is null))
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
var environmentFlags = configuration.IncludeEnvironmentFlags
|
||||
? context.EnvironmentFlags
|
||||
: ImmutableDictionary<string, string>.Empty;
|
||||
|
||||
var blastRadius = configuration.IncludeBlastRadius
|
||||
? context.BlastRadius
|
||||
: null;
|
||||
|
||||
return SbomContextResult.Create(
|
||||
context.ArtifactId,
|
||||
context.Purl,
|
||||
context.VersionTimeline,
|
||||
context.DependencyPaths,
|
||||
environmentFlags,
|
||||
blastRadius,
|
||||
context.Metadata);
|
||||
}
|
||||
|
||||
private static string ComputeCacheKey(
|
||||
AdvisoryTaskRequest request,
|
||||
AdvisoryRetrievalResult structured,
|
||||
@@ -242,8 +273,8 @@ internal sealed class AdvisoryPipelineOrchestrator : IAdvisoryPipelineOrchestrat
|
||||
|
||||
if (sbom is not null)
|
||||
{
|
||||
builder.Append("|sbom:timeline=").Append(sbom.VersionTimeline.Count);
|
||||
builder.Append("|sbom:paths=").Append(sbom.DependencyPaths.Count);
|
||||
builder.Append("|sbom:timeline=").Append(sbom.VersionTimeline.Length);
|
||||
builder.Append("|sbom:paths=").Append(sbom.DependencyPaths.Length);
|
||||
foreach (var entry in sbom.VersionTimeline
|
||||
.OrderBy(e => e.Version, StringComparer.Ordinal)
|
||||
.ThenBy(e => e.FirstObserved.ToUnixTimeMilliseconds())
|
||||
|
||||
@@ -72,8 +72,8 @@ public sealed class AdvisoryPipelinePlanResponse
|
||||
{
|
||||
sbomSummary = new PipelineSbomSummary(
|
||||
plan.SbomContext.ArtifactId,
|
||||
plan.SbomContext.VersionTimeline.Count,
|
||||
plan.SbomContext.DependencyPaths.Count,
|
||||
plan.SbomContext.VersionTimeline.Length,
|
||||
plan.SbomContext.DependencyPaths.Length,
|
||||
plan.DependencyAnalysis?.Nodes.Length ?? 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Immutable;
|
||||
using StellaOps.AdvisoryAI.Abstractions;
|
||||
using StellaOps.AdvisoryAI.Documents;
|
||||
using StellaOps.AdvisoryAI.Context;
|
||||
using StellaOps.AdvisoryAI.Documents;
|
||||
using StellaOps.AdvisoryAI.Tools;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
@@ -56,18 +57,18 @@ internal sealed class AdvisoryPromptAssembler : IAdvisoryPromptAssembler
|
||||
var metadata = OrderMetadata(plan.Metadata);
|
||||
|
||||
var payload = new PromptPayload(
|
||||
task: plan.Request.TaskType.ToString(),
|
||||
advisoryKey: plan.Request.AdvisoryKey,
|
||||
profile: plan.Request.Profile,
|
||||
policyVersion: plan.Request.PolicyVersion,
|
||||
instructions: ResolveInstruction(plan.Request.TaskType),
|
||||
structured: structured.Select(chunk => chunk.Payload).ToImmutableArray(),
|
||||
vectors: vectors,
|
||||
sbom: sbom,
|
||||
dependency: dependency,
|
||||
metadata: metadata,
|
||||
budget: new PromptBudget(plan.Budget.PromptTokens, plan.Budget.CompletionTokens),
|
||||
policyContext: BuildPolicyContext(plan.Request));
|
||||
Task: plan.Request.TaskType.ToString(),
|
||||
AdvisoryKey: plan.Request.AdvisoryKey,
|
||||
Profile: plan.Request.Profile,
|
||||
PolicyVersion: plan.Request.PolicyVersion,
|
||||
Instructions: ResolveInstruction(plan.Request.TaskType),
|
||||
Structured: structured.Select(chunk => chunk.Payload).ToImmutableArray(),
|
||||
Vectors: vectors,
|
||||
Sbom: sbom,
|
||||
Dependency: dependency,
|
||||
Metadata: ToSortedDictionary(metadata),
|
||||
Budget: new PromptBudget(plan.Budget.PromptTokens, plan.Budget.CompletionTokens),
|
||||
PolicyContext: ToSortedDictionary(BuildPolicyContext(plan.Request)));
|
||||
|
||||
var promptJson = JsonSerializer.Serialize(payload, SerializerOptions);
|
||||
|
||||
@@ -114,6 +115,16 @@ internal sealed class AdvisoryPromptAssembler : IAdvisoryPromptAssembler
|
||||
return ordered;
|
||||
}
|
||||
|
||||
private static IReadOnlyDictionary<string, string> ToSortedDictionary(IReadOnlyDictionary<string, string> metadata)
|
||||
{
|
||||
if (metadata is null || metadata.Count == 0)
|
||||
{
|
||||
return ImmutableSortedDictionary.Create<string, string>(StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
return ImmutableSortedDictionary.CreateRange(StringComparer.Ordinal, metadata);
|
||||
}
|
||||
|
||||
private static ImmutableArray<AdvisoryPromptCitation> BuildCitations(
|
||||
ImmutableArray<PromptStructuredChunk> structured)
|
||||
{
|
||||
@@ -180,10 +191,10 @@ internal sealed class AdvisoryPromptAssembler : IAdvisoryPromptAssembler
|
||||
.ToImmutableArray(),
|
||||
path.IsRuntime,
|
||||
path.Source,
|
||||
OrderMetadata(path.Metadata)))
|
||||
ToSortedDictionary(OrderMetadata(path.Metadata))))
|
||||
.ToImmutableArray();
|
||||
|
||||
var environmentFlags = OrderMetadata(result.EnvironmentFlags);
|
||||
var environmentFlags = ToSortedDictionary(OrderMetadata(result.EnvironmentFlags));
|
||||
|
||||
PromptSbomBlastRadius? blastRadius = null;
|
||||
if (result.BlastRadius is not null)
|
||||
@@ -193,7 +204,7 @@ internal sealed class AdvisoryPromptAssembler : IAdvisoryPromptAssembler
|
||||
result.BlastRadius.ImpactedWorkloads,
|
||||
result.BlastRadius.ImpactedNamespaces,
|
||||
result.BlastRadius.ImpactedPercentage,
|
||||
OrderMetadata(result.BlastRadius.Metadata));
|
||||
ToSortedDictionary(OrderMetadata(result.BlastRadius.Metadata)));
|
||||
}
|
||||
|
||||
return new PromptSbomContext(
|
||||
@@ -203,7 +214,7 @@ internal sealed class AdvisoryPromptAssembler : IAdvisoryPromptAssembler
|
||||
dependencyPaths,
|
||||
environmentFlags,
|
||||
blastRadius,
|
||||
OrderMetadata(result.Metadata));
|
||||
ToSortedDictionary(OrderMetadata(result.Metadata)));
|
||||
}
|
||||
|
||||
private static PromptDependencySummary? BuildDependency(DependencyAnalysisResult? analysis)
|
||||
@@ -225,7 +236,7 @@ internal sealed class AdvisoryPromptAssembler : IAdvisoryPromptAssembler
|
||||
return new PromptDependencySummary(
|
||||
analysis.ArtifactId,
|
||||
nodes,
|
||||
OrderMetadata(analysis.Metadata));
|
||||
ToSortedDictionary(OrderMetadata(analysis.Metadata)));
|
||||
}
|
||||
|
||||
private static ImmutableDictionary<string, string> BuildPolicyContext(AdvisoryTaskRequest request)
|
||||
@@ -297,9 +308,9 @@ internal sealed class AdvisoryPromptAssembler : IAdvisoryPromptAssembler
|
||||
ImmutableArray<PromptVectorQuery> Vectors,
|
||||
PromptSbomContext? Sbom,
|
||||
PromptDependencySummary? Dependency,
|
||||
ImmutableDictionary<string, string> Metadata,
|
||||
IReadOnlyDictionary<string, string> Metadata,
|
||||
PromptBudget Budget,
|
||||
ImmutableDictionary<string, string> PolicyContext);
|
||||
IReadOnlyDictionary<string, string> PolicyContext);
|
||||
|
||||
private sealed record PromptStructuredChunk(
|
||||
int Index,
|
||||
@@ -317,7 +328,7 @@ internal sealed class AdvisoryPromptAssembler : IAdvisoryPromptAssembler
|
||||
Section,
|
||||
ParagraphId,
|
||||
Text,
|
||||
Metadata);
|
||||
ToSortedDictionary(Metadata));
|
||||
}
|
||||
|
||||
private sealed record PromptStructuredChunkPayload(
|
||||
@@ -327,7 +338,7 @@ internal sealed class AdvisoryPromptAssembler : IAdvisoryPromptAssembler
|
||||
string Section,
|
||||
string ParagraphId,
|
||||
string Text,
|
||||
ImmutableDictionary<string, string> Metadata);
|
||||
IReadOnlyDictionary<string, string> Metadata);
|
||||
|
||||
private sealed record PromptVectorQuery(string Query, ImmutableArray<PromptVectorMatch> Matches);
|
||||
|
||||
@@ -338,9 +349,9 @@ internal sealed class AdvisoryPromptAssembler : IAdvisoryPromptAssembler
|
||||
string? Purl,
|
||||
ImmutableArray<PromptSbomVersion> VersionTimeline,
|
||||
ImmutableArray<PromptSbomDependencyPath> DependencyPaths,
|
||||
ImmutableDictionary<string, string> EnvironmentFlags,
|
||||
IReadOnlyDictionary<string, string> EnvironmentFlags,
|
||||
PromptSbomBlastRadius? BlastRadius,
|
||||
ImmutableDictionary<string, string> Metadata);
|
||||
IReadOnlyDictionary<string, string> Metadata);
|
||||
|
||||
private sealed record PromptSbomVersion(
|
||||
string Version,
|
||||
@@ -353,7 +364,7 @@ internal sealed class AdvisoryPromptAssembler : IAdvisoryPromptAssembler
|
||||
ImmutableArray<PromptSbomNode> Nodes,
|
||||
bool IsRuntime,
|
||||
string? Source,
|
||||
ImmutableDictionary<string, string> Metadata);
|
||||
IReadOnlyDictionary<string, string> Metadata);
|
||||
|
||||
private sealed record PromptSbomNode(string Identifier, string? Version);
|
||||
|
||||
@@ -362,12 +373,12 @@ internal sealed class AdvisoryPromptAssembler : IAdvisoryPromptAssembler
|
||||
int ImpactedWorkloads,
|
||||
int ImpactedNamespaces,
|
||||
double? ImpactedPercentage,
|
||||
ImmutableDictionary<string, string> Metadata);
|
||||
IReadOnlyDictionary<string, string> Metadata);
|
||||
|
||||
private sealed record PromptDependencySummary(
|
||||
string ArtifactId,
|
||||
ImmutableArray<PromptDependencyNode> Nodes,
|
||||
ImmutableDictionary<string, string> Metadata);
|
||||
IReadOnlyDictionary<string, string> Metadata);
|
||||
|
||||
private sealed record PromptDependencyNode(
|
||||
string Identifier,
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StellaOps.AdvisoryAI.Providers;
|
||||
|
||||
/// <summary>
|
||||
/// Fallback SBOM context client that always returns <c>null</c>, used when the SBOM service is not configured.
|
||||
/// </summary>
|
||||
internal sealed class NullSbomContextClient : ISbomContextClient
|
||||
{
|
||||
public Task<SbomContextDocument?> GetContextAsync(SbomContextQuery query, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(query);
|
||||
return Task.FromResult<SbomContextDocument?>(null);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
@@ -92,7 +93,8 @@ internal sealed class SbomContextHttpClient : ISbomContextClient
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
var payload = await response.Content.ReadFromJsonAsync<SbomContextPayload>(SerializerOptions, cancellationToken)
|
||||
var httpContent = response.Content ?? throw new InvalidOperationException("SBOM context response did not include content.");
|
||||
var payload = await httpContent.ReadFromJsonAsync<SbomContextPayload>(SerializerOptions, cancellationToken: cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (payload is null)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<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="Microsoft.Extensions.Http" Version="10.0.0-rc.2.25502.107" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Concelier\__Libraries\StellaOps.Concelier.Core\StellaOps.Concelier.Core.csproj" />
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
| AIAI-31-004A | DOING (2025-11-04) | Advisory AI Guild, Platform Guild | AIAI-31-004, AIAI-31-002 | Wire `AdvisoryPipelineOrchestrator` into WebService/Worker, expose API/queue contracts, emit metrics, and stand up cache stub. | API returns plan metadata; worker executes queue message; metrics recorded; doc updated. |
|
||||
| AIAI-31-004B | TODO | Advisory AI Guild, Security Guild | AIAI-31-004A, DOCS-AIAI-31-003, AUTH-AIAI-31-004 | Implement prompt assembler, guardrail plumbing, cache persistence, DSSE provenance; add golden outputs. | Deterministic outputs cached; guardrails enforced; tests cover prompt assembly + caching. |
|
||||
| AIAI-31-004C | TODO | Advisory AI Guild, CLI Guild, Docs Guild | AIAI-31-004B, CLI-AIAI-31-003 | Deliver CLI `stella advise run <task>` command, renderers, documentation updates, and CLI golden tests. | CLI command produces deterministic output; docs published; smoke run recorded. |
|
||||
| AIAI-31-005 | TODO | Advisory AI Guild, Security Guild | AIAI-31-004 | Implement guardrails (redaction, injection defense, output validation, citation enforcement) and fail-safe handling. | Guardrails block adversarial inputs; output validator enforces schemas; security tests pass. |
|
||||
| AIAI-31-006 | TODO | Advisory AI Guild | AIAI-31-004..005 | Expose REST API endpoints (`/advisory/ai/*`) with RBAC, rate limits, OpenAPI schemas, and batching support. | Endpoints deployed with schema validation; rate limits enforced; integration tests cover error codes. |
|
||||
| AIAI-31-005 | DOING (2025-11-03) | Advisory AI Guild, Security Guild | AIAI-31-004 | Implement guardrails (redaction, injection defense, output validation, citation enforcement) and fail-safe handling. | Guardrails block adversarial inputs; output validator enforces schemas; security tests pass. |
|
||||
| AIAI-31-006 | DOING (2025-11-03) | Advisory AI Guild | AIAI-31-004..005 | Expose REST API endpoints (`/advisory/ai/*`) with RBAC, rate limits, OpenAPI schemas, and batching support. | Endpoints deployed with schema validation; rate limits enforced; integration tests cover error codes. |
|
||||
| AIAI-31-007 | TODO | Advisory AI Guild, Observability Guild | AIAI-31-004..006 | Instrument metrics (`advisory_ai_latency`, `guardrail_blocks`, `validation_failures`, `citation_coverage`), logs, and traces; publish dashboards/alerts. | Telemetry live; dashboards approved; alerts configured. |
|
||||
| AIAI-31-008 | TODO | Advisory AI Guild, DevOps Guild | AIAI-31-006..007 | Package inference on-prem container, remote inference toggle, Helm/Compose manifests, scaling guidance, offline kit instructions. | Deployment docs merged; smoke deploy executed; offline kit updated; feature flags documented. |
|
||||
| AIAI-31-010 | DONE (2025-11-02) | Advisory AI Guild | CONCELIER-VULN-29-001, EXCITITOR-VULN-29-001 | Implement Concelier advisory raw document provider mapping CSAF/OSV payloads into structured chunks for retrieval. | Provider resolves content format, preserves metadata, and passes unit tests covering CSAF/OSV cases. |
|
||||
|
||||
@@ -42,7 +42,7 @@ internal sealed class DeterministicToolset : IDeterministicToolset
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
|
||||
if (context.DependencyPaths.Count == 0)
|
||||
if (context.DependencyPaths.Length == 0)
|
||||
{
|
||||
return DependencyAnalysisResult.Empty(context.ArtifactId);
|
||||
}
|
||||
@@ -106,7 +106,7 @@ internal sealed class DeterministicToolset : IDeterministicToolset
|
||||
["unique_nodes"] = summaries.Length.ToString(CultureInfo.InvariantCulture),
|
||||
};
|
||||
|
||||
return new DependencyAnalysisResult(context.ArtifactId, summaries, metadata);
|
||||
return DependencyAnalysisResult.Create(context.ArtifactId, summaries, metadata);
|
||||
}
|
||||
|
||||
private static string NormalizeScheme(string scheme)
|
||||
|
||||
Reference in New Issue
Block a user