Add SBOM, symbols, traces, and VEX files for CVE-2022-21661 SQLi case
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Created CycloneDX and SPDX SBOM files for both reachable and unreachable images.
- Added symbols.json detailing function entry and sink points in the WordPress code.
- Included runtime traces for function calls in both reachable and unreachable scenarios.
- Developed OpenVEX files indicating vulnerability status and justification for both cases.
- Updated README for evaluator harness to guide integration with scanner output.
This commit is contained in:
master
2025-11-08 20:53:45 +02:00
parent 515975edc5
commit 536f6249a6
837 changed files with 37279 additions and 14675 deletions

View File

@@ -126,7 +126,7 @@ public sealed class EnsureAdvisoryCanonicalKeyBackfillMigration : IMongoMigratio
return string.Empty;
}
return value.IsString ? value.AsString : value.ToString();
return value.IsString ? value.AsString : value.ToString() ?? string.Empty;
}
private static string? GetOptionalString(BsonDocument document, string name)
@@ -150,7 +150,7 @@ public sealed class EnsureAdvisoryCanonicalKeyBackfillMigration : IMongoMigratio
BsonInt32 i => i.AsInt32.ToString(CultureInfo.InvariantCulture),
BsonInt64 l => l.AsInt64.ToString(CultureInfo.InvariantCulture),
BsonDouble d => d.AsDouble.ToString(CultureInfo.InvariantCulture),
_ => value.ToString()
_ => value?.ToString() ?? string.Empty
};
}

View File

@@ -157,7 +157,7 @@ public sealed class EnsureAdvisoryObservationsRawLinksetMigration : IMongoMigrat
content,
identifiers,
linkset,
supersedes.IsBsonNull ? null : supersedes.AsString);
Supersedes: supersedes.IsBsonNull ? null : supersedes.AsString);
}
private static RawSourceMetadata MapSource(BsonDocument source)

View File

@@ -90,12 +90,27 @@ public sealed class MongoBootstrapper
_logger.LogInformation("Mongo bootstrapper completed");
}
private async Task<HashSet<string>> ListCollectionsAsync(CancellationToken cancellationToken)
{
using var cursor = await _database.ListCollectionNamesAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
var list = await cursor.ToListAsync(cancellationToken).ConfigureAwait(false);
return new HashSet<string>(list, StringComparer.Ordinal);
}
private async Task<HashSet<string>> ListCollectionsAsync(CancellationToken cancellationToken)
{
using var cursor = await _database.ListCollectionNamesAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
var list = await cursor.ToListAsync(cancellationToken).ConfigureAwait(false);
return new HashSet<string>(list, StringComparer.Ordinal);
}
private async Task<bool> CollectionIsViewAsync(string collectionName, CancellationToken cancellationToken)
{
var filter = Builders<BsonDocument>.Filter.Eq("name", collectionName);
var options = new ListCollectionsOptions { Filter = filter };
using var cursor = await _database.ListCollectionsAsync(options, cancellationToken).ConfigureAwait(false);
var collections = await cursor.ToListAsync(cancellationToken).ConfigureAwait(false);
if (collections.Count == 0)
{
return false;
}
var typeValue = collections[0].GetValue("type", BsonString.Empty).AsString;
return string.Equals(typeValue, "view", StringComparison.OrdinalIgnoreCase);
}
private Task EnsureLocksIndexesAsync(CancellationToken cancellationToken)
{
@@ -129,9 +144,15 @@ public sealed class MongoBootstrapper
return collection.Indexes.CreateManyAsync(indexes, cancellationToken);
}
private Task EnsureAdvisoryIndexesAsync(CancellationToken cancellationToken)
{
var collection = _database.GetCollection<BsonDocument>(MongoStorageDefaults.Collections.Advisory);
private async Task EnsureAdvisoryIndexesAsync(CancellationToken cancellationToken)
{
if (await CollectionIsViewAsync(MongoStorageDefaults.Collections.Advisory, cancellationToken).ConfigureAwait(false))
{
_logger.LogDebug("Skipping advisory index creation because {Collection} is a view", MongoStorageDefaults.Collections.Advisory);
return;
}
var collection = _database.GetCollection<BsonDocument>(MongoStorageDefaults.Collections.Advisory);
var indexes = new List<CreateIndexModel<BsonDocument>>
{
new(
@@ -159,7 +180,7 @@ public sealed class MongoBootstrapper
new CreateIndexOptions { Name = "advisory_normalizedVersions_value", Sparse = true }));
}
return collection.Indexes.CreateManyAsync(indexes, cancellationToken);
await collection.Indexes.CreateManyAsync(indexes, cancellationToken).ConfigureAwait(false);
}
private Task EnsureDocumentsIndexesAsync(CancellationToken cancellationToken)

View File

@@ -1,16 +1,18 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using System.Text;
using System.Linq;
using System.Text.Json;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Bson.IO;
using Microsoft.Extensions.Logging;
using StellaOps.Concelier.Core.Raw;
using StellaOps.Concelier.RawModels;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Driver;
using StellaOps.Concelier.Core.Raw;
using StellaOps.Concelier.RawModels;
using StellaOps.Ingestion.Telemetry;
namespace StellaOps.Concelier.Storage.Mongo.Raw;
@@ -34,76 +36,115 @@ internal sealed class MongoAdvisoryRawRepository : IAdvisoryRawRepository
_collection = database.GetCollection<BsonDocument>(MongoStorageDefaults.Collections.AdvisoryRaw);
}
public async Task<AdvisoryRawUpsertResult> UpsertAsync(AdvisoryRawDocument document, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(document);
var tenant = document.Tenant;
var vendor = document.Source.Vendor;
var upstreamId = document.Upstream.UpstreamId;
var contentHash = document.Upstream.ContentHash;
var baseFilter = Builders<BsonDocument>.Filter.Eq("tenant", tenant) &
Builders<BsonDocument>.Filter.Eq("source.vendor", vendor) &
Builders<BsonDocument>.Filter.Eq("upstream.upstream_id", upstreamId);
public async Task<AdvisoryRawUpsertResult> UpsertAsync(AdvisoryRawDocument document, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(document);
var tenant = document.Tenant;
var vendor = document.Source.Vendor;
var upstreamId = document.Upstream.UpstreamId;
var contentHash = document.Upstream.ContentHash;
var sourceUri = ResolveProvenanceUri(document);
var baseFilter = Builders<BsonDocument>.Filter.Eq("tenant", tenant) &
Builders<BsonDocument>.Filter.Eq("source.vendor", vendor) &
Builders<BsonDocument>.Filter.Eq("upstream.upstream_id", upstreamId);
var duplicateFilter = baseFilter &
Builders<BsonDocument>.Filter.Eq("upstream.content_hash", contentHash);
var duplicate = await _collection
.Find(duplicateFilter)
.Limit(1)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (duplicate is not null)
{
var existing = MapToRecord(duplicate);
return new AdvisoryRawUpsertResult(false, existing);
}
var previous = await _collection
.Find(baseFilter)
.Sort(Builders<BsonDocument>.Sort.Descending("ingested_at").Descending("_id"))
.Limit(1)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
var supersedesId = previous?["_id"]?.AsString;
var recordDocument = CreateBsonDocument(document, supersedesId);
try
{
await _collection.InsertOneAsync(recordDocument, cancellationToken: cancellationToken).ConfigureAwait(false);
}
catch (MongoWriteException ex) when (ex.WriteError?.Category == ServerErrorCategory.DuplicateKey)
{
_logger.LogWarning(
ex,
"Duplicate key detected while inserting advisory_raw document tenant={Tenant} vendor={Vendor} upstream={Upstream} hash={Hash}",
tenant,
vendor,
upstreamId,
contentHash);
var existingDoc = await _collection
.Find(duplicateFilter)
.Limit(1)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (existingDoc is not null)
{
var existing = MapToRecord(existingDoc);
return new AdvisoryRawUpsertResult(false, existing);
}
throw;
}
var inserted = MapToRecord(recordDocument);
return new AdvisoryRawUpsertResult(true, inserted);
}
using var fetchActivity = IngestionTelemetry.StartFetchActivity(tenant, vendor, upstreamId, contentHash, sourceUri);
var fetchWatch = Stopwatch.StartNew();
var duplicate = await _collection
.Find(duplicateFilter)
.Limit(1)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (duplicate is not null)
{
fetchWatch.Stop();
fetchActivity?.SetTag("result", "duplicate");
fetchActivity?.SetStatus(ActivityStatusCode.Ok);
IngestionTelemetry.RecordLatency(tenant, vendor, IngestionTelemetry.PhaseFetch, fetchWatch.Elapsed);
var existing = MapToRecord(duplicate);
return new AdvisoryRawUpsertResult(false, existing);
}
var previous = await _collection
.Find(baseFilter)
.Sort(Builders<BsonDocument>.Sort.Descending("ingested_at").Descending("_id"))
.Limit(1)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
fetchWatch.Stop();
fetchActivity?.SetTag("result", previous is null ? "new" : "supersede");
fetchActivity?.SetStatus(ActivityStatusCode.Ok);
IngestionTelemetry.RecordLatency(tenant, vendor, IngestionTelemetry.PhaseFetch, fetchWatch.Elapsed);
var supersedesId = previous?["_id"]?.AsString;
var recordDocument = CreateBsonDocument(document, supersedesId);
var writeWatch = Stopwatch.StartNew();
using var writeActivity = IngestionTelemetry.StartWriteActivity(tenant, vendor, upstreamId, contentHash, MongoStorageDefaults.Collections.AdvisoryRaw);
try
{
await _collection.InsertOneAsync(recordDocument, cancellationToken: cancellationToken).ConfigureAwait(false);
writeActivity?.SetTag("result", IngestionTelemetry.ResultOk);
writeActivity?.SetStatus(ActivityStatusCode.Ok);
}
catch (MongoWriteException ex) when (ex.WriteError?.Category == ServerErrorCategory.DuplicateKey)
{
writeActivity?.SetTag("result", IngestionTelemetry.ResultNoop);
writeActivity?.SetStatus(ActivityStatusCode.Error, "duplicate_key");
_logger.LogWarning(
ex,
"Duplicate key detected while inserting advisory_raw document tenant={Tenant} vendor={Vendor} upstream={Upstream} hash={Hash}",
tenant,
vendor,
upstreamId,
contentHash);
var existingDoc = await _collection
.Find(duplicateFilter)
.Limit(1)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (existingDoc is not null)
{
var existing = MapToRecord(existingDoc);
return new AdvisoryRawUpsertResult(false, existing);
}
throw;
}
finally
{
writeWatch.Stop();
IngestionTelemetry.RecordLatency(tenant, vendor, IngestionTelemetry.PhaseWrite, writeWatch.Elapsed);
}
var inserted = MapToRecord(recordDocument);
return new AdvisoryRawUpsertResult(true, inserted);
}
private static string? ResolveProvenanceUri(AdvisoryRawDocument document)
{
if (document.Upstream?.Provenance is null)
{
return null;
}
return document.Upstream.Provenance.TryGetValue("uri", out var uri) && !string.IsNullOrWhiteSpace(uri)
? uri
: null;
}
public async Task<AdvisoryRawRecord?> FindByIdAsync(string tenant, string id, CancellationToken cancellationToken)
{

View File

@@ -11,8 +11,9 @@
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.0-rc.2.25502.107" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0-rc.2.25502.107" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StellaOps.Concelier.Core\StellaOps.Concelier.Core.csproj" />
<ProjectReference Include="..\StellaOps.Concelier.Models\StellaOps.Concelier.Models.csproj" />
</ItemGroup>
</Project>
<ItemGroup>
<ProjectReference Include="..\StellaOps.Concelier.Core\StellaOps.Concelier.Core.csproj" />
<ProjectReference Include="..\StellaOps.Concelier.Models\StellaOps.Concelier.Models.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Ingestion.Telemetry\StellaOps.Ingestion.Telemetry.csproj" />
</ItemGroup>
</Project>