feat: Add native binary analyzer test utilities and implement SM2 signing tests
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
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.
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
namespace StellaOps.Scanner.Analyzers.Lang;
|
||||
|
||||
/// <summary>
|
||||
/// Base record representing evidence of a capability usage in source code.
|
||||
/// This provides a consistent structure across all language analyzers for
|
||||
/// reporting detected capabilities.
|
||||
/// </summary>
|
||||
public record CapabilityEvidence
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new capability evidence instance.
|
||||
/// </summary>
|
||||
/// <param name="kind">The capability category.</param>
|
||||
/// <param name="sourceFile">The source file path where the capability was detected.</param>
|
||||
/// <param name="sourceLine">The line number of the detection.</param>
|
||||
/// <param name="pattern">The function, API, or pattern that was matched.</param>
|
||||
/// <param name="snippet">Optional code snippet for context.</param>
|
||||
/// <param name="confidence">Confidence level (0.0 to 1.0).</param>
|
||||
/// <param name="risk">Risk level of this usage.</param>
|
||||
public CapabilityEvidence(
|
||||
CapabilityKind kind,
|
||||
string sourceFile,
|
||||
int sourceLine,
|
||||
string pattern,
|
||||
string? snippet = null,
|
||||
float confidence = 1.0f,
|
||||
CapabilityRisk risk = CapabilityRisk.Low)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(sourceFile, nameof(sourceFile));
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(pattern, nameof(pattern));
|
||||
|
||||
Kind = kind;
|
||||
SourceFile = NormalizePath(sourceFile);
|
||||
SourceLine = sourceLine;
|
||||
Pattern = pattern;
|
||||
Snippet = snippet;
|
||||
Confidence = Math.Clamp(confidence, 0f, 1f);
|
||||
Risk = risk;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The capability category.
|
||||
/// </summary>
|
||||
public CapabilityKind Kind { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The source file where the capability is used (normalized to forward slashes).
|
||||
/// </summary>
|
||||
public string SourceFile { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The line number of the capability usage (1-based).
|
||||
/// </summary>
|
||||
public int SourceLine { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The function name, API, or pattern that was matched.
|
||||
/// </summary>
|
||||
public string Pattern { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional snippet of the code for context (may be truncated).
|
||||
/// </summary>
|
||||
public string? Snippet { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Confidence level from 0.0 (low) to 1.0 (high).
|
||||
/// Lower confidence indicates pattern-based detection that may have false positives.
|
||||
/// </summary>
|
||||
public float Confidence { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Risk level associated with this capability usage.
|
||||
/// </summary>
|
||||
public CapabilityRisk Risk { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a unique key for deduplication purposes.
|
||||
/// </summary>
|
||||
public string DeduplicationKey => $"{Kind}|{SourceFile}|{SourceLine}|{Pattern}";
|
||||
|
||||
/// <summary>
|
||||
/// Creates metadata entries for SBOM generation.
|
||||
/// </summary>
|
||||
public virtual IEnumerable<KeyValuePair<string, string?>> CreateMetadata()
|
||||
{
|
||||
yield return new KeyValuePair<string, string?>("capability.kind", Kind.ToString().ToLowerInvariant());
|
||||
yield return new KeyValuePair<string, string?>("capability.source", $"{SourceFile}:{SourceLine}");
|
||||
yield return new KeyValuePair<string, string?>("capability.pattern", Pattern);
|
||||
yield return new KeyValuePair<string, string?>("capability.risk", Risk.ToString().ToLowerInvariant());
|
||||
yield return new KeyValuePair<string, string?>("capability.confidence", Confidence.ToString("F2", CultureInfo.InvariantCulture));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Snippet))
|
||||
{
|
||||
// Truncate snippet to reasonable length for metadata
|
||||
var truncated = Snippet.Length > 200 ? Snippet[..197] + "..." : Snippet;
|
||||
yield return new KeyValuePair<string, string?>("capability.snippet", truncated);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a LanguageComponentEvidence from this capability evidence.
|
||||
/// </summary>
|
||||
public LanguageComponentEvidence ToLanguageEvidence()
|
||||
{
|
||||
return new LanguageComponentEvidence(
|
||||
Kind: LanguageEvidenceKind.Metadata,
|
||||
Source: SourceFile,
|
||||
Locator: $"line:{SourceLine}",
|
||||
Value: $"{Kind}:{Pattern}",
|
||||
Sha256: null);
|
||||
}
|
||||
|
||||
private static string NormalizePath(string path)
|
||||
=> path.Replace('\\', '/');
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
namespace StellaOps.Scanner.Analyzers.Lang;
|
||||
|
||||
/// <summary>
|
||||
/// Categories of runtime capabilities that can be detected in source code.
|
||||
/// These represent security-relevant functionality that may indicate potential
|
||||
/// attack surface or require careful review.
|
||||
/// </summary>
|
||||
public enum CapabilityKind
|
||||
{
|
||||
/// <summary>
|
||||
/// Command/process execution capabilities.
|
||||
/// Examples: exec, spawn, ProcessBuilder, os/exec, Process.Start
|
||||
/// </summary>
|
||||
Exec,
|
||||
|
||||
/// <summary>
|
||||
/// Filesystem operations including read, write, delete, and permission changes.
|
||||
/// Examples: open, write, unlink, chmod, fs.readFile
|
||||
/// </summary>
|
||||
Filesystem,
|
||||
|
||||
/// <summary>
|
||||
/// Network I/O including sockets, HTTP clients, and network listeners.
|
||||
/// Examples: Socket, HttpClient, net.Dial, fetch
|
||||
/// </summary>
|
||||
Network,
|
||||
|
||||
/// <summary>
|
||||
/// Environment variable access for reading or writing.
|
||||
/// Examples: getenv, process.env, os.Getenv, Environment.GetEnvironmentVariable
|
||||
/// </summary>
|
||||
Environment,
|
||||
|
||||
/// <summary>
|
||||
/// Object serialization and deserialization operations.
|
||||
/// Examples: serialize/unserialize, ObjectInputStream, JSON.parse with reviver
|
||||
/// </summary>
|
||||
Serialization,
|
||||
|
||||
/// <summary>
|
||||
/// Cryptographic operations including encryption, hashing, and signing.
|
||||
/// Examples: AES, RSA, SHA256, crypto.*, openssl_*
|
||||
/// </summary>
|
||||
Crypto,
|
||||
|
||||
/// <summary>
|
||||
/// Database access and query execution.
|
||||
/// Examples: SQL queries, MongoDB operations, database/sql, SqlConnection
|
||||
/// </summary>
|
||||
Database,
|
||||
|
||||
/// <summary>
|
||||
/// Dynamic code execution including eval and runtime code generation.
|
||||
/// Examples: eval, Function(), DynamicMethod, ScriptEngine.eval
|
||||
/// </summary>
|
||||
DynamicCode,
|
||||
|
||||
/// <summary>
|
||||
/// Reflection and runtime type introspection.
|
||||
/// Examples: reflect.*, Type.GetMethod, Class.forName
|
||||
/// </summary>
|
||||
Reflection,
|
||||
|
||||
/// <summary>
|
||||
/// Native code interop including FFI, P/Invoke, JNI, and CGO.
|
||||
/// Examples: DllImport, import "C", System.loadLibrary, FFI::cdef
|
||||
/// </summary>
|
||||
NativeCode,
|
||||
|
||||
/// <summary>
|
||||
/// File upload handling (web-specific).
|
||||
/// Examples: $_FILES, move_uploaded_file, multipart handling
|
||||
/// </summary>
|
||||
Upload,
|
||||
|
||||
/// <summary>
|
||||
/// Stream wrappers and protocol handlers.
|
||||
/// Examples: php://, data://, custom URL schemes
|
||||
/// </summary>
|
||||
StreamWrapper,
|
||||
|
||||
/// <summary>
|
||||
/// Session management and authentication state.
|
||||
/// Examples: session_start, $_SESSION, express-session
|
||||
/// </summary>
|
||||
Session,
|
||||
|
||||
/// <summary>
|
||||
/// Output control and HTTP response manipulation.
|
||||
/// Examples: header, setcookie, ob_start with callback
|
||||
/// </summary>
|
||||
OutputControl,
|
||||
|
||||
/// <summary>
|
||||
/// Error handling that may expose sensitive information.
|
||||
/// Examples: phpinfo, stack trace exposure, error_reporting
|
||||
/// </summary>
|
||||
ErrorHandling,
|
||||
|
||||
/// <summary>
|
||||
/// Plugin/module loading at runtime.
|
||||
/// Examples: plugin.Open, Assembly.LoadFrom, dlopen
|
||||
/// </summary>
|
||||
PluginLoading,
|
||||
|
||||
/// <summary>
|
||||
/// Language-specific capabilities not covered by other categories.
|
||||
/// </summary>
|
||||
Other
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
namespace StellaOps.Scanner.Analyzers.Lang;
|
||||
|
||||
/// <summary>
|
||||
/// Risk levels for capability usage.
|
||||
/// Used to prioritize security review and flag potentially dangerous code patterns.
|
||||
/// </summary>
|
||||
public enum CapabilityRisk
|
||||
{
|
||||
/// <summary>
|
||||
/// Low risk - common, safe usage patterns.
|
||||
/// Examples: reading files with sanitized paths, standard logging.
|
||||
/// </summary>
|
||||
Low = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Medium risk - potentially dangerous in certain contexts.
|
||||
/// Requires context-aware security review.
|
||||
/// Examples: environment variable access, standard network operations.
|
||||
/// </summary>
|
||||
Medium = 1,
|
||||
|
||||
/// <summary>
|
||||
/// High risk - requires careful security review.
|
||||
/// Often involves untrusted input or sensitive operations.
|
||||
/// Examples: dynamic assembly loading, reflection invocation, native code.
|
||||
/// </summary>
|
||||
High = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Critical risk - often associated with security vulnerabilities.
|
||||
/// Should be flagged for immediate security review.
|
||||
/// Examples: eval, command execution, unsafe deserialization.
|
||||
/// </summary>
|
||||
Critical = 3
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Lang;
|
||||
|
||||
/// <summary>
|
||||
/// Aggregates capability scan results from source code analysis.
|
||||
/// Provides methods for querying and summarizing detected capabilities.
|
||||
/// </summary>
|
||||
public class CapabilityScanResult
|
||||
{
|
||||
private readonly IReadOnlyList<CapabilityEvidence> _evidences;
|
||||
private ILookup<CapabilityKind, CapabilityEvidence>? _byKind;
|
||||
private ILookup<CapabilityRisk, CapabilityEvidence>? _byRisk;
|
||||
private ILookup<string, CapabilityEvidence>? _byFile;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new capability scan result.
|
||||
/// </summary>
|
||||
public CapabilityScanResult(IReadOnlyList<CapabilityEvidence> evidences)
|
||||
{
|
||||
_evidences = evidences ?? Array.Empty<CapabilityEvidence>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// All capability evidences found.
|
||||
/// </summary>
|
||||
public IReadOnlyList<CapabilityEvidence> 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, CapabilityEvidence> EvidencesByKind
|
||||
=> _byKind ??= _evidences.ToLookup(e => e.Kind);
|
||||
|
||||
/// <summary>
|
||||
/// Gets evidences grouped by risk level.
|
||||
/// </summary>
|
||||
public ILookup<CapabilityRisk, CapabilityEvidence> EvidencesByRisk
|
||||
=> _byRisk ??= _evidences.ToLookup(e => e.Risk);
|
||||
|
||||
/// <summary>
|
||||
/// Gets evidences grouped by source file.
|
||||
/// </summary>
|
||||
public ILookup<string, CapabilityEvidence> EvidencesByFile
|
||||
=> _byFile ??= _evidences.ToLookup(e => e.SourceFile, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all critical risk evidences.
|
||||
/// </summary>
|
||||
public IEnumerable<CapabilityEvidence> CriticalRiskEvidences
|
||||
=> _evidences.Where(e => e.Risk == CapabilityRisk.Critical);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all high risk evidences.
|
||||
/// </summary>
|
||||
public IEnumerable<CapabilityEvidence> 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<CapabilityEvidence> GetByKind(CapabilityKind kind)
|
||||
=> EvidencesByKind[kind];
|
||||
|
||||
/// <summary>
|
||||
/// Gets evidences at or above a specific risk level.
|
||||
/// </summary>
|
||||
public IEnumerable<CapabilityEvidence> GetByMinimumRisk(CapabilityRisk minRisk)
|
||||
=> _evidences.Where(e => e.Risk >= minRisk);
|
||||
|
||||
/// <summary>
|
||||
/// Creates metadata entries for the scan result.
|
||||
/// </summary>
|
||||
public virtual 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 CapabilitySummary CreateSummary()
|
||||
{
|
||||
return new CapabilitySummary(
|
||||
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(),
|
||||
HasUpload: EvidencesByKind[CapabilityKind.Upload].Any(),
|
||||
HasSession: EvidencesByKind[CapabilityKind.Session].Any(),
|
||||
CriticalCount: CriticalRiskEvidences.Count(),
|
||||
HighRiskCount: HighRiskEvidences.Count(),
|
||||
TotalCount: _evidences.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Empty scan result with no capabilities detected.
|
||||
/// </summary>
|
||||
public static CapabilityScanResult Empty { get; } = new(Array.Empty<CapabilityEvidence>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Summary of detected capabilities as boolean flags.
|
||||
/// </summary>
|
||||
public sealed record CapabilitySummary(
|
||||
bool HasExec,
|
||||
bool HasFilesystem,
|
||||
bool HasNetwork,
|
||||
bool HasEnvironment,
|
||||
bool HasSerialization,
|
||||
bool HasCrypto,
|
||||
bool HasDatabase,
|
||||
bool HasDynamicCode,
|
||||
bool HasReflection,
|
||||
bool HasNativeCode,
|
||||
bool HasUpload,
|
||||
bool HasSession,
|
||||
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_upload", HasUpload.ToString().ToLowerInvariant());
|
||||
yield return new KeyValuePair<string, string?>("capability.has_session", HasSession.ToString().ToLowerInvariant());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
namespace StellaOps.Scanner.Analyzers.Lang;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for language-specific capability scanners.
|
||||
/// Implementations detect security-relevant capabilities in source code files.
|
||||
/// </summary>
|
||||
public interface ICapabilityScanner
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the language identifier (e.g., "go", "dotnet", "java", "node", "php").
|
||||
/// </summary>
|
||||
string LanguageId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file extensions this scanner can process (e.g., ".go", ".cs", ".java", ".js").
|
||||
/// </summary>
|
||||
IReadOnlySet<string> SupportedExtensions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Scans source code content for capability usage.
|
||||
/// </summary>
|
||||
/// <param name="content">The source code content.</param>
|
||||
/// <param name="filePath">The path to the source file (for reporting).</param>
|
||||
/// <returns>List of detected capability evidences.</returns>
|
||||
IReadOnlyList<CapabilityEvidence> ScanContent(string content, string filePath);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if this scanner can process the given file.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The file path to check.</param>
|
||||
/// <returns>True if this scanner can process the file.</returns>
|
||||
bool CanScan(string filePath)
|
||||
{
|
||||
var extension = Path.GetExtension(filePath);
|
||||
return !string.IsNullOrEmpty(extension) &&
|
||||
SupportedExtensions.Contains(extension.ToLowerInvariant());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines a capability detection pattern with associated metadata.
|
||||
/// Used by scanners to configure what patterns to look for.
|
||||
/// </summary>
|
||||
/// <param name="Pattern">The regex or literal pattern to match.</param>
|
||||
/// <param name="Kind">The capability kind this pattern detects.</param>
|
||||
/// <param name="Risk">The risk level associated with matches.</param>
|
||||
/// <param name="Confidence">Base confidence for matches (0.0-1.0).</param>
|
||||
/// <param name="Description">Human-readable description of what this detects.</param>
|
||||
/// <param name="IsRegex">Whether Pattern is a regex (true) or literal match (false).</param>
|
||||
public sealed record CapabilityPattern(
|
||||
string Pattern,
|
||||
CapabilityKind Kind,
|
||||
CapabilityRisk Risk,
|
||||
float Confidence = 1.0f,
|
||||
string? Description = null,
|
||||
bool IsRegex = true);
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for building capability patterns.
|
||||
/// </summary>
|
||||
public static class CapabilityPatterns
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a critical risk exec pattern.
|
||||
/// </summary>
|
||||
public static CapabilityPattern CriticalExec(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.Exec, CapabilityRisk.Critical, 1.0f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a high risk exec pattern.
|
||||
/// </summary>
|
||||
public static CapabilityPattern HighExec(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.Exec, CapabilityRisk.High, 1.0f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a critical risk dynamic code pattern.
|
||||
/// </summary>
|
||||
public static CapabilityPattern CriticalDynamicCode(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.DynamicCode, CapabilityRisk.Critical, 1.0f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a high risk native code pattern.
|
||||
/// </summary>
|
||||
public static CapabilityPattern HighNativeCode(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.NativeCode, CapabilityRisk.High, 1.0f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a critical risk native code pattern (unsafe operations).
|
||||
/// </summary>
|
||||
public static CapabilityPattern CriticalNativeCode(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.NativeCode, CapabilityRisk.Critical, 1.0f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a critical risk serialization pattern (unsafe deserialization).
|
||||
/// </summary>
|
||||
public static CapabilityPattern CriticalSerialization(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.Serialization, CapabilityRisk.Critical, 1.0f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a medium risk serialization pattern.
|
||||
/// </summary>
|
||||
public static CapabilityPattern MediumSerialization(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.Serialization, CapabilityRisk.Medium, 0.9f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a medium risk filesystem pattern.
|
||||
/// </summary>
|
||||
public static CapabilityPattern MediumFilesystem(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.Filesystem, CapabilityRisk.Medium, 0.9f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a high risk filesystem pattern.
|
||||
/// </summary>
|
||||
public static CapabilityPattern HighFilesystem(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.Filesystem, CapabilityRisk.High, 1.0f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a medium risk network pattern.
|
||||
/// </summary>
|
||||
public static CapabilityPattern MediumNetwork(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.Network, CapabilityRisk.Medium, 0.9f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a medium risk database pattern.
|
||||
/// </summary>
|
||||
public static CapabilityPattern MediumDatabase(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.Database, CapabilityRisk.Medium, 0.9f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a high risk database pattern (raw SQL).
|
||||
/// </summary>
|
||||
public static CapabilityPattern HighDatabase(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.Database, CapabilityRisk.High, 0.95f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a medium risk environment pattern.
|
||||
/// </summary>
|
||||
public static CapabilityPattern MediumEnvironment(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.Environment, CapabilityRisk.Medium, 0.9f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a low risk crypto pattern.
|
||||
/// </summary>
|
||||
public static CapabilityPattern LowCrypto(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.Crypto, CapabilityRisk.Low, 0.9f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a medium risk reflection pattern.
|
||||
/// </summary>
|
||||
public static CapabilityPattern MediumReflection(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.Reflection, CapabilityRisk.Medium, 0.85f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a high risk reflection pattern.
|
||||
/// </summary>
|
||||
public static CapabilityPattern HighReflection(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.Reflection, CapabilityRisk.High, 0.95f, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a high risk plugin loading pattern.
|
||||
/// </summary>
|
||||
public static CapabilityPattern HighPluginLoading(string pattern, string? description = null)
|
||||
=> new(pattern, CapabilityKind.PluginLoading, CapabilityRisk.High, 1.0f, description);
|
||||
}
|
||||
@@ -3,6 +3,7 @@ global using System.Collections.Concurrent;
|
||||
global using System.Collections.Generic;
|
||||
global using System.Collections.Immutable;
|
||||
global using System.Diagnostics.CodeAnalysis;
|
||||
global using System.Globalization;
|
||||
global using System.IO;
|
||||
global using System.Linq;
|
||||
global using System.Text.Json;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<LangVersion>preview</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<EnableDefaultItems>false</EnableDefaultItems>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user