Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Manifest Integrity / Audit SHA256SUMS Files (push) Has been cancelled
Manifest Integrity / Validate Schema Integrity (push) Has been cancelled
Manifest Integrity / Validate Contract Documents (push) Has been cancelled
Manifest Integrity / Validate Pack Fixtures (push) Has been cancelled
Manifest Integrity / Verify Merkle Roots (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
- Introduced `NativeTestBase` class for ELF, PE, and Mach-O binary parsing helpers and assertions. - Created `TestCryptoFactory` for SM2 cryptographic provider setup and key generation. - Implemented `Sm2SigningTests` to validate signing functionality with environment gate checks. - Developed console export service and store with comprehensive unit tests for export status management.
228 lines
9.4 KiB
C#
228 lines
9.4 KiB
C#
using System.Collections.Immutable;
|
|
using System.Globalization;
|
|
|
|
namespace StellaOps.Scanner.Analyzers.Lang.Go.Internal;
|
|
|
|
/// <summary>
|
|
/// Aggregates capability scan results from Go source code analysis.
|
|
/// </summary>
|
|
internal sealed class GoCapabilityScanResult
|
|
{
|
|
private readonly IReadOnlyList<GoCapabilityEvidence> _evidences;
|
|
private ILookup<CapabilityKind, GoCapabilityEvidence>? _byKind;
|
|
private ILookup<CapabilityRisk, GoCapabilityEvidence>? _byRisk;
|
|
private ILookup<string, GoCapabilityEvidence>? _byFile;
|
|
|
|
public GoCapabilityScanResult(IReadOnlyList<GoCapabilityEvidence> evidences)
|
|
{
|
|
_evidences = evidences ?? Array.Empty<GoCapabilityEvidence>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// All capability evidences found.
|
|
/// </summary>
|
|
public IReadOnlyList<GoCapabilityEvidence> Evidences => _evidences;
|
|
|
|
/// <summary>
|
|
/// Gets whether any capabilities were detected.
|
|
/// </summary>
|
|
public bool HasCapabilities => _evidences.Count > 0;
|
|
|
|
/// <summary>
|
|
/// Gets evidences grouped by capability kind.
|
|
/// </summary>
|
|
public ILookup<CapabilityKind, GoCapabilityEvidence> EvidencesByKind
|
|
=> _byKind ??= _evidences.ToLookup(e => e.Kind);
|
|
|
|
/// <summary>
|
|
/// Gets evidences grouped by risk level.
|
|
/// </summary>
|
|
public ILookup<CapabilityRisk, GoCapabilityEvidence> EvidencesByRisk
|
|
=> _byRisk ??= _evidences.ToLookup(e => e.Risk);
|
|
|
|
/// <summary>
|
|
/// Gets evidences grouped by source file.
|
|
/// </summary>
|
|
public ILookup<string, GoCapabilityEvidence> EvidencesByFile
|
|
=> _byFile ??= _evidences.ToLookup(e => e.SourceFile, StringComparer.OrdinalIgnoreCase);
|
|
|
|
/// <summary>
|
|
/// Gets all critical risk evidences.
|
|
/// </summary>
|
|
public IEnumerable<GoCapabilityEvidence> CriticalRiskEvidences
|
|
=> _evidences.Where(e => e.Risk == CapabilityRisk.Critical);
|
|
|
|
/// <summary>
|
|
/// Gets all high risk evidences.
|
|
/// </summary>
|
|
public IEnumerable<GoCapabilityEvidence> HighRiskEvidences
|
|
=> _evidences.Where(e => e.Risk == CapabilityRisk.High);
|
|
|
|
/// <summary>
|
|
/// Gets the set of detected capability kinds.
|
|
/// </summary>
|
|
public IReadOnlySet<CapabilityKind> DetectedKinds
|
|
=> _evidences.Select(e => e.Kind).ToHashSet();
|
|
|
|
/// <summary>
|
|
/// Gets the highest risk level found.
|
|
/// </summary>
|
|
public CapabilityRisk HighestRisk
|
|
=> _evidences.Count > 0
|
|
? _evidences.Max(e => e.Risk)
|
|
: CapabilityRisk.Low;
|
|
|
|
/// <summary>
|
|
/// Gets evidences for a specific capability kind.
|
|
/// </summary>
|
|
public IEnumerable<GoCapabilityEvidence> GetByKind(CapabilityKind kind)
|
|
=> EvidencesByKind[kind];
|
|
|
|
/// <summary>
|
|
/// Gets evidences at or above a specific risk level.
|
|
/// </summary>
|
|
public IEnumerable<GoCapabilityEvidence> GetByMinimumRisk(CapabilityRisk minRisk)
|
|
=> _evidences.Where(e => e.Risk >= minRisk);
|
|
|
|
/// <summary>
|
|
/// Creates metadata entries for the scan result.
|
|
/// </summary>
|
|
public IEnumerable<KeyValuePair<string, string?>> CreateMetadata()
|
|
{
|
|
yield return new KeyValuePair<string, string?>(
|
|
"capability.total_count",
|
|
_evidences.Count.ToString(CultureInfo.InvariantCulture));
|
|
|
|
// Count by kind (only emit non-zero)
|
|
foreach (var kindGroup in EvidencesByKind.OrderBy(g => g.Key.ToString(), StringComparer.Ordinal))
|
|
{
|
|
yield return new KeyValuePair<string, string?>(
|
|
$"capability.{kindGroup.Key.ToString().ToLowerInvariant()}_count",
|
|
kindGroup.Count().ToString(CultureInfo.InvariantCulture));
|
|
}
|
|
|
|
// Count by risk
|
|
var criticalCount = CriticalRiskEvidences.Count();
|
|
var highCount = HighRiskEvidences.Count();
|
|
var mediumCount = _evidences.Count(e => e.Risk == CapabilityRisk.Medium);
|
|
var lowCount = _evidences.Count(e => e.Risk == CapabilityRisk.Low);
|
|
|
|
yield return new KeyValuePair<string, string?>("capability.critical_risk_count", criticalCount.ToString(CultureInfo.InvariantCulture));
|
|
yield return new KeyValuePair<string, string?>("capability.high_risk_count", highCount.ToString(CultureInfo.InvariantCulture));
|
|
yield return new KeyValuePair<string, string?>("capability.medium_risk_count", mediumCount.ToString(CultureInfo.InvariantCulture));
|
|
yield return new KeyValuePair<string, string?>("capability.low_risk_count", lowCount.ToString(CultureInfo.InvariantCulture));
|
|
|
|
// Highest risk
|
|
if (_evidences.Count > 0)
|
|
{
|
|
yield return new KeyValuePair<string, string?>(
|
|
"capability.highest_risk",
|
|
HighestRisk.ToString().ToLowerInvariant());
|
|
}
|
|
|
|
// Detected capabilities as semicolon-separated list
|
|
if (DetectedKinds.Count > 0)
|
|
{
|
|
yield return new KeyValuePair<string, string?>(
|
|
"capability.detected_kinds",
|
|
string.Join(';', DetectedKinds.OrderBy(k => k.ToString(), StringComparer.Ordinal).Select(k => k.ToString().ToLowerInvariant())));
|
|
}
|
|
|
|
// Files with critical issues (first 10)
|
|
var criticalFiles = CriticalRiskEvidences
|
|
.Select(e => e.SourceFile)
|
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
.OrderBy(f => f, StringComparer.Ordinal)
|
|
.ToList();
|
|
|
|
if (criticalFiles.Count > 0)
|
|
{
|
|
yield return new KeyValuePair<string, string?>(
|
|
"capability.critical_files",
|
|
string.Join(';', criticalFiles.Take(10)));
|
|
|
|
if (criticalFiles.Count > 10)
|
|
{
|
|
yield return new KeyValuePair<string, string?>(
|
|
"capability.critical_files_truncated",
|
|
"true");
|
|
}
|
|
}
|
|
|
|
// Unique patterns detected
|
|
var uniquePatterns = _evidences
|
|
.Select(e => e.Pattern)
|
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
.Count();
|
|
|
|
yield return new KeyValuePair<string, string?>(
|
|
"capability.unique_pattern_count",
|
|
uniquePatterns.ToString(CultureInfo.InvariantCulture));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a summary of detected capabilities.
|
|
/// </summary>
|
|
public GoCapabilitySummary CreateSummary()
|
|
{
|
|
return new GoCapabilitySummary(
|
|
HasExec: EvidencesByKind[CapabilityKind.Exec].Any(),
|
|
HasFilesystem: EvidencesByKind[CapabilityKind.Filesystem].Any(),
|
|
HasNetwork: EvidencesByKind[CapabilityKind.Network].Any(),
|
|
HasEnvironment: EvidencesByKind[CapabilityKind.Environment].Any(),
|
|
HasSerialization: EvidencesByKind[CapabilityKind.Serialization].Any(),
|
|
HasCrypto: EvidencesByKind[CapabilityKind.Crypto].Any(),
|
|
HasDatabase: EvidencesByKind[CapabilityKind.Database].Any(),
|
|
HasDynamicCode: EvidencesByKind[CapabilityKind.DynamicCode].Any(),
|
|
HasReflection: EvidencesByKind[CapabilityKind.Reflection].Any(),
|
|
HasNativeCode: EvidencesByKind[CapabilityKind.NativeCode].Any(),
|
|
HasPluginLoading: EvidencesByKind[CapabilityKind.PluginLoading].Any(),
|
|
CriticalCount: CriticalRiskEvidences.Count(),
|
|
HighRiskCount: HighRiskEvidences.Count(),
|
|
TotalCount: _evidences.Count);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Empty scan result with no capabilities detected.
|
|
/// </summary>
|
|
public static GoCapabilityScanResult Empty { get; } = new(Array.Empty<GoCapabilityEvidence>());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Summary of detected Go capabilities.
|
|
/// </summary>
|
|
internal sealed record GoCapabilitySummary(
|
|
bool HasExec,
|
|
bool HasFilesystem,
|
|
bool HasNetwork,
|
|
bool HasEnvironment,
|
|
bool HasSerialization,
|
|
bool HasCrypto,
|
|
bool HasDatabase,
|
|
bool HasDynamicCode,
|
|
bool HasReflection,
|
|
bool HasNativeCode,
|
|
bool HasPluginLoading,
|
|
int CriticalCount,
|
|
int HighRiskCount,
|
|
int TotalCount)
|
|
{
|
|
/// <summary>
|
|
/// Creates metadata entries for the summary.
|
|
/// </summary>
|
|
public IEnumerable<KeyValuePair<string, string?>> CreateMetadata()
|
|
{
|
|
yield return new KeyValuePair<string, string?>("capability.has_exec", HasExec.ToString().ToLowerInvariant());
|
|
yield return new KeyValuePair<string, string?>("capability.has_filesystem", HasFilesystem.ToString().ToLowerInvariant());
|
|
yield return new KeyValuePair<string, string?>("capability.has_network", HasNetwork.ToString().ToLowerInvariant());
|
|
yield return new KeyValuePair<string, string?>("capability.has_environment", HasEnvironment.ToString().ToLowerInvariant());
|
|
yield return new KeyValuePair<string, string?>("capability.has_serialization", HasSerialization.ToString().ToLowerInvariant());
|
|
yield return new KeyValuePair<string, string?>("capability.has_crypto", HasCrypto.ToString().ToLowerInvariant());
|
|
yield return new KeyValuePair<string, string?>("capability.has_database", HasDatabase.ToString().ToLowerInvariant());
|
|
yield return new KeyValuePair<string, string?>("capability.has_dynamic_code", HasDynamicCode.ToString().ToLowerInvariant());
|
|
yield return new KeyValuePair<string, string?>("capability.has_reflection", HasReflection.ToString().ToLowerInvariant());
|
|
yield return new KeyValuePair<string, string?>("capability.has_native_code", HasNativeCode.ToString().ToLowerInvariant());
|
|
yield return new KeyValuePair<string, string?>("capability.has_plugin_loading", HasPluginLoading.ToString().ToLowerInvariant());
|
|
}
|
|
}
|