feat(scanner): Implement Deno analyzer and associated tests
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
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:
@@ -6942,6 +6942,35 @@ internal static class CommandHandlers
|
||||
return;
|
||||
}
|
||||
|
||||
if (report.Observation is { } observation)
|
||||
{
|
||||
var bundler = string.IsNullOrWhiteSpace(observation.BundlerVersion)
|
||||
? "n/a"
|
||||
: observation.BundlerVersion;
|
||||
|
||||
AnsiConsole.MarkupLine(
|
||||
"[grey]Observation[/] bundler={0} • packages={1} • runtimeEdges={2}",
|
||||
Markup.Escape(bundler),
|
||||
observation.PackageCount,
|
||||
observation.RuntimeEdgeCount);
|
||||
|
||||
AnsiConsole.MarkupLine(
|
||||
"[grey]Capabilities[/] exec={0} net={1} serialization={2}",
|
||||
observation.UsesExec ? "[green]on[/]" : "[red]off[/]",
|
||||
observation.UsesNetwork ? "[green]on[/]" : "[red]off[/]",
|
||||
observation.UsesSerialization ? "[green]on[/]" : "[red]off[/]");
|
||||
|
||||
if (observation.SchedulerCount > 0)
|
||||
{
|
||||
var schedulerLabel = observation.Schedulers.Count > 0
|
||||
? string.Join(", ", observation.Schedulers)
|
||||
: observation.SchedulerCount.ToString(CultureInfo.InvariantCulture);
|
||||
AnsiConsole.MarkupLine("[grey]Schedulers[/] {0}", Markup.Escape(schedulerLabel));
|
||||
}
|
||||
|
||||
AnsiConsole.WriteLine();
|
||||
}
|
||||
|
||||
var table = new Table().Border(TableBorder.Rounded);
|
||||
table.AddColumn("Package");
|
||||
table.AddColumn("Version");
|
||||
@@ -7088,14 +7117,19 @@ internal static class CommandHandlers
|
||||
[JsonPropertyName("packages")]
|
||||
public IReadOnlyList<RubyInspectEntry> Packages { get; }
|
||||
|
||||
private RubyInspectReport(IReadOnlyList<RubyInspectEntry> packages)
|
||||
[JsonPropertyName("observation")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public RubyObservationSummary? Observation { get; }
|
||||
|
||||
private RubyInspectReport(IReadOnlyList<RubyInspectEntry> packages, RubyObservationSummary? observation)
|
||||
{
|
||||
Packages = packages;
|
||||
Observation = observation;
|
||||
}
|
||||
|
||||
public static RubyInspectReport Create(IEnumerable<LanguageComponentSnapshot>? snapshots)
|
||||
{
|
||||
var source = snapshots ?? Array.Empty<LanguageComponentSnapshot>();
|
||||
var source = snapshots?.ToArray() ?? Array.Empty<LanguageComponentSnapshot>();
|
||||
|
||||
var entries = source
|
||||
.Where(static snapshot => string.Equals(snapshot.Type, "gem", StringComparison.OrdinalIgnoreCase))
|
||||
@@ -7104,7 +7138,9 @@ internal static class CommandHandlers
|
||||
.ThenBy(static entry => entry.Version ?? string.Empty, StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
|
||||
return new RubyInspectReport(entries);
|
||||
var observation = RubyObservationSummary.TryCreate(source);
|
||||
|
||||
return new RubyInspectReport(entries, observation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7149,6 +7185,41 @@ internal static class CommandHandlers
|
||||
}
|
||||
}
|
||||
|
||||
private sealed record RubyObservationSummary(
|
||||
[property: JsonPropertyName("packageCount")] int PackageCount,
|
||||
[property: JsonPropertyName("runtimeEdgeCount")] int RuntimeEdgeCount,
|
||||
[property: JsonPropertyName("bundlerVersion")] string? BundlerVersion,
|
||||
[property: JsonPropertyName("usesExec")] bool UsesExec,
|
||||
[property: JsonPropertyName("usesNetwork")] bool UsesNetwork,
|
||||
[property: JsonPropertyName("usesSerialization")] bool UsesSerialization,
|
||||
[property: JsonPropertyName("schedulerCount")] int SchedulerCount,
|
||||
[property: JsonPropertyName("schedulers")] IReadOnlyList<string> Schedulers)
|
||||
{
|
||||
public static RubyObservationSummary? TryCreate(IEnumerable<LanguageComponentSnapshot> snapshots)
|
||||
{
|
||||
var observation = snapshots.FirstOrDefault(static snapshot =>
|
||||
string.Equals(snapshot.Type, "ruby-observation", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (observation is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var metadata = RubyMetadataHelpers.Clone(observation.Metadata);
|
||||
var schedulers = RubyMetadataHelpers.GetList(metadata, "ruby.observation.capability.scheduler_list");
|
||||
|
||||
return new RubyObservationSummary(
|
||||
RubyMetadataHelpers.GetInt(metadata, "ruby.observation.packages") ?? 0,
|
||||
RubyMetadataHelpers.GetInt(metadata, "ruby.observation.runtime_edges") ?? 0,
|
||||
RubyMetadataHelpers.GetString(metadata, "ruby.observation.bundler_version"),
|
||||
RubyMetadataHelpers.GetBool(metadata, "ruby.observation.capability.exec") ?? false,
|
||||
RubyMetadataHelpers.GetBool(metadata, "ruby.observation.capability.net") ?? false,
|
||||
RubyMetadataHelpers.GetBool(metadata, "ruby.observation.capability.serialization") ?? false,
|
||||
RubyMetadataHelpers.GetInt(metadata, "ruby.observation.capability.schedulers") ?? schedulers.Count,
|
||||
schedulers);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class RubyResolveReport
|
||||
{
|
||||
[JsonPropertyName("scanId")]
|
||||
@@ -7343,6 +7414,22 @@ internal static class CommandHandlers
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int? GetInt(IDictionary<string, string?> metadata, string key)
|
||||
{
|
||||
var value = GetString(metadata, key);
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsed))
|
||||
{
|
||||
return parsed;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed record LockValidationEntry(
|
||||
|
||||
Reference in New Issue
Block a user