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

@@ -0,0 +1,298 @@
namespace StellaOps.VexLens.Trust.SourceTrust;
/// <summary>
/// Default implementation of <see cref="ITrustDecayService"/>.
/// Applies time-based trust decay, recency bonuses, and revocation penalties.
/// </summary>
public sealed class TrustDecayService : ITrustDecayService
{
public DecayResult ApplyDecay(
double baseScore,
DateTimeOffset statementTimestamp,
DecayContext context)
{
var age = context.EvaluationTime - statementTimestamp;
var ageDays = age.TotalDays;
var config = context.Configuration;
var (decayFactor, category) = CalculateDecayFactor(age, config);
// Reduce decay for statements with updates
if (context.HasUpdates && context.UpdateCount > 0)
{
// Each update reduces effective age by 10%, up to 50% reduction
var updateReduction = Math.Min(0.5, context.UpdateCount * 0.1);
decayFactor = Math.Min(1.0, decayFactor + (1.0 - decayFactor) * updateReduction);
}
var decayedScore = baseScore * decayFactor;
return new DecayResult
{
BaseScore = baseScore,
DecayFactor = decayFactor,
DecayedScore = decayedScore,
AgeDays = ageDays,
Category = category
};
}
public double CalculateRecencyBonus(
DateTimeOffset lastUpdateTimestamp,
RecencyBonusContext context)
{
var age = context.EvaluationTime - lastUpdateTimestamp;
if (age > context.RecencyWindow)
{
return 0.0;
}
// Linear decrease from max bonus to 0 over the recency window
var ratio = 1.0 - (age.TotalSeconds / context.RecencyWindow.TotalSeconds);
return context.MaxBonus * ratio;
}
public RevocationImpact CalculateRevocationImpact(
RevocationInfo revocation,
RevocationContext context)
{
if (!revocation.IsRevoked)
{
return new RevocationImpact
{
ShouldExclude = false,
Penalty = 0.0,
Explanation = "Statement is not revoked",
RecommendedAction = RevocationAction.None
};
}
// Determine impact based on revocation type
return revocation.RevocationType switch
{
RevocationType.Superseded when revocation.WasSuperseded => new RevocationImpact
{
ShouldExclude = true,
Penalty = context.SupersededPenalty,
Explanation = $"Statement superseded by {revocation.SupersededBy ?? "newer statement"}",
RecommendedAction = RevocationAction.Replace
},
RevocationType.Correction => new RevocationImpact
{
ShouldExclude = false,
Penalty = context.CorrectionPenalty,
Explanation = $"Statement corrected: {revocation.RevocationReason ?? "unspecified reason"}",
RecommendedAction = RevocationAction.Penalize
},
RevocationType.Withdrawn => new RevocationImpact
{
ShouldExclude = true,
Penalty = context.RevocationPenalty,
Explanation = $"Statement withdrawn: {revocation.RevocationReason ?? "unspecified reason"}",
RecommendedAction = RevocationAction.Exclude
},
RevocationType.Expired => new RevocationImpact
{
ShouldExclude = false,
Penalty = context.RevocationPenalty * 0.5,
Explanation = "Statement expired and was not renewed",
RecommendedAction = RevocationAction.Review
},
RevocationType.SourceRevoked => new RevocationImpact
{
ShouldExclude = true,
Penalty = context.RevocationPenalty,
Explanation = "Source has been revoked",
RecommendedAction = RevocationAction.Exclude
},
_ => new RevocationImpact
{
ShouldExclude = false,
Penalty = context.RevocationPenalty * 0.75,
Explanation = $"Statement revoked: {revocation.RevocationReason ?? "unknown reason"}",
RecommendedAction = RevocationAction.Review
}
};
}
public EffectiveTrustScore GetEffectiveScore(
double baseScore,
TrustScoreFactors factors,
DateTimeOffset evaluationTime)
{
var adjustments = new List<TrustAdjustment>();
var shouldExclude = false;
// Apply decay
var decayConfig = factors.DecayConfiguration ?? DecayConfiguration.CreateDefault();
var decayContext = new DecayContext
{
EvaluationTime = evaluationTime,
Configuration = decayConfig,
HasUpdates = factors.UpdateCount > 0,
UpdateCount = factors.UpdateCount
};
var decayResult = ApplyDecay(baseScore, factors.StatementTimestamp, decayContext);
adjustments.Add(new TrustAdjustment
{
Type = TrustAdjustmentType.Decay,
Amount = decayResult.DecayedScore - baseScore,
Reason = $"Time-based decay (age: {decayResult.AgeDays:F1} days, category: {decayResult.Category})"
});
var effectiveScore = decayResult.DecayedScore;
// Apply recency bonus if recently updated
var recencyBonus = 0.0;
if (factors.LastUpdateTimestamp.HasValue)
{
var recencyContext = new RecencyBonusContext
{
EvaluationTime = evaluationTime
};
recencyBonus = CalculateRecencyBonus(factors.LastUpdateTimestamp.Value, recencyContext);
if (recencyBonus > 0)
{
effectiveScore += recencyBonus;
adjustments.Add(new TrustAdjustment
{
Type = TrustAdjustmentType.RecencyBonus,
Amount = recencyBonus,
Reason = "Recently updated statement"
});
}
}
// Apply update bonus
if (factors.UpdateCount > 1)
{
var updateBonus = Math.Min(0.05, factors.UpdateCount * 0.01);
effectiveScore += updateBonus;
adjustments.Add(new TrustAdjustment
{
Type = TrustAdjustmentType.UpdateBonus,
Amount = updateBonus,
Reason = $"Statement has been updated {factors.UpdateCount} times"
});
}
// Apply revocation penalty
var revocationPenalty = 0.0;
if (factors.Revocation != null)
{
var revocationContext = new RevocationContext
{
EvaluationTime = evaluationTime
};
var revocationImpact = CalculateRevocationImpact(factors.Revocation, revocationContext);
if (revocationImpact.ShouldExclude)
{
shouldExclude = true;
}
revocationPenalty = revocationImpact.Penalty;
effectiveScore -= revocationPenalty;
adjustments.Add(new TrustAdjustment
{
Type = TrustAdjustmentType.RevocationPenalty,
Amount = -revocationPenalty,
Reason = revocationImpact.Explanation
});
}
// Clamp final score
effectiveScore = Math.Clamp(effectiveScore, 0.0, 1.0);
return new EffectiveTrustScore
{
BaseScore = baseScore,
EffectiveScore = effectiveScore,
DecayFactor = decayResult.DecayFactor,
RecencyBonus = recencyBonus,
RevocationPenalty = revocationPenalty,
ShouldExclude = shouldExclude,
StalenessCategory = decayResult.Category,
Adjustments = adjustments
};
}
private (double Factor, StalenessCategory Category) CalculateDecayFactor(
TimeSpan age,
DecayConfiguration config)
{
if (age <= TimeSpan.Zero)
{
return (1.0, StalenessCategory.Fresh);
}
if (age < config.FreshThreshold)
{
return (1.0, StalenessCategory.Fresh);
}
if (age < config.RecentThreshold)
{
var factor = CalculateCurveValue(
age, config.FreshThreshold, config.RecentThreshold,
1.0, 0.9, config.CurveType);
return (factor, StalenessCategory.Recent);
}
if (age < config.StaleThreshold)
{
var factor = CalculateCurveValue(
age, config.RecentThreshold, config.StaleThreshold,
0.9, 0.7, config.CurveType);
return (factor, StalenessCategory.Aging);
}
if (age < config.ExpiredThreshold)
{
var factor = CalculateCurveValue(
age, config.StaleThreshold, config.ExpiredThreshold,
0.7, config.MinDecayFactor, config.CurveType);
return (factor, StalenessCategory.Stale);
}
return (config.MinDecayFactor, StalenessCategory.Expired);
}
private static double CalculateCurveValue(
TimeSpan current,
TimeSpan start,
TimeSpan end,
double startValue,
double endValue,
DecayCurveType curveType)
{
var progress = (current - start).TotalSeconds / (end - start).TotalSeconds;
progress = Math.Clamp(progress, 0.0, 1.0);
return curveType switch
{
DecayCurveType.Linear =>
startValue + (endValue - startValue) * progress,
DecayCurveType.Exponential =>
startValue * Math.Pow(endValue / startValue, progress),
DecayCurveType.Step =>
progress < 0.5 ? startValue : endValue,
_ => startValue + (endValue - startValue) * progress
};
}
}