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

@@ -73,6 +73,18 @@ public sealed record ProofSpineRequest
/// Key profile to use for signing the spine statement.
/// </summary>
public SigningKeyProfile SigningProfile { get; init; } = SigningKeyProfile.Authority;
/// <summary>
/// Optional: ID of the uncertainty state attestation to include in the spine.
/// Sprint: SPRINT_4300_0002_0002_unknowns_attestation_predicates
/// </summary>
public string? UncertaintyStatementId { get; init; }
/// <summary>
/// Optional: ID of the uncertainty budget attestation to include in the spine.
/// Sprint: SPRINT_4300_0002_0002_unknowns_attestation_predicates
/// </summary>
public string? UncertaintyBudgetStatementId { get; init; }
}
/// <summary>

View File

@@ -92,4 +92,26 @@ public interface IStatementBuilder
SbomLinkageStatement BuildSbomLinkageStatement(
IReadOnlyList<ProofSubject> subjects,
SbomLinkagePayload predicate);
/// <summary>
/// Build an Uncertainty statement for signing.
/// Sprint: SPRINT_4300_0002_0002_unknowns_attestation_predicates
/// </summary>
/// <param name="subject">The artifact subject this uncertainty relates to.</param>
/// <param name="predicate">The uncertainty payload.</param>
/// <returns>An UncertaintyStatement ready for signing.</returns>
UncertaintyStatement BuildUncertaintyStatement(
ProofSubject subject,
UncertaintyPayload predicate);
/// <summary>
/// Build an Uncertainty Budget statement for signing.
/// Sprint: SPRINT_4300_0002_0002_unknowns_attestation_predicates
/// </summary>
/// <param name="subject">The artifact subject this budget evaluation relates to.</param>
/// <param name="predicate">The uncertainty budget payload.</param>
/// <returns>An UncertaintyBudgetStatement ready for signing.</returns>
UncertaintyBudgetStatement BuildUncertaintyBudgetStatement(
ProofSubject subject,
UncertaintyBudgetPayload predicate);
}

View File

@@ -103,4 +103,34 @@ public sealed class StatementBuilder : IStatementBuilder
Predicate = predicate
};
}
/// <inheritdoc />
public UncertaintyStatement BuildUncertaintyStatement(
ProofSubject subject,
UncertaintyPayload predicate)
{
ArgumentNullException.ThrowIfNull(subject);
ArgumentNullException.ThrowIfNull(predicate);
return new UncertaintyStatement
{
Subject = [subject.ToSubject()],
Predicate = predicate
};
}
/// <inheritdoc />
public UncertaintyBudgetStatement BuildUncertaintyBudgetStatement(
ProofSubject subject,
UncertaintyBudgetPayload predicate)
{
ArgumentNullException.ThrowIfNull(subject);
ArgumentNullException.ThrowIfNull(predicate);
return new UncertaintyBudgetStatement
{
Subject = [subject.ToSubject()],
Predicate = predicate
};
}
}

View File

@@ -91,6 +91,13 @@ public sealed record DeltaVerdictPredicate
/// </summary>
[JsonPropertyName("comparedAt")]
public required DateTimeOffset ComparedAt { get; init; }
/// <summary>
/// Unknowns budget evaluation result (if available).
/// Sprint: SPRINT_5100_0004_0001 Task T5
/// </summary>
[JsonPropertyName("unknownsBudget")]
public UnknownsBudgetPredicate? UnknownsBudget { get; init; }
}
/// <summary>

View File

@@ -0,0 +1,108 @@
// -----------------------------------------------------------------------------
// UnknownsBudgetPredicate.cs
// Sprint: SPRINT_5100_0004_0001_unknowns_budget_ci_gates
// Task: T5 - Attestation Integration
// Description: DSSE predicate for unknowns budget evaluation in verdict attestations.
// -----------------------------------------------------------------------------
using System.Collections.Immutable;
using System.Text.Json.Serialization;
namespace StellaOps.Attestor.ProofChain.Predicates;
/// <summary>
/// DSSE predicate for unknowns budget evaluation within verdict attestations.
/// predicateType: unknowns-budget.stella/v1
/// </summary>
public sealed record UnknownsBudgetPredicate
{
/// <summary>
/// The predicate type URI for unknowns budget attestations.
/// </summary>
public const string PredicateType = "unknowns-budget.stella/v1";
/// <summary>
/// Environment for which the budget was evaluated (prod, stage, dev).
/// </summary>
[JsonPropertyName("environment")]
public required string Environment { get; init; }
/// <summary>
/// Total number of unknowns found in the scan.
/// </summary>
[JsonPropertyName("totalUnknowns")]
public required int TotalUnknowns { get; init; }
/// <summary>
/// Maximum unknowns allowed by the budget (null if unlimited).
/// </summary>
[JsonPropertyName("totalLimit")]
public int? TotalLimit { get; init; }
/// <summary>
/// Whether the scan is within budget limits.
/// </summary>
[JsonPropertyName("isWithinBudget")]
public required bool IsWithinBudget { get; init; }
/// <summary>
/// Percentage of budget used (0-100+).
/// </summary>
[JsonPropertyName("percentageUsed")]
public decimal PercentageUsed { get; init; }
/// <summary>
/// Action recommended when budget is exceeded.
/// </summary>
[JsonPropertyName("recommendedAction")]
public string? RecommendedAction { get; init; }
/// <summary>
/// Violations by reason code (if any).
/// </summary>
[JsonPropertyName("violations")]
public ImmutableArray<BudgetViolationPredicate> Violations { get; init; } = [];
/// <summary>
/// Breakdown of unknowns by reason code.
/// </summary>
[JsonPropertyName("byReasonCode")]
public ImmutableDictionary<string, int> ByReasonCode { get; init; }
= ImmutableDictionary<string, int>.Empty;
/// <summary>
/// When the budget was evaluated.
/// </summary>
[JsonPropertyName("evaluatedAt")]
public required DateTimeOffset EvaluatedAt { get; init; }
/// <summary>
/// Optional message describing the budget status.
/// </summary>
[JsonPropertyName("message")]
public string? Message { get; init; }
}
/// <summary>
/// Individual budget violation for a specific reason code.
/// </summary>
public sealed record BudgetViolationPredicate
{
/// <summary>
/// Reason code for this violation (e.g., Reachability, Identity).
/// </summary>
[JsonPropertyName("reasonCode")]
public required string ReasonCode { get; init; }
/// <summary>
/// Number of unknowns with this reason code.
/// </summary>
[JsonPropertyName("count")]
public required int Count { get; init; }
/// <summary>
/// Maximum allowed for this reason code.
/// </summary>
[JsonPropertyName("limit")]
public required int Limit { get; init; }
}

View File

@@ -61,4 +61,18 @@ public sealed record ProofSpinePayload
/// </summary>
[JsonPropertyName("proofBundleId")]
public required string ProofBundleId { get; init; }
/// <summary>
/// Optional: ID of the uncertainty state attestation.
/// Sprint: SPRINT_4300_0002_0002_unknowns_attestation_predicates
/// </summary>
[JsonPropertyName("uncertaintyStatementId")]
public string? UncertaintyStatementId { get; init; }
/// <summary>
/// Optional: ID of the uncertainty budget evaluation attestation.
/// Sprint: SPRINT_4300_0002_0002_unknowns_attestation_predicates
/// </summary>
[JsonPropertyName("uncertaintyBudgetStatementId")]
public string? UncertaintyBudgetStatementId { get; init; }
}

View File

@@ -0,0 +1,257 @@
// -----------------------------------------------------------------------------
// UncertaintyBudgetStatement.cs
// Sprint: SPRINT_4300_0002_0002_unknowns_attestation_predicates
// Description: In-toto predicate type for uncertainty budget evaluation attestations.
// -----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace StellaOps.Attestor.ProofChain.Statements;
/// <summary>
/// In-toto statement for uncertainty budget evaluation attestations.
/// Predicate type: uncertainty-budget.stella/v1
/// </summary>
public sealed record UncertaintyBudgetStatement : InTotoStatement
{
/// <inheritdoc />
[JsonPropertyName("predicateType")]
public override string PredicateType => "uncertainty-budget.stella/v1";
/// <summary>
/// The uncertainty budget evaluation payload.
/// </summary>
[JsonPropertyName("predicate")]
public required UncertaintyBudgetPayload Predicate { get; init; }
}
/// <summary>
/// Payload for uncertainty budget evaluation statements.
/// </summary>
public sealed record UncertaintyBudgetPayload
{
/// <summary>
/// Schema version for this predicate.
/// </summary>
[JsonPropertyName("schemaVersion")]
public string SchemaVersion { get; init; } = "1.0";
/// <summary>
/// The environment this budget was evaluated for (prod, staging, dev).
/// </summary>
[JsonPropertyName("environment")]
public required string Environment { get; init; }
/// <summary>
/// Whether the evaluation passed (within budget).
/// </summary>
[JsonPropertyName("passed")]
public required bool Passed { get; init; }
/// <summary>
/// The action recommended by the budget policy.
/// Values: pass, warn, block.
/// </summary>
[JsonPropertyName("action")]
public required string Action { get; init; }
/// <summary>
/// The budget definition that was applied.
/// </summary>
[JsonPropertyName("budget")]
public required BudgetDefinition Budget { get; init; }
/// <summary>
/// Actual counts observed during evaluation.
/// </summary>
[JsonPropertyName("observed")]
public required BudgetObservation Observed { get; init; }
/// <summary>
/// Violations detected during budget evaluation.
/// </summary>
[JsonPropertyName("violations")]
public IReadOnlyList<BudgetViolationEntry>? Violations { get; init; }
/// <summary>
/// Exceptions that were applied to cover violations.
/// </summary>
[JsonPropertyName("exceptionsApplied")]
public IReadOnlyList<BudgetExceptionEntry>? ExceptionsApplied { get; init; }
/// <summary>
/// UTC timestamp when this budget was evaluated.
/// </summary>
[JsonPropertyName("evaluatedAt")]
public required DateTimeOffset EvaluatedAt { get; init; }
/// <summary>
/// Digest of the policy bundle containing the budget rules.
/// </summary>
[JsonPropertyName("policyDigest")]
public string? PolicyDigest { get; init; }
/// <summary>
/// Human-readable summary message.
/// </summary>
[JsonPropertyName("message")]
public string? Message { get; init; }
}
/// <summary>
/// Definition of a budget with limits.
/// </summary>
public sealed record BudgetDefinition
{
/// <summary>
/// Budget identifier.
/// </summary>
[JsonPropertyName("budgetId")]
public required string BudgetId { get; init; }
/// <summary>
/// Maximum total unknowns allowed.
/// </summary>
[JsonPropertyName("totalLimit")]
public int? TotalLimit { get; init; }
/// <summary>
/// Per-reason-code limits.
/// </summary>
[JsonPropertyName("reasonLimits")]
public IReadOnlyDictionary<string, int>? ReasonLimits { get; init; }
/// <summary>
/// Per-tier limits (e.g., T1 = 0, T2 = 5).
/// </summary>
[JsonPropertyName("tierLimits")]
public IReadOnlyDictionary<string, int>? TierLimits { get; init; }
/// <summary>
/// Maximum allowed cumulative entropy.
/// </summary>
[JsonPropertyName("maxCumulativeEntropy")]
public double? MaxCumulativeEntropy { get; init; }
}
/// <summary>
/// Observed values during budget evaluation.
/// </summary>
public sealed record BudgetObservation
{
/// <summary>
/// Total unknowns observed.
/// </summary>
[JsonPropertyName("totalUnknowns")]
public required int TotalUnknowns { get; init; }
/// <summary>
/// Unknowns by reason code.
/// </summary>
[JsonPropertyName("byReasonCode")]
public IReadOnlyDictionary<string, int>? ByReasonCode { get; init; }
/// <summary>
/// Unknowns by tier.
/// </summary>
[JsonPropertyName("byTier")]
public IReadOnlyDictionary<string, int>? ByTier { get; init; }
/// <summary>
/// Cumulative entropy observed.
/// </summary>
[JsonPropertyName("cumulativeEntropy")]
public double? CumulativeEntropy { get; init; }
/// <summary>
/// Mean entropy per unknown.
/// </summary>
[JsonPropertyName("meanEntropy")]
public double? MeanEntropy { get; init; }
}
/// <summary>
/// A specific budget violation.
/// </summary>
public sealed record BudgetViolationEntry
{
/// <summary>
/// Type of limit violated (total, reason, tier, entropy).
/// </summary>
[JsonPropertyName("limitType")]
public required string LimitType { get; init; }
/// <summary>
/// Specific limit key (e.g., "U-RCH" for reason, "T1" for tier).
/// </summary>
[JsonPropertyName("limitKey")]
public string? LimitKey { get; init; }
/// <summary>
/// The configured limit value.
/// </summary>
[JsonPropertyName("limit")]
public required double Limit { get; init; }
/// <summary>
/// The observed value that exceeded the limit.
/// </summary>
[JsonPropertyName("observed")]
public required double Observed { get; init; }
/// <summary>
/// Amount by which the limit was exceeded.
/// </summary>
[JsonPropertyName("exceeded")]
public required double Exceeded { get; init; }
/// <summary>
/// Severity of this violation (critical, high, medium, low).
/// </summary>
[JsonPropertyName("severity")]
public string? Severity { get; init; }
}
/// <summary>
/// An exception applied to cover a budget violation.
/// </summary>
public sealed record BudgetExceptionEntry
{
/// <summary>
/// Exception identifier.
/// </summary>
[JsonPropertyName("exceptionId")]
public required string ExceptionId { get; init; }
/// <summary>
/// Reason codes covered by this exception.
/// </summary>
[JsonPropertyName("coveredReasons")]
public IReadOnlyList<string>? CoveredReasons { get; init; }
/// <summary>
/// Tiers covered by this exception.
/// </summary>
[JsonPropertyName("coveredTiers")]
public IReadOnlyList<string>? CoveredTiers { get; init; }
/// <summary>
/// When this exception expires (if time-limited).
/// </summary>
[JsonPropertyName("expiresAt")]
public DateTimeOffset? ExpiresAt { get; init; }
/// <summary>
/// Justification for the exception.
/// </summary>
[JsonPropertyName("justification")]
public string? Justification { get; init; }
/// <summary>
/// Who approved this exception.
/// </summary>
[JsonPropertyName("approvedBy")]
public string? ApprovedBy { get; init; }
}

View File

@@ -0,0 +1,162 @@
// -----------------------------------------------------------------------------
// UncertaintyStatement.cs
// Sprint: SPRINT_4300_0002_0002_unknowns_attestation_predicates
// Description: In-toto predicate type for uncertainty state attestations.
// -----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace StellaOps.Attestor.ProofChain.Statements;
/// <summary>
/// In-toto statement for uncertainty state attestations.
/// Predicate type: uncertainty.stella/v1
/// </summary>
public sealed record UncertaintyStatement : InTotoStatement
{
/// <inheritdoc />
[JsonPropertyName("predicateType")]
public override string PredicateType => "uncertainty.stella/v1";
/// <summary>
/// The uncertainty state payload.
/// </summary>
[JsonPropertyName("predicate")]
public required UncertaintyPayload Predicate { get; init; }
}
/// <summary>
/// Payload for uncertainty state statements.
/// </summary>
public sealed record UncertaintyPayload
{
/// <summary>
/// Schema version for this predicate.
/// </summary>
[JsonPropertyName("schemaVersion")]
public string SchemaVersion { get; init; } = "1.0";
/// <summary>
/// The aggregate uncertainty tier (T1-T4).
/// T1 = High uncertainty, T4 = Negligible.
/// </summary>
[JsonPropertyName("aggregateTier")]
public required string AggregateTier { get; init; }
/// <summary>
/// Mean entropy across all uncertainty states (0.0-1.0).
/// </summary>
[JsonPropertyName("meanEntropy")]
public required double MeanEntropy { get; init; }
/// <summary>
/// Total count of uncertainty markers.
/// </summary>
[JsonPropertyName("markerCount")]
public required int MarkerCount { get; init; }
/// <summary>
/// Risk modifier applied due to uncertainty (multiplier, e.g., 1.5 = 50% boost).
/// </summary>
[JsonPropertyName("riskModifier")]
public required double RiskModifier { get; init; }
/// <summary>
/// Individual uncertainty states that contribute to this aggregate.
/// </summary>
[JsonPropertyName("states")]
public required IReadOnlyList<UncertaintyStateEntry> States { get; init; }
/// <summary>
/// Evidence references supporting the uncertainty claims.
/// </summary>
[JsonPropertyName("evidence")]
public IReadOnlyList<UncertaintyEvidence>? Evidence { get; init; }
/// <summary>
/// UTC timestamp when this uncertainty state was computed.
/// </summary>
[JsonPropertyName("computedAt")]
public required DateTimeOffset ComputedAt { get; init; }
/// <summary>
/// Reference to the knowledge snapshot used.
/// </summary>
[JsonPropertyName("knowledgeSnapshotId")]
public string? KnowledgeSnapshotId { get; init; }
}
/// <summary>
/// An individual uncertainty state entry.
/// </summary>
public sealed record UncertaintyStateEntry
{
/// <summary>
/// Uncertainty code (U1-U4 or custom).
/// </summary>
[JsonPropertyName("code")]
public required string Code { get; init; }
/// <summary>
/// Human-readable name for this uncertainty type.
/// </summary>
[JsonPropertyName("name")]
public required string Name { get; init; }
/// <summary>
/// Entropy value for this state (0.0-1.0).
/// Higher values indicate more uncertainty.
/// </summary>
[JsonPropertyName("entropy")]
public required double Entropy { get; init; }
/// <summary>
/// Tier classification for this state (T1-T4).
/// </summary>
[JsonPropertyName("tier")]
public required string Tier { get; init; }
/// <summary>
/// Marker kind that triggered this uncertainty.
/// </summary>
[JsonPropertyName("markerKind")]
public string? MarkerKind { get; init; }
/// <summary>
/// Confidence band (high, medium, low).
/// </summary>
[JsonPropertyName("confidenceBand")]
public string? ConfidenceBand { get; init; }
}
/// <summary>
/// Evidence supporting an uncertainty claim.
/// </summary>
public sealed record UncertaintyEvidence
{
/// <summary>
/// Type of evidence (advisory, binary, purl, etc.).
/// </summary>
[JsonPropertyName("type")]
public required string Type { get; init; }
/// <summary>
/// Reference to the evidence source.
/// </summary>
[JsonPropertyName("reference")]
public required string Reference { get; init; }
/// <summary>
/// Optional digest for content-addressed evidence.
/// </summary>
[JsonPropertyName("digest")]
public string? Digest { get; init; }
/// <summary>
/// Human-readable description.
/// </summary>
[JsonPropertyName("description")]
public string? Description { get; init; }
}

View File

@@ -183,4 +183,18 @@ public sealed record VerdictOutputs
/// </summary>
[JsonPropertyName("vexVerdictId")]
public required string VexVerdictId { get; init; }
/// <summary>
/// Optional: ID of the uncertainty state attestation.
/// Sprint: SPRINT_4300_0002_0002_unknowns_attestation_predicates
/// </summary>
[JsonPropertyName("uncertaintyStatementId")]
public string? UncertaintyStatementId { get; init; }
/// <summary>
/// Optional: ID of the uncertainty budget attestation.
/// Sprint: SPRINT_4300_0002_0002_unknowns_attestation_predicates
/// </summary>
[JsonPropertyName("uncertaintyBudgetStatementId")]
public string? UncertaintyBudgetStatementId { get; init; }
}