feat(scanner): Implement Deno analyzer and associated tests
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Added Deno analyzer with comprehensive metadata and evidence structure.
- Created a detailed implementation plan for Sprint 130 focusing on Deno analyzer.
- Introduced AdvisoryAiGuardrailOptions for managing guardrail configurations.
- Developed GuardrailPhraseLoader for loading blocked phrases from JSON files.
- Implemented tests for AdvisoryGuardrailOptions binding and phrase loading.
- Enhanced telemetry for Advisory AI with metrics tracking.
- Added VexObservationProjectionService for querying VEX observations.
- Created extensive tests for VexObservationProjectionService functionality.
- Introduced Ruby language analyzer with tests for simple and complex workspaces.
- Added Ruby application fixtures for testing purposes.
This commit is contained in:
master
2025-11-12 10:01:54 +02:00
parent 0e8655cbb1
commit babb81af52
75 changed files with 3346 additions and 187 deletions

View File

@@ -1,13 +1,18 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http.Headers;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using StellaOps.AdvisoryAI.Caching;
using StellaOps.AdvisoryAI.DependencyInjection;
using StellaOps.AdvisoryAI.Inference;
using StellaOps.AdvisoryAI.Metrics;
using StellaOps.AdvisoryAI.Guardrails;
using StellaOps.AdvisoryAI.Outputs;
using StellaOps.AdvisoryAI.Providers;
using StellaOps.AdvisoryAI.Queue;
@@ -86,6 +91,12 @@ public static class ServiceCollectionExtensions
services.AddAdvisoryPipeline();
services.AddAdvisoryPipelineInfrastructure();
services.AddOptions<AdvisoryGuardrailOptions>()
.Configure<IOptions<AdvisoryAiServiceOptions>, IHostEnvironment>((options, aiOptions, environment) =>
{
ApplyGuardrailConfiguration(options, aiOptions.Value.Guardrails, environment);
});
services.Replace(ServiceDescriptor.Singleton<IAdvisoryTaskQueue, FileSystemAdvisoryTaskQueue>());
services.Replace(ServiceDescriptor.Singleton<IAdvisoryPlanCache, FileSystemAdvisoryPlanCache>());
services.Replace(ServiceDescriptor.Singleton<IAdvisoryOutputStore, FileSystemAdvisoryOutputStore>());
@@ -93,4 +104,87 @@ public static class ServiceCollectionExtensions
return services;
}
private static void ApplyGuardrailConfiguration(
AdvisoryGuardrailOptions target,
AdvisoryAiGuardrailOptions? source,
IHostEnvironment? environment)
{
if (source is null)
{
return;
}
if (source.MaxPromptLength.HasValue && source.MaxPromptLength.Value > 0)
{
target.MaxPromptLength = source.MaxPromptLength.Value;
}
target.RequireCitations = source.RequireCitations;
var defaults = target.BlockedPhrases.ToList();
var merged = new SortedSet<string>(defaults, StringComparer.OrdinalIgnoreCase);
if (source.BlockedPhrases is { Count: > 0 })
{
foreach (var phrase in source.BlockedPhrases)
{
if (!string.IsNullOrWhiteSpace(phrase))
{
merged.Add(phrase.Trim());
}
}
}
if (!string.IsNullOrWhiteSpace(source.BlockedPhraseFile))
{
var resolvedPath = ResolveGuardrailPath(source.BlockedPhraseFile!, environment);
foreach (var phrase in GuardrailPhraseLoader.Load(resolvedPath))
{
if (!string.IsNullOrWhiteSpace(phrase))
{
merged.Add(phrase.Trim());
}
}
}
if (merged.Count == 0)
{
return;
}
target.BlockedPhrases.Clear();
foreach (var phrase in merged)
{
target.BlockedPhrases.Add(phrase);
}
}
private static string ResolveGuardrailPath(string configuredPath, IHostEnvironment? environment)
{
var trimmed = configuredPath.Trim();
if (Path.IsPathRooted(trimmed))
{
if (!File.Exists(trimmed))
{
throw new FileNotFoundException($"Guardrail phrase file {trimmed} was not found.", trimmed);
}
return trimmed;
}
var root = environment?.ContentRootPath;
if (string.IsNullOrWhiteSpace(root))
{
root = AppContext.BaseDirectory;
}
var resolved = Path.GetFullPath(Path.Combine(root!, trimmed));
if (!File.Exists(resolved))
{
throw new FileNotFoundException($"Guardrail phrase file {resolved} was not found.", resolved);
}
return resolved;
}
}