Add unit tests for AST parsing and security sink detection

- Created `StellaOps.AuditPack.Tests.csproj` for unit testing the AuditPack library.
- Implemented comprehensive unit tests in `index.test.js` for AST parsing, covering various JavaScript and TypeScript constructs including functions, classes, decorators, and JSX.
- Added `sink-detect.test.js` to test security sink detection patterns, validating command injection, SQL injection, file write, deserialization, SSRF, NoSQL injection, and more.
- Included tests for taint source detection in various contexts such as Express, Koa, and AWS Lambda.
This commit is contained in:
StellaOps Bot
2025-12-23 09:23:42 +02:00
parent 7e384ab610
commit 56e2dc01ee
96 changed files with 8555 additions and 1455 deletions

View File

@@ -19,8 +19,9 @@ public sealed class SbomDiffEngine
SbomId toId,
IReadOnlyList<ComponentRef> toComponents)
{
var fromByPurl = fromComponents.ToDictionary(c => c.Purl, c => c);
var toByPurl = toComponents.ToDictionary(c => c.Purl, c => c);
// Match by package identity (PURL without version) to detect version changes
var fromByIdentity = fromComponents.ToDictionary(c => GetPackageIdentity(c), c => c);
var toByIdentity = toComponents.ToDictionary(c => GetPackageIdentity(c), c => c);
var deltas = new List<ComponentDelta>();
var added = 0;
@@ -31,9 +32,9 @@ public sealed class SbomDiffEngine
var isBreaking = false;
// Find added and modified components
foreach (var (purl, toComp) in toByPurl)
foreach (var (identity, toComp) in toByIdentity)
{
if (!fromByPurl.TryGetValue(purl, out var fromComp))
if (!fromByIdentity.TryGetValue(identity, out var fromComp))
{
// Added
deltas.Add(new ComponentDelta
@@ -80,9 +81,9 @@ public sealed class SbomDiffEngine
}
// Find removed components
foreach (var (purl, fromComp) in fromByPurl)
foreach (var (identity, fromComp) in fromByIdentity)
{
if (!toByPurl.ContainsKey(purl))
if (!toByIdentity.ContainsKey(identity))
{
deltas.Add(new ComponentDelta
{
@@ -192,4 +193,25 @@ public sealed class SbomDiffEngine
var hashBytes = SHA256.HashData(Encoding.UTF8.GetBytes(json));
return Convert.ToHexStringLower(hashBytes);
}
/// <summary>
/// Gets the package identity (PURL without version) for matching.
/// </summary>
private static string GetPackageIdentity(ComponentRef component)
{
// Strip version from PURL to match by package identity
// PURL format: pkg:type/namespace/name@version?qualifiers#subpath
var purl = component.Purl;
var atIndex = purl.IndexOf('@');
if (atIndex > 0)
{
var beforeAt = purl[..atIndex];
// Also preserve qualifiers/subpath after version if present
var queryIndex = purl.IndexOf('?', atIndex);
var hashIndex = purl.IndexOf('#', atIndex);
var suffixIndex = queryIndex >= 0 ? queryIndex : hashIndex;
return suffixIndex > 0 ? beforeAt + purl[suffixIndex..] : beforeAt;
}
return purl;
}
}