feat: add security sink detection patterns for JavaScript/TypeScript

- Introduced `sink-detect.js` with various security sink detection patterns categorized by type (e.g., command injection, SQL injection, file operations).
- Implemented functions to build a lookup map for fast sink detection and to match sink calls against known patterns.
- Added `package-lock.json` for dependency management.
This commit is contained in:
StellaOps Bot
2025-12-22 23:21:21 +02:00
parent 3ba7157b00
commit 5146204f1b
529 changed files with 73579 additions and 5985 deletions

View File

@@ -1,11 +1,14 @@
namespace StellaOps.Interop.Tests;
// -----------------------------------------------------------------------------
// ToolManager.cs
// Sprint: SPRINT_5100_0003_0001_sbom_interop_roundtrip
// Task: T1 - Interop Test Harness
// Description: Manages execution of external tools (Syft, Grype, cosign).
// -----------------------------------------------------------------------------
using System.Diagnostics;
using System.Text;
/// <summary>
/// Manages execution of external tools for interop testing.
/// </summary>
namespace StellaOps.Interop.Tests;
public sealed class ToolManager
{
private readonly string _workDir;
@@ -15,110 +18,66 @@ public sealed class ToolManager
_workDir = workDir;
}
/// <summary>
/// Verify that a tool is available and executable.
/// </summary>
public async Task<bool> VerifyToolAsync(string toolName, string testArgs, CancellationToken ct = default)
public async Task VerifyToolAsync(string tool, string versionArg)
{
try
var result = await RunAsync(tool, versionArg, CancellationToken.None);
if (!result.Success)
{
var result = await RunAsync(toolName, testArgs, ct);
return result.Success || result.ExitCode == 0; // Some tools return 0 even on --version
}
catch
{
return false;
throw new InvalidOperationException(
$"Tool '{tool}' is not available or failed verification: {result.Error}");
}
}
/// <summary>
/// Run an external tool with arguments.
/// </summary>
public async Task<ToolResult> RunAsync(
string toolName,
string tool,
string arguments,
CancellationToken ct = default,
int timeoutMs = 300000) // 5 minute default timeout
CancellationToken ct,
int timeoutSeconds = 300)
{
var startInfo = new ProcessStartInfo
{
FileName = toolName,
Arguments = arguments,
WorkingDirectory = _workDir,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = startInfo };
var outputBuilder = new StringBuilder();
var errorBuilder = new StringBuilder();
process.OutputDataReceived += (sender, e) =>
{
if (e.Data != null)
outputBuilder.AppendLine(e.Data);
};
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data != null)
errorBuilder.AppendLine(e.Data);
};
try
{
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = tool,
Arguments = arguments,
WorkingDirectory = _workDir,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
using var cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
cts.CancelAfter(timeoutMs);
var outputTask = process.StandardOutput.ReadToEndAsync(ct);
var errorTask = process.StandardError.ReadToEndAsync(ct);
await process.WaitForExitAsync(cts.Token);
var completed = await Task.WhenAny(
process.WaitForExitAsync(ct),
Task.Delay(TimeSpan.FromSeconds(timeoutSeconds), ct));
var output = outputBuilder.ToString();
var error = errorBuilder.ToString();
var exitCode = process.ExitCode;
return new ToolResult(
Success: exitCode == 0,
ExitCode: exitCode,
Output: output,
Error: string.IsNullOrWhiteSpace(error) ? null : error);
}
catch (OperationCanceledException)
{
try
if (!process.HasExited)
{
if (!process.HasExited)
process.Kill();
}
catch
{
// Ignore kill failures
process.Kill(entireProcessTree: true);
return new ToolResult(false, "", "Process timed out");
}
return new ToolResult(
Success: false,
ExitCode: -1,
Output: outputBuilder.ToString(),
Error: $"Tool execution timed out after {timeoutMs}ms");
var output = await outputTask;
var error = await errorTask;
if (process.ExitCode != 0)
{
return new ToolResult(false, output, error);
}
return new ToolResult(true, output);
}
catch (Exception ex)
{
return new ToolResult(
Success: false,
ExitCode: -1,
Output: outputBuilder.ToString(),
Error: $"Tool execution failed: {ex.Message}");
return new ToolResult(false, "", ex.Message);
}
}
}
public sealed record ToolResult(
bool Success,
int ExitCode,
string Output,
string? Error = null);