wip: doctor/cli/docs/api to vector db consolidation; api hardening for descriptions, tenant, and scopes; migrations and conversions of all DALs to EF v10

This commit is contained in:
master
2026-02-23 15:30:50 +02:00
parent bd8fee6ed8
commit e746577380
1424 changed files with 81225 additions and 25251 deletions

View File

@@ -10,7 +10,7 @@ BinaryIndex is a collection of libraries and services for binary analysis:
- **BinaryIndex.Core** - Binary identity models, resolution logic, feature extractors
- **BinaryIndex.Contracts** - API contracts and DTOs
- **BinaryIndex.Cache** - Caching layer for binary analysis results
- **BinaryIndex.Persistence** - PostgreSQL storage for signatures and identities
- **BinaryIndex.Persistence** - PostgreSQL storage for signatures and identities (EF Core v10 + compiled models)
### Delta Signature Stack (Backport Detection)
- **BinaryIndex.Disassembly.Abstractions** - Plugin interfaces for disassembly

View File

@@ -17,15 +17,24 @@ Provide foundational data models, storage, and validation for Golden Set definit
4. **Air-Gap Ready**: Validation supports offline mode without external lookups
5. **Human-Readable**: YAML as primary format for git-friendliness
## DAL Technology
- **Primary**: EF Core v10 DbContext (`EfCore/Context/GoldenSetDbContext.cs`) with 3 entities (definitions, targets, audit_log) in `golden_sets` schema.
- **Compiled model**: `EfCore/CompiledModels/GoldenSetDbContextModel` generated for runtime performance.
- **Legacy**: `PostgresGoldenSetStore` still uses NpgsqlDataSource directly (deferred from EF Core conversion). Mixed DAL acceptable per cutover strategy.
- **SQL migrations remain authoritative**: EF models are scaffolded FROM the SQL schema, never the reverse.
## Dependencies
- `BinaryIndex.Contracts` - Shared contracts and DTOs
- `Npgsql` - PostgreSQL driver
- `Npgsql.EntityFrameworkCore.PostgreSQL` - EF Core Npgsql provider
- `Microsoft.EntityFrameworkCore` - EF Core v10
- `YamlDotNet` - YAML serialization
- `Microsoft.Extensions.*` - DI, Options, Logging, Caching
## Required Reading
- `docs/modules/binary-index/golden-set-schema.md`
- `docs-archived/implplan/SPRINT_20260110_012_001_BINDEX_golden_set_foundation.md`
- `docs/db/EF_CORE_MODEL_GENERATION_STANDARDS.md`
## Test Strategy
- Unit tests in `StellaOps.BinaryIndex.GoldenSet.Tests`

View File

@@ -0,0 +1,136 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.GoldenSet.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.GoldenSet.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class GoldenSetAuditLogEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.GoldenSet.EfCore.Models.GoldenSetAuditLogEntity",
typeof(GoldenSetAuditLogEntity),
baseEntityType,
propertyCount: 8,
namedIndexCount: 2,
keyCount: 1);
var id = runtimeEntityType.AddProperty(
"Id",
typeof(Guid),
propertyInfo: typeof(GoldenSetAuditLogEntity).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetAuditLogEntity).GetField("<Id>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: Guid.Empty);
id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
id.AddAnnotation("Relational:ColumnName", "id");
id.AddAnnotation("Relational:DefaultValueSql", "gen_random_uuid()");
var goldenSetId = runtimeEntityType.AddProperty(
"GoldenSetId",
typeof(string),
propertyInfo: typeof(GoldenSetAuditLogEntity).GetProperty("GoldenSetId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetAuditLogEntity).GetField("<GoldenSetId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
goldenSetId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
goldenSetId.AddAnnotation("Relational:ColumnName", "golden_set_id");
var action = runtimeEntityType.AddProperty(
"Action",
typeof(string),
propertyInfo: typeof(GoldenSetAuditLogEntity).GetProperty("Action", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetAuditLogEntity).GetField("<Action>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
action.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
action.AddAnnotation("Relational:ColumnName", "action");
var actorId = runtimeEntityType.AddProperty(
"ActorId",
typeof(string),
propertyInfo: typeof(GoldenSetAuditLogEntity).GetProperty("ActorId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetAuditLogEntity).GetField("<ActorId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
actorId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
actorId.AddAnnotation("Relational:ColumnName", "actor_id");
var oldStatus = runtimeEntityType.AddProperty(
"OldStatus",
typeof(string),
propertyInfo: typeof(GoldenSetAuditLogEntity).GetProperty("OldStatus", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetAuditLogEntity).GetField("<OldStatus>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
oldStatus.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
oldStatus.AddAnnotation("Relational:ColumnName", "old_status");
var newStatus = runtimeEntityType.AddProperty(
"NewStatus",
typeof(string),
propertyInfo: typeof(GoldenSetAuditLogEntity).GetProperty("NewStatus", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetAuditLogEntity).GetField("<NewStatus>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
newStatus.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
newStatus.AddAnnotation("Relational:ColumnName", "new_status");
var details = runtimeEntityType.AddProperty(
"Details",
typeof(string),
propertyInfo: typeof(GoldenSetAuditLogEntity).GetProperty("Details", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetAuditLogEntity).GetField("<Details>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
details.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
details.AddAnnotation("Relational:ColumnName", "details");
details.AddAnnotation("Relational:ColumnType", "jsonb");
var timestamp = runtimeEntityType.AddProperty(
"Timestamp",
typeof(DateTime),
propertyInfo: typeof(GoldenSetAuditLogEntity).GetProperty("Timestamp", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetAuditLogEntity).GetField("<Timestamp>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
timestamp.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
timestamp.AddAnnotation("Relational:ColumnName", "timestamp");
timestamp.AddAnnotation("Relational:DefaultValueSql", "NOW()");
var key = runtimeEntityType.AddKey(
new[] { id });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "audit_log_pkey");
var idx_audit_golden_set = runtimeEntityType.AddIndex(
new[] { goldenSetId },
name: "idx_audit_golden_set");
var idx_audit_timestamp = runtimeEntityType.AddIndex(
new[] { timestamp },
name: "idx_audit_timestamp");
idx_audit_timestamp.AddAnnotation("Relational:IsDescending", new[] { true });
var idx_audit_actor = runtimeEntityType.AddIndex(
new[] { actorId },
name: "idx_audit_actor");
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "golden_sets");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "audit_log");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,9 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore.Infrastructure;
using StellaOps.BinaryIndex.GoldenSet.EfCore.CompiledModels;
using StellaOps.BinaryIndex.GoldenSet.EfCore.Context;
#pragma warning disable 219, 612, 618
#nullable disable
[assembly: DbContextModel(typeof(GoldenSetDbContext), typeof(GoldenSetDbContextModel))]

View File

@@ -0,0 +1,48 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using StellaOps.BinaryIndex.GoldenSet.EfCore.Context;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.GoldenSet.EfCore.CompiledModels
{
[DbContext(typeof(GoldenSetDbContext))]
public partial class GoldenSetDbContextModel : RuntimeModel
{
private static readonly bool _useOldBehavior31751 =
System.AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31751", out var enabled31751) && enabled31751;
static GoldenSetDbContextModel()
{
var model = new GoldenSetDbContextModel();
if (_useOldBehavior31751)
{
model.Initialize();
}
else
{
var thread = new System.Threading.Thread(RunInitialization, 10 * 1024 * 1024);
thread.Start();
thread.Join();
void RunInitialization()
{
model.Initialize();
}
}
model.Customize();
_instance = (GoldenSetDbContextModel)model.FinalizeModel();
}
private static GoldenSetDbContextModel _instance;
public static IModel Instance => _instance;
partial void Initialize();
partial void Customize();
}
}

View File

@@ -0,0 +1,34 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.GoldenSet.EfCore.CompiledModels
{
public partial class GoldenSetDbContextModel
{
private GoldenSetDbContextModel()
: base(skipDetectChanges: false, modelId: new Guid("b25d0a3e-8c4f-4e9b-a6d2-e7f1c3b82945"), entityTypeCount: 3)
{
}
partial void Initialize()
{
var definition = GoldenSetDefinitionEntityType.Create(this);
var target = GoldenSetTargetEntityType.Create(this);
var auditLog = GoldenSetAuditLogEntityType.Create(this);
GoldenSetDefinitionEntityType.CreateAnnotations(definition);
GoldenSetTargetEntityType.CreateAnnotations(target);
GoldenSetAuditLogEntityType.CreateAnnotations(auditLog);
AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
AddAnnotation("ProductVersion", "10.0.0");
AddAnnotation("Relational:MaxIdentifierLength", 63);
}
}
}

View File

@@ -0,0 +1,202 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.GoldenSet.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.GoldenSet.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class GoldenSetDefinitionEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.GoldenSet.EfCore.Models.GoldenSetDefinitionEntity",
typeof(GoldenSetDefinitionEntity),
baseEntityType,
propertyCount: 15,
namedIndexCount: 4,
keyCount: 1);
var id = runtimeEntityType.AddProperty(
"Id",
typeof(string),
propertyInfo: typeof(GoldenSetDefinitionEntity).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetDefinitionEntity).GetField("<Id>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
afterSaveBehavior: PropertySaveBehavior.Throw);
id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
id.AddAnnotation("Relational:ColumnName", "id");
var component = runtimeEntityType.AddProperty(
"Component",
typeof(string),
propertyInfo: typeof(GoldenSetDefinitionEntity).GetProperty("Component", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetDefinitionEntity).GetField("<Component>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
component.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
component.AddAnnotation("Relational:ColumnName", "component");
var contentDigest = runtimeEntityType.AddProperty(
"ContentDigest",
typeof(string),
propertyInfo: typeof(GoldenSetDefinitionEntity).GetProperty("ContentDigest", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetDefinitionEntity).GetField("<ContentDigest>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
contentDigest.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
contentDigest.AddAnnotation("Relational:ColumnName", "content_digest");
var status = runtimeEntityType.AddProperty(
"Status",
typeof(string),
propertyInfo: typeof(GoldenSetDefinitionEntity).GetProperty("Status", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetDefinitionEntity).GetField("<Status>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
status.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
status.AddAnnotation("Relational:ColumnName", "status");
var definitionYaml = runtimeEntityType.AddProperty(
"DefinitionYaml",
typeof(string),
propertyInfo: typeof(GoldenSetDefinitionEntity).GetProperty("DefinitionYaml", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetDefinitionEntity).GetField("<DefinitionYaml>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
definitionYaml.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
definitionYaml.AddAnnotation("Relational:ColumnName", "definition_yaml");
var definitionJson = runtimeEntityType.AddProperty(
"DefinitionJson",
typeof(string),
propertyInfo: typeof(GoldenSetDefinitionEntity).GetProperty("DefinitionJson", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetDefinitionEntity).GetField("<DefinitionJson>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
definitionJson.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
definitionJson.AddAnnotation("Relational:ColumnName", "definition_json");
definitionJson.AddAnnotation("Relational:ColumnType", "jsonb");
var targetCount = runtimeEntityType.AddProperty(
"TargetCount",
typeof(int),
propertyInfo: typeof(GoldenSetDefinitionEntity).GetProperty("TargetCount", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetDefinitionEntity).GetField("<TargetCount>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: 0);
targetCount.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
targetCount.AddAnnotation("Relational:ColumnName", "target_count");
var authorId = runtimeEntityType.AddProperty(
"AuthorId",
typeof(string),
propertyInfo: typeof(GoldenSetDefinitionEntity).GetProperty("AuthorId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetDefinitionEntity).GetField("<AuthorId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
authorId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
authorId.AddAnnotation("Relational:ColumnName", "author_id");
var createdAt = runtimeEntityType.AddProperty(
"CreatedAt",
typeof(DateTime),
propertyInfo: typeof(GoldenSetDefinitionEntity).GetProperty("CreatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetDefinitionEntity).GetField("<CreatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
createdAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
createdAt.AddAnnotation("Relational:ColumnName", "created_at");
createdAt.AddAnnotation("Relational:DefaultValueSql", "NOW()");
var reviewedBy = runtimeEntityType.AddProperty(
"ReviewedBy",
typeof(string),
propertyInfo: typeof(GoldenSetDefinitionEntity).GetProperty("ReviewedBy", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetDefinitionEntity).GetField("<ReviewedBy>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
reviewedBy.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
reviewedBy.AddAnnotation("Relational:ColumnName", "reviewed_by");
var reviewedAt = runtimeEntityType.AddProperty(
"ReviewedAt",
typeof(DateTime?),
propertyInfo: typeof(GoldenSetDefinitionEntity).GetProperty("ReviewedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetDefinitionEntity).GetField("<ReviewedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
reviewedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
reviewedAt.AddAnnotation("Relational:ColumnName", "reviewed_at");
var sourceRef = runtimeEntityType.AddProperty(
"SourceRef",
typeof(string),
propertyInfo: typeof(GoldenSetDefinitionEntity).GetProperty("SourceRef", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetDefinitionEntity).GetField("<SourceRef>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
sourceRef.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
sourceRef.AddAnnotation("Relational:ColumnName", "source_ref");
var tags = runtimeEntityType.AddProperty(
"Tags",
typeof(string[]),
propertyInfo: typeof(GoldenSetDefinitionEntity).GetProperty("Tags", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetDefinitionEntity).GetField("<Tags>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
tags.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
tags.AddAnnotation("Relational:ColumnName", "tags");
var schemaVersion = runtimeEntityType.AddProperty(
"SchemaVersion",
typeof(string),
propertyInfo: typeof(GoldenSetDefinitionEntity).GetProperty("SchemaVersion", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetDefinitionEntity).GetField("<SchemaVersion>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
schemaVersion.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
schemaVersion.AddAnnotation("Relational:ColumnName", "schema_version");
var updatedAt = runtimeEntityType.AddProperty(
"UpdatedAt",
typeof(DateTime),
propertyInfo: typeof(GoldenSetDefinitionEntity).GetProperty("UpdatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetDefinitionEntity).GetField("<UpdatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
updatedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
updatedAt.AddAnnotation("Relational:ColumnName", "updated_at");
updatedAt.AddAnnotation("Relational:DefaultValueSql", "NOW()");
var key = runtimeEntityType.AddKey(
new[] { id });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "definitions_pkey");
var idx_goldensets_component = runtimeEntityType.AddIndex(
new[] { component },
name: "idx_goldensets_component");
var idx_goldensets_status = runtimeEntityType.AddIndex(
new[] { status },
name: "idx_goldensets_status");
var idx_goldensets_digest = runtimeEntityType.AddIndex(
new[] { contentDigest },
name: "idx_goldensets_digest",
unique: true);
var idx_goldensets_created = runtimeEntityType.AddIndex(
new[] { createdAt },
name: "idx_goldensets_created");
idx_goldensets_created.AddAnnotation("Relational:IsDescending", new[] { true });
var idx_goldensets_component_status = runtimeEntityType.AddIndex(
new[] { component, status },
name: "idx_goldensets_component_status");
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "golden_sets");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "definitions");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,138 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.GoldenSet.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.GoldenSet.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class GoldenSetTargetEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.GoldenSet.EfCore.Models.GoldenSetTargetEntity",
typeof(GoldenSetTargetEntity),
baseEntityType,
propertyCount: 9,
namedIndexCount: 1,
keyCount: 1);
var id = runtimeEntityType.AddProperty(
"Id",
typeof(Guid),
propertyInfo: typeof(GoldenSetTargetEntity).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetTargetEntity).GetField("<Id>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: Guid.Empty);
id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
id.AddAnnotation("Relational:ColumnName", "id");
id.AddAnnotation("Relational:DefaultValueSql", "gen_random_uuid()");
var goldenSetId = runtimeEntityType.AddProperty(
"GoldenSetId",
typeof(string),
propertyInfo: typeof(GoldenSetTargetEntity).GetProperty("GoldenSetId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetTargetEntity).GetField("<GoldenSetId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
goldenSetId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
goldenSetId.AddAnnotation("Relational:ColumnName", "golden_set_id");
var functionName = runtimeEntityType.AddProperty(
"FunctionName",
typeof(string),
propertyInfo: typeof(GoldenSetTargetEntity).GetProperty("FunctionName", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetTargetEntity).GetField("<FunctionName>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
functionName.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
functionName.AddAnnotation("Relational:ColumnName", "function_name");
var edges = runtimeEntityType.AddProperty(
"Edges",
typeof(string),
propertyInfo: typeof(GoldenSetTargetEntity).GetProperty("Edges", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetTargetEntity).GetField("<Edges>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd);
edges.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
edges.AddAnnotation("Relational:ColumnName", "edges");
edges.AddAnnotation("Relational:ColumnType", "jsonb");
edges.AddAnnotation("Relational:DefaultValueSql", "'[]'::jsonb");
var sinks = runtimeEntityType.AddProperty(
"Sinks",
typeof(string[]),
propertyInfo: typeof(GoldenSetTargetEntity).GetProperty("Sinks", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetTargetEntity).GetField("<Sinks>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
sinks.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
sinks.AddAnnotation("Relational:ColumnName", "sinks");
var constants = runtimeEntityType.AddProperty(
"Constants",
typeof(string[]),
propertyInfo: typeof(GoldenSetTargetEntity).GetProperty("Constants", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetTargetEntity).GetField("<Constants>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
constants.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
constants.AddAnnotation("Relational:ColumnName", "constants");
var taintInvariant = runtimeEntityType.AddProperty(
"TaintInvariant",
typeof(string),
propertyInfo: typeof(GoldenSetTargetEntity).GetProperty("TaintInvariant", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetTargetEntity).GetField("<TaintInvariant>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
taintInvariant.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
taintInvariant.AddAnnotation("Relational:ColumnName", "taint_invariant");
var sourceFile = runtimeEntityType.AddProperty(
"SourceFile",
typeof(string),
propertyInfo: typeof(GoldenSetTargetEntity).GetProperty("SourceFile", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetTargetEntity).GetField("<SourceFile>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
sourceFile.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
sourceFile.AddAnnotation("Relational:ColumnName", "source_file");
var sourceLine = runtimeEntityType.AddProperty(
"SourceLine",
typeof(int?),
propertyInfo: typeof(GoldenSetTargetEntity).GetProperty("SourceLine", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(GoldenSetTargetEntity).GetField("<SourceLine>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
sourceLine.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
sourceLine.AddAnnotation("Relational:ColumnName", "source_line");
var key = runtimeEntityType.AddKey(
new[] { id });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "targets_pkey");
var idx_targets_golden_set = runtimeEntityType.AddIndex(
new[] { goldenSetId },
name: "idx_targets_golden_set");
var idx_targets_function = runtimeEntityType.AddIndex(
new[] { functionName },
name: "idx_targets_function");
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "golden_sets");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "targets");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,109 @@
using Microsoft.EntityFrameworkCore;
using StellaOps.BinaryIndex.GoldenSet.EfCore.Models;
namespace StellaOps.BinaryIndex.GoldenSet.EfCore.Context;
/// <summary>
/// EF Core DbContext for the GoldenSet module.
/// Covers tables in the golden_sets schema.
/// </summary>
public partial class GoldenSetDbContext : DbContext
{
private readonly string _schemaName;
public GoldenSetDbContext(DbContextOptions<GoldenSetDbContext> options, string? schemaName = null)
: base(options)
{
_schemaName = string.IsNullOrWhiteSpace(schemaName)
? "golden_sets"
: schemaName.Trim();
}
public virtual DbSet<GoldenSetDefinitionEntity> Definitions { get; set; }
public virtual DbSet<GoldenSetTargetEntity> Targets { get; set; }
public virtual DbSet<GoldenSetAuditLogEntity> AuditLogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var schemaName = _schemaName;
// =====================================================================
// golden_sets.definitions
// =====================================================================
modelBuilder.Entity<GoldenSetDefinitionEntity>(entity =>
{
entity.HasKey(e => e.Id).HasName("definitions_pkey");
entity.ToTable("definitions", schemaName);
entity.HasIndex(e => e.Component, "idx_goldensets_component");
entity.HasIndex(e => e.Status, "idx_goldensets_status");
entity.HasIndex(e => e.ContentDigest, "idx_goldensets_digest").IsUnique();
entity.HasIndex(e => e.CreatedAt, "idx_goldensets_created").IsDescending();
entity.HasIndex(e => new { e.Component, e.Status }, "idx_goldensets_component_status");
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.Component).HasColumnName("component");
entity.Property(e => e.ContentDigest).HasColumnName("content_digest");
entity.Property(e => e.Status).HasColumnName("status");
entity.Property(e => e.DefinitionYaml).HasColumnName("definition_yaml");
entity.Property(e => e.DefinitionJson).HasColumnType("jsonb").HasColumnName("definition_json");
entity.Property(e => e.TargetCount).HasColumnName("target_count");
entity.Property(e => e.AuthorId).HasColumnName("author_id");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("NOW()").HasColumnName("created_at");
entity.Property(e => e.ReviewedBy).HasColumnName("reviewed_by");
entity.Property(e => e.ReviewedAt).HasColumnName("reviewed_at");
entity.Property(e => e.SourceRef).HasColumnName("source_ref");
entity.Property(e => e.Tags).HasColumnName("tags");
entity.Property(e => e.SchemaVersion).HasColumnName("schema_version");
entity.Property(e => e.UpdatedAt).HasDefaultValueSql("NOW()").HasColumnName("updated_at");
});
// =====================================================================
// golden_sets.targets
// =====================================================================
modelBuilder.Entity<GoldenSetTargetEntity>(entity =>
{
entity.HasKey(e => e.Id).HasName("targets_pkey");
entity.ToTable("targets", schemaName);
entity.HasIndex(e => e.GoldenSetId, "idx_targets_golden_set");
entity.HasIndex(e => e.FunctionName, "idx_targets_function");
entity.Property(e => e.Id).HasDefaultValueSql("gen_random_uuid()").HasColumnName("id");
entity.Property(e => e.GoldenSetId).HasColumnName("golden_set_id");
entity.Property(e => e.FunctionName).HasColumnName("function_name");
entity.Property(e => e.Edges).HasColumnType("jsonb").HasDefaultValueSql("'[]'::jsonb").HasColumnName("edges");
entity.Property(e => e.Sinks).HasColumnName("sinks");
entity.Property(e => e.Constants).HasColumnName("constants");
entity.Property(e => e.TaintInvariant).HasColumnName("taint_invariant");
entity.Property(e => e.SourceFile).HasColumnName("source_file");
entity.Property(e => e.SourceLine).HasColumnName("source_line");
});
// =====================================================================
// golden_sets.audit_log
// =====================================================================
modelBuilder.Entity<GoldenSetAuditLogEntity>(entity =>
{
entity.HasKey(e => e.Id).HasName("audit_log_pkey");
entity.ToTable("audit_log", schemaName);
entity.HasIndex(e => e.GoldenSetId, "idx_audit_golden_set");
entity.HasIndex(e => e.Timestamp, "idx_audit_timestamp").IsDescending();
entity.HasIndex(e => e.ActorId, "idx_audit_actor");
entity.Property(e => e.Id).HasDefaultValueSql("gen_random_uuid()").HasColumnName("id");
entity.Property(e => e.GoldenSetId).HasColumnName("golden_set_id");
entity.Property(e => e.Action).HasColumnName("action");
entity.Property(e => e.ActorId).HasColumnName("actor_id");
entity.Property(e => e.OldStatus).HasColumnName("old_status");
entity.Property(e => e.NewStatus).HasColumnName("new_status");
entity.Property(e => e.Details).HasColumnType("jsonb").HasColumnName("details");
entity.Property(e => e.Timestamp).HasDefaultValueSql("NOW()").HasColumnName("timestamp");
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

View File

@@ -0,0 +1,32 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
namespace StellaOps.BinaryIndex.GoldenSet.EfCore.Context;
/// <summary>
/// Design-time factory for EF Core CLI tooling (scaffold, optimize).
/// </summary>
public sealed class GoldenSetDesignTimeDbContextFactory
: IDesignTimeDbContextFactory<GoldenSetDbContext>
{
private const string DefaultConnectionString =
"Host=localhost;Port=55433;Database=postgres;Username=postgres;Password=postgres;Search Path=golden_sets,public";
private const string ConnectionStringEnvironmentVariable =
"STELLAOPS_GOLDENSET_EF_CONNECTION";
public GoldenSetDbContext CreateDbContext(string[] args)
{
var connectionString = ResolveConnectionString();
var options = new DbContextOptionsBuilder<GoldenSetDbContext>()
.UseNpgsql(connectionString)
.Options;
return new GoldenSetDbContext(options);
}
private static string ResolveConnectionString()
{
var fromEnvironment = Environment.GetEnvironmentVariable(ConnectionStringEnvironmentVariable);
return string.IsNullOrWhiteSpace(fromEnvironment) ? DefaultConnectionString : fromEnvironment;
}
}

View File

@@ -0,0 +1,16 @@
namespace StellaOps.BinaryIndex.GoldenSet.EfCore.Models;
/// <summary>
/// EF Core entity for golden_sets.audit_log table.
/// </summary>
public partial class GoldenSetAuditLogEntity
{
public Guid Id { get; set; }
public string GoldenSetId { get; set; } = null!;
public string Action { get; set; } = null!;
public string ActorId { get; set; } = null!;
public string? OldStatus { get; set; }
public string? NewStatus { get; set; }
public string? Details { get; set; }
public DateTime Timestamp { get; set; }
}

View File

@@ -0,0 +1,23 @@
namespace StellaOps.BinaryIndex.GoldenSet.EfCore.Models;
/// <summary>
/// EF Core entity for golden_sets.definitions table.
/// </summary>
public partial class GoldenSetDefinitionEntity
{
public string Id { get; set; } = null!;
public string Component { get; set; } = null!;
public string ContentDigest { get; set; } = null!;
public string Status { get; set; } = null!;
public string DefinitionYaml { get; set; } = null!;
public string DefinitionJson { get; set; } = null!;
public int TargetCount { get; set; }
public string AuthorId { get; set; } = null!;
public DateTime CreatedAt { get; set; }
public string? ReviewedBy { get; set; }
public DateTime? ReviewedAt { get; set; }
public string SourceRef { get; set; } = null!;
public string[] Tags { get; set; } = null!;
public string SchemaVersion { get; set; } = null!;
public DateTime UpdatedAt { get; set; }
}

View File

@@ -0,0 +1,17 @@
namespace StellaOps.BinaryIndex.GoldenSet.EfCore.Models;
/// <summary>
/// EF Core entity for golden_sets.targets table.
/// </summary>
public partial class GoldenSetTargetEntity
{
public Guid Id { get; set; }
public string GoldenSetId { get; set; } = null!;
public string FunctionName { get; set; } = null!;
public string Edges { get; set; } = null!;
public string[] Sinks { get; set; } = null!;
public string[] Constants { get; set; } = null!;
public string? TaintInvariant { get; set; }
public string? SourceFile { get; set; }
public int? SourceLine { get; set; }
}

View File

@@ -10,6 +10,17 @@
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="Migrations\**\*.sql" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup>
<!-- Prevent automatic compiled-model binding so non-default schemas can build runtime models. -->
<Compile Remove="EfCore\CompiledModels\GoldenSetDbContextAssemblyAttributes.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" />
<PackageReference Include="Microsoft.Extensions.Http" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
@@ -17,6 +28,7 @@
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" />
<PackageReference Include="Microsoft.Extensions.Options.DataAnnotations" />
<PackageReference Include="Npgsql" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
<PackageReference Include="YamlDotNet" />
</ItemGroup>

View File

@@ -7,3 +7,6 @@ Source of truth: `docs/implplan/SPRINT_20260130_002_Tools_csproj_remediation_sol
| QA-BINARYINDEX-VERIFY-024 | BLOCKED | SPRINT_20260211_033 run-001: blocked because required module-local AGENTS is missing for `src/BinaryIndex/__Tests/StellaOps.BinaryIndex.GoldenSet.Tests` (repo AGENTS rule 5). |
| REMED-05 | TODO | Remediation checklist: docs/implplan/audits/csproj-standards/remediation/checklists/src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.GoldenSet/StellaOps.BinaryIndex.GoldenSet.md. |
| REMED-06 | DONE | SOLID review notes captured for SPRINT_20260130_002. |
| BINARY-EF-02 | DONE | SPRINT_20260222_090: EF Core model baseline scaffolded (3 entities, golden_sets schema). |
| BINARY-EF-04 | DONE | SPRINT_20260222_090: Compiled model (6 files) generated. |
| BINARY-EF-05 | DONE | SPRINT_20260222_090: Build/tests validated (261 pass, 0 fail). Module docs updated. |

View File

@@ -8,20 +8,33 @@ Own BinaryIndex persistence layer, migrations, and repositories. Keep data acces
- Ensure RLS tenant context handling is safe and consistent.
- Surface open work on `TASKS.md`; update statuses (TODO/DOING/DONE/BLOCKED/REVIEW).
## DAL Technology
- **Primary**: EF Core v10 (as of Sprint 090 BinaryIndex DAL-to-EF-Core conversion).
- **Legacy wrapper**: `BinaryIndexDbContext` provides NpgsqlConnection with tenant RLS; repositories create EF Core `BinaryIndexPersistenceDbContext` per operation.
- **Compiled model**: `EfCore/CompiledModels/BinaryIndexPersistenceDbContextModel` used when schema names match defaults (`binaries` + `groundtruth`).
- **Mixed DAL**: `FunctionCorpusRepository` (corpus schema) and `PostgresGoldenSetStore` (NpgsqlDataSource) remain Dapper/raw Npgsql. Mixed DAL is acceptable per cutover strategy for adapter-eligible modules.
- **SQL migrations remain authoritative**: EF models are scaffolded FROM the SQL schema, never the reverse. No auto-migrations at runtime.
## Key Paths
- `BinaryIndexDbContext.cs`
- `BinaryIndexMigrationRunner.cs`
- `Repositories/*.cs`
- `BinaryIndexDbContext.cs` (legacy connection wrapper with tenant RLS)
- `EfCore/Context/BinaryIndexPersistenceDbContext.cs` (EF Core DbContext, 15 entities across binaries + groundtruth schemas)
- `EfCore/Models/*.cs` (EF Core entity models)
- `EfCore/CompiledModels/*.cs` (compiled model for runtime performance)
- `Postgres/BinaryIndexPersistenceDbContextFactory.cs` (runtime factory with UseModel conditional)
- `Repositories/*.cs` (EF Core LINQ repositories)
- `Services/BinaryVulnerabilityService.cs`
- `Migrations/*.sql`
- `Migrations/*.sql` (authoritative schema)
## Coordination
- BinaryIndex core/corpus/fix index/fingerprint owners.
- Infrastructure.Postgres team for migrations and testing.
- Platform Database team for migration registry wiring (BinaryIndexMigrationModulePlugin).
## Required Reading
- `docs/modules/binary-index/architecture.md`
- `docs/modules/platform/architecture-overview.md`
- `docs/db/EF_CORE_MODEL_GENERATION_STANDARDS.md`
- `docs/db/EF_CORE_RUNTIME_CUTOVER_STRATEGY.md`
## Working Agreement
- 1. Update task status to `DOING`/`DONE` in both corresponding sprint file `/docs/implplan/SPRINT_*.md` and the local `TASKS.md` when you start or finish work.
@@ -29,4 +42,6 @@ Own BinaryIndex persistence layer, migrations, and repositories. Keep data acces
- 3. Keep changes deterministic (stable ordering, timestamps, hashes) and align with offline/air-gap expectations.
- 4. Coordinate doc updates, tests, and cross-guild communication whenever contracts or workflows change.
- 5. Revert to `TODO` if you pause the task without shipping changes; leave notes in commit/PR descriptions for context.
- 6. When modifying EF entity models, update the corresponding compiled model entity type file to stay in sync.
- 7. When adding new database tables, update both the SQL migration AND the EF DbContext OnModelCreating.

View File

@@ -0,0 +1,226 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class BinaryIdentityEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.Persistence.EfCore.Models.BinaryIdentityEntity",
typeof(BinaryIdentityEntity),
baseEntityType,
propertyCount: 16,
namedIndexCount: 5,
keyCount: 1);
var id = runtimeEntityType.AddProperty(
"Id",
typeof(Guid),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<Id>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: Guid.Empty);
id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
id.AddAnnotation("Relational:ColumnName", "id");
id.AddAnnotation("Relational:DefaultValueSql", "gen_random_uuid()");
var tenantId = runtimeEntityType.AddProperty(
"TenantId",
typeof(Guid),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("TenantId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<TenantId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: Guid.Empty);
tenantId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
tenantId.AddAnnotation("Relational:ColumnName", "tenant_id");
var binaryKey = runtimeEntityType.AddProperty(
"BinaryKey",
typeof(string),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("BinaryKey", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<BinaryKey>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
binaryKey.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
binaryKey.AddAnnotation("Relational:ColumnName", "binary_key");
var buildId = runtimeEntityType.AddProperty(
"BuildId",
typeof(string),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("BuildId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<BuildId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
buildId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
buildId.AddAnnotation("Relational:ColumnName", "build_id");
var buildIdType = runtimeEntityType.AddProperty(
"BuildIdType",
typeof(string),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("BuildIdType", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<BuildIdType>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
buildIdType.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
buildIdType.AddAnnotation("Relational:ColumnName", "build_id_type");
var fileSha256 = runtimeEntityType.AddProperty(
"FileSha256",
typeof(string),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("FileSha256", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<FileSha256>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
fileSha256.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
fileSha256.AddAnnotation("Relational:ColumnName", "file_sha256");
var textSha256 = runtimeEntityType.AddProperty(
"TextSha256",
typeof(string),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("TextSha256", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<TextSha256>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
textSha256.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
textSha256.AddAnnotation("Relational:ColumnName", "text_sha256");
var blake3Hash = runtimeEntityType.AddProperty(
"Blake3Hash",
typeof(string),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("Blake3Hash", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<Blake3Hash>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
blake3Hash.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
blake3Hash.AddAnnotation("Relational:ColumnName", "blake3_hash");
var format = runtimeEntityType.AddProperty(
"Format",
typeof(string),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("Format", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<Format>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
format.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
format.AddAnnotation("Relational:ColumnName", "format");
var architecture = runtimeEntityType.AddProperty(
"Architecture",
typeof(string),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("Architecture", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<Architecture>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
architecture.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
architecture.AddAnnotation("Relational:ColumnName", "architecture");
var osabi = runtimeEntityType.AddProperty(
"Osabi",
typeof(string),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("Osabi", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<Osabi>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
osabi.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
osabi.AddAnnotation("Relational:ColumnName", "osabi");
var binaryType = runtimeEntityType.AddProperty(
"BinaryType",
typeof(string),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("BinaryType", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<BinaryType>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
binaryType.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
binaryType.AddAnnotation("Relational:ColumnName", "binary_type");
var isStripped = runtimeEntityType.AddProperty(
"IsStripped",
typeof(bool?),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("IsStripped", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<IsStripped>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
isStripped.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
isStripped.AddAnnotation("Relational:ColumnName", "is_stripped");
var firstSeenSnapshotId = runtimeEntityType.AddProperty(
"FirstSeenSnapshotId",
typeof(Guid?),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("FirstSeenSnapshotId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<FirstSeenSnapshotId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
firstSeenSnapshotId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
firstSeenSnapshotId.AddAnnotation("Relational:ColumnName", "first_seen_snapshot_id");
var lastSeenSnapshotId = runtimeEntityType.AddProperty(
"LastSeenSnapshotId",
typeof(Guid?),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("LastSeenSnapshotId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<LastSeenSnapshotId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
lastSeenSnapshotId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
lastSeenSnapshotId.AddAnnotation("Relational:ColumnName", "last_seen_snapshot_id");
var createdAt = runtimeEntityType.AddProperty(
"CreatedAt",
typeof(DateTime),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("CreatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<CreatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
createdAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
createdAt.AddAnnotation("Relational:ColumnName", "created_at");
createdAt.AddAnnotation("Relational:DefaultValueSql", "NOW()");
var updatedAt = runtimeEntityType.AddProperty(
"UpdatedAt",
typeof(DateTime),
propertyInfo: typeof(BinaryIdentityEntity).GetProperty("UpdatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryIdentityEntity).GetField("<UpdatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
updatedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
updatedAt.AddAnnotation("Relational:ColumnName", "updated_at");
updatedAt.AddAnnotation("Relational:DefaultValueSql", "NOW()");
var key = runtimeEntityType.AddKey(
new[] { id });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "binary_identity_pkey");
var idx_binary_identity_tenant = runtimeEntityType.AddIndex(
new[] { tenantId },
name: "idx_binary_identity_tenant");
var idx_binary_identity_buildid = runtimeEntityType.AddIndex(
new[] { buildId },
name: "idx_binary_identity_buildid");
idx_binary_identity_buildid.AddAnnotation("Relational:Filter", "(build_id IS NOT NULL)");
var idx_binary_identity_sha256 = runtimeEntityType.AddIndex(
new[] { fileSha256 },
name: "idx_binary_identity_sha256");
var idx_binary_identity_key = runtimeEntityType.AddIndex(
new[] { binaryKey },
name: "idx_binary_identity_key");
var binary_identity_key_unique = runtimeEntityType.AddIndex(
new[] { tenantId, binaryKey },
name: "binary_identity_key_unique",
unique: true);
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "binaries");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "binary_identity");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,9 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore.Infrastructure;
using StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels;
using StellaOps.BinaryIndex.Persistence.EfCore.Context;
#pragma warning disable 219, 612, 618
#nullable disable
[assembly: DbContextModel(typeof(BinaryIndexPersistenceDbContext), typeof(BinaryIndexPersistenceDbContextModel))]

View File

@@ -0,0 +1,48 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Context;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[DbContext(typeof(BinaryIndexPersistenceDbContext))]
public partial class BinaryIndexPersistenceDbContextModel : RuntimeModel
{
private static readonly bool _useOldBehavior31751 =
System.AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31751", out var enabled31751) && enabled31751;
static BinaryIndexPersistenceDbContextModel()
{
var model = new BinaryIndexPersistenceDbContextModel();
if (_useOldBehavior31751)
{
model.Initialize();
}
else
{
var thread = new System.Threading.Thread(RunInitialization, 10 * 1024 * 1024);
thread.Start();
thread.Join();
void RunInitialization()
{
model.Initialize();
}
}
model.Customize();
_instance = (BinaryIndexPersistenceDbContextModel)model.FinalizeModel();
}
private static BinaryIndexPersistenceDbContextModel _instance;
public static IModel Instance => _instance;
partial void Initialize();
partial void Customize();
}
}

View File

@@ -0,0 +1,62 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
public partial class BinaryIndexPersistenceDbContextModel
{
private BinaryIndexPersistenceDbContextModel()
: base(skipDetectChanges: false, modelId: new Guid("a14c9f2e-7b3d-4e8a-b5c1-d6f0e2a91834"), entityTypeCount: 15)
{
}
partial void Initialize()
{
// --- binaries schema ---
var binaryIdentity = BinaryIdentityEntityType.Create(this);
var corpusSnapshot = CorpusSnapshotEntityType.Create(this);
var binaryVulnAssertion = BinaryVulnAssertionEntityType.Create(this);
var deltaSignature = DeltaSignatureDbEntityType.Create(this);
var deltaSigMatch = DeltaSigMatchDbEntityType.Create(this);
var vulnerableFingerprint = VulnerableFingerprintEntityType.Create(this);
var fingerprintMatch = FingerprintMatchEntityType.Create(this);
var fingerprintCorpusMetadata = FingerprintCorpusMetadataEntityType.Create(this);
var cveFixIndex = CveFixIndexEntityType.Create(this);
var fixEvidence = FixEvidenceEntityType.Create(this);
// --- groundtruth schema ---
var symbolSource = SymbolSourceEntityType.Create(this);
var sourceState = SourceStateEntityType.Create(this);
var rawDocument = RawDocumentEntityType.Create(this);
var symbolObservation = SymbolObservationEntityType.Create(this);
var securityPair = SecurityPairEntityType.Create(this);
// --- annotations ---
BinaryIdentityEntityType.CreateAnnotations(binaryIdentity);
CorpusSnapshotEntityType.CreateAnnotations(corpusSnapshot);
BinaryVulnAssertionEntityType.CreateAnnotations(binaryVulnAssertion);
DeltaSignatureDbEntityType.CreateAnnotations(deltaSignature);
DeltaSigMatchDbEntityType.CreateAnnotations(deltaSigMatch);
VulnerableFingerprintEntityType.CreateAnnotations(vulnerableFingerprint);
FingerprintMatchEntityType.CreateAnnotations(fingerprintMatch);
FingerprintCorpusMetadataEntityType.CreateAnnotations(fingerprintCorpusMetadata);
CveFixIndexEntityType.CreateAnnotations(cveFixIndex);
FixEvidenceEntityType.CreateAnnotations(fixEvidence);
SymbolSourceEntityType.CreateAnnotations(symbolSource);
SourceStateEntityType.CreateAnnotations(sourceState);
RawDocumentEntityType.CreateAnnotations(rawDocument);
SymbolObservationEntityType.CreateAnnotations(symbolObservation);
SecurityPairEntityType.CreateAnnotations(securityPair);
AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
AddAnnotation("ProductVersion", "10.0.0");
AddAnnotation("Relational:MaxIdentifierLength", 63);
}
}
}

View File

@@ -0,0 +1,185 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class BinaryVulnAssertionEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.Persistence.EfCore.Models.BinaryVulnAssertionEntity",
typeof(BinaryVulnAssertionEntity),
baseEntityType,
propertyCount: 12,
namedIndexCount: 3,
keyCount: 1);
var id = runtimeEntityType.AddProperty(
"Id",
typeof(Guid),
propertyInfo: typeof(BinaryVulnAssertionEntity).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryVulnAssertionEntity).GetField("<Id>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: Guid.Empty);
id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
id.AddAnnotation("Relational:ColumnName", "id");
id.AddAnnotation("Relational:DefaultValueSql", "gen_random_uuid()");
var tenantId = runtimeEntityType.AddProperty(
"TenantId",
typeof(Guid),
propertyInfo: typeof(BinaryVulnAssertionEntity).GetProperty("TenantId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryVulnAssertionEntity).GetField("<TenantId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: Guid.Empty);
tenantId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
tenantId.AddAnnotation("Relational:ColumnName", "tenant_id");
var binaryKey = runtimeEntityType.AddProperty(
"BinaryKey",
typeof(string),
propertyInfo: typeof(BinaryVulnAssertionEntity).GetProperty("BinaryKey", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryVulnAssertionEntity).GetField("<BinaryKey>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
binaryKey.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
binaryKey.AddAnnotation("Relational:ColumnName", "binary_key");
var binaryIdentityId = runtimeEntityType.AddProperty(
"BinaryIdentityId",
typeof(Guid?),
propertyInfo: typeof(BinaryVulnAssertionEntity).GetProperty("BinaryIdentityId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryVulnAssertionEntity).GetField("<BinaryIdentityId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
binaryIdentityId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
binaryIdentityId.AddAnnotation("Relational:ColumnName", "binary_identity_id");
var cveId = runtimeEntityType.AddProperty(
"CveId",
typeof(string),
propertyInfo: typeof(BinaryVulnAssertionEntity).GetProperty("CveId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryVulnAssertionEntity).GetField("<CveId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
cveId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
cveId.AddAnnotation("Relational:ColumnName", "cve_id");
var advisoryId = runtimeEntityType.AddProperty(
"AdvisoryId",
typeof(Guid?),
propertyInfo: typeof(BinaryVulnAssertionEntity).GetProperty("AdvisoryId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryVulnAssertionEntity).GetField("<AdvisoryId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
advisoryId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
advisoryId.AddAnnotation("Relational:ColumnName", "advisory_id");
var status = runtimeEntityType.AddProperty(
"Status",
typeof(string),
propertyInfo: typeof(BinaryVulnAssertionEntity).GetProperty("Status", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryVulnAssertionEntity).GetField("<Status>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
status.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
status.AddAnnotation("Relational:ColumnName", "status");
var method = runtimeEntityType.AddProperty(
"Method",
typeof(string),
propertyInfo: typeof(BinaryVulnAssertionEntity).GetProperty("Method", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryVulnAssertionEntity).GetField("<Method>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
method.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
method.AddAnnotation("Relational:ColumnName", "method");
var confidence = runtimeEntityType.AddProperty(
"Confidence",
typeof(decimal?),
propertyInfo: typeof(BinaryVulnAssertionEntity).GetProperty("Confidence", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryVulnAssertionEntity).GetField("<Confidence>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
confidence.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
confidence.AddAnnotation("Relational:ColumnName", "confidence");
var evidenceRef = runtimeEntityType.AddProperty(
"EvidenceRef",
typeof(string),
propertyInfo: typeof(BinaryVulnAssertionEntity).GetProperty("EvidenceRef", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryVulnAssertionEntity).GetField("<EvidenceRef>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
evidenceRef.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
evidenceRef.AddAnnotation("Relational:ColumnName", "evidence_ref");
var evidenceDigest = runtimeEntityType.AddProperty(
"EvidenceDigest",
typeof(string),
propertyInfo: typeof(BinaryVulnAssertionEntity).GetProperty("EvidenceDigest", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryVulnAssertionEntity).GetField("<EvidenceDigest>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
evidenceDigest.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
evidenceDigest.AddAnnotation("Relational:ColumnName", "evidence_digest");
var evaluatedAt = runtimeEntityType.AddProperty(
"EvaluatedAt",
typeof(DateTime),
propertyInfo: typeof(BinaryVulnAssertionEntity).GetProperty("EvaluatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryVulnAssertionEntity).GetField("<EvaluatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
evaluatedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
evaluatedAt.AddAnnotation("Relational:ColumnName", "evaluated_at");
evaluatedAt.AddAnnotation("Relational:DefaultValueSql", "NOW()");
var createdAt = runtimeEntityType.AddProperty(
"CreatedAt",
typeof(DateTime),
propertyInfo: typeof(BinaryVulnAssertionEntity).GetProperty("CreatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(BinaryVulnAssertionEntity).GetField("<CreatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
createdAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
createdAt.AddAnnotation("Relational:ColumnName", "created_at");
createdAt.AddAnnotation("Relational:DefaultValueSql", "NOW()");
var key = runtimeEntityType.AddKey(
new[] { id });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "binary_vuln_assertion_pkey");
var idx_binary_vuln_assertion_tenant = runtimeEntityType.AddIndex(
new[] { tenantId },
name: "idx_binary_vuln_assertion_tenant");
var idx_binary_vuln_assertion_binary = runtimeEntityType.AddIndex(
new[] { binaryKey },
name: "idx_binary_vuln_assertion_binary");
var idx_binary_vuln_assertion_cve = runtimeEntityType.AddIndex(
new[] { cveId },
name: "idx_binary_vuln_assertion_cve");
var binary_vuln_assertion_unique = runtimeEntityType.AddIndex(
new[] { tenantId, binaryKey, cveId },
name: "binary_vuln_assertion_unique",
unique: true);
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "binaries");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "binary_vuln_assertion");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,205 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class CorpusSnapshotEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.Persistence.EfCore.Models.CorpusSnapshotEntity",
typeof(CorpusSnapshotEntity),
baseEntityType,
propertyCount: 15,
namedIndexCount: 2,
keyCount: 1);
var id = runtimeEntityType.AddProperty(
"Id",
typeof(Guid),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<Id>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: Guid.Empty);
id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
id.AddAnnotation("Relational:ColumnName", "id");
id.AddAnnotation("Relational:DefaultValueSql", "gen_random_uuid()");
var tenantId = runtimeEntityType.AddProperty(
"TenantId",
typeof(Guid),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("TenantId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<TenantId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: Guid.Empty);
tenantId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
tenantId.AddAnnotation("Relational:ColumnName", "tenant_id");
var distro = runtimeEntityType.AddProperty(
"Distro",
typeof(string),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("Distro", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<Distro>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
distro.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
distro.AddAnnotation("Relational:ColumnName", "distro");
var release = runtimeEntityType.AddProperty(
"Release",
typeof(string),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("Release", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<Release>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
release.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
release.AddAnnotation("Relational:ColumnName", "release");
var architecture = runtimeEntityType.AddProperty(
"Architecture",
typeof(string),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("Architecture", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<Architecture>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
architecture.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
architecture.AddAnnotation("Relational:ColumnName", "architecture");
var snapshotId = runtimeEntityType.AddProperty(
"SnapshotId",
typeof(string),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("SnapshotId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<SnapshotId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
snapshotId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
snapshotId.AddAnnotation("Relational:ColumnName", "snapshot_id");
var packagesProcessed = runtimeEntityType.AddProperty(
"PackagesProcessed",
typeof(int),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("PackagesProcessed", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<PackagesProcessed>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: 0);
packagesProcessed.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
packagesProcessed.AddAnnotation("Relational:ColumnName", "packages_processed");
var binariesIndexed = runtimeEntityType.AddProperty(
"BinariesIndexed",
typeof(int),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("BinariesIndexed", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<BinariesIndexed>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: 0);
binariesIndexed.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
binariesIndexed.AddAnnotation("Relational:ColumnName", "binaries_indexed");
var repoMetadataDigest = runtimeEntityType.AddProperty(
"RepoMetadataDigest",
typeof(string),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("RepoMetadataDigest", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<RepoMetadataDigest>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
repoMetadataDigest.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
repoMetadataDigest.AddAnnotation("Relational:ColumnName", "repo_metadata_digest");
var signingKeyId = runtimeEntityType.AddProperty(
"SigningKeyId",
typeof(string),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("SigningKeyId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<SigningKeyId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
signingKeyId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
signingKeyId.AddAnnotation("Relational:ColumnName", "signing_key_id");
var dsseEnvelopeRef = runtimeEntityType.AddProperty(
"DsseEnvelopeRef",
typeof(string),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("DsseEnvelopeRef", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<DsseEnvelopeRef>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
dsseEnvelopeRef.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
dsseEnvelopeRef.AddAnnotation("Relational:ColumnName", "dsse_envelope_ref");
var status = runtimeEntityType.AddProperty(
"Status",
typeof(string),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("Status", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<Status>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
status.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
status.AddAnnotation("Relational:ColumnName", "status");
var error = runtimeEntityType.AddProperty(
"Error",
typeof(string),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("Error", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<Error>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
error.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
error.AddAnnotation("Relational:ColumnName", "error");
var startedAt = runtimeEntityType.AddProperty(
"StartedAt",
typeof(DateTime?),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("StartedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<StartedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
startedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
startedAt.AddAnnotation("Relational:ColumnName", "started_at");
var completedAt = runtimeEntityType.AddProperty(
"CompletedAt",
typeof(DateTime?),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("CompletedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<CompletedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
completedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
completedAt.AddAnnotation("Relational:ColumnName", "completed_at");
var createdAt = runtimeEntityType.AddProperty(
"CreatedAt",
typeof(DateTime),
propertyInfo: typeof(CorpusSnapshotEntity).GetProperty("CreatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CorpusSnapshotEntity).GetField("<CreatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
createdAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
createdAt.AddAnnotation("Relational:ColumnName", "created_at");
createdAt.AddAnnotation("Relational:DefaultValueSql", "NOW()");
var key = runtimeEntityType.AddKey(
new[] { id });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "corpus_snapshots_pkey");
var idx_corpus_snapshots_tenant = runtimeEntityType.AddIndex(
new[] { tenantId },
name: "idx_corpus_snapshots_tenant");
var idx_corpus_snapshots_distro = runtimeEntityType.AddIndex(
new[] { distro, release, architecture },
name: "idx_corpus_snapshots_distro");
var corpus_snapshots_unique = runtimeEntityType.AddIndex(
new[] { tenantId, distro, release, architecture, snapshotId },
name: "corpus_snapshots_unique",
unique: true);
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "binaries");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "corpus_snapshots");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,196 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class CveFixIndexEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.Persistence.EfCore.Models.CveFixIndexEntity",
typeof(CveFixIndexEntity),
baseEntityType,
propertyCount: 14,
namedIndexCount: 2,
keyCount: 1);
var id = runtimeEntityType.AddProperty(
"Id",
typeof(Guid),
propertyInfo: typeof(CveFixIndexEntity).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CveFixIndexEntity).GetField("<Id>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: Guid.Empty);
id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
id.AddAnnotation("Relational:ColumnName", "id");
id.AddAnnotation("Relational:DefaultValueSql", "gen_random_uuid()");
var tenantId = runtimeEntityType.AddProperty(
"TenantId",
typeof(string),
propertyInfo: typeof(CveFixIndexEntity).GetProperty("TenantId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CveFixIndexEntity).GetField("<TenantId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
tenantId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
tenantId.AddAnnotation("Relational:ColumnName", "tenant_id");
var distro = runtimeEntityType.AddProperty(
"Distro",
typeof(string),
propertyInfo: typeof(CveFixIndexEntity).GetProperty("Distro", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CveFixIndexEntity).GetField("<Distro>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
distro.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
distro.AddAnnotation("Relational:ColumnName", "distro");
var release = runtimeEntityType.AddProperty(
"Release",
typeof(string),
propertyInfo: typeof(CveFixIndexEntity).GetProperty("Release", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CveFixIndexEntity).GetField("<Release>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
release.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
release.AddAnnotation("Relational:ColumnName", "release");
var sourcePkg = runtimeEntityType.AddProperty(
"SourcePkg",
typeof(string),
propertyInfo: typeof(CveFixIndexEntity).GetProperty("SourcePkg", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CveFixIndexEntity).GetField("<SourcePkg>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
sourcePkg.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
sourcePkg.AddAnnotation("Relational:ColumnName", "source_pkg");
var cveId = runtimeEntityType.AddProperty(
"CveId",
typeof(string),
propertyInfo: typeof(CveFixIndexEntity).GetProperty("CveId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CveFixIndexEntity).GetField("<CveId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
cveId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
cveId.AddAnnotation("Relational:ColumnName", "cve_id");
var architecture = runtimeEntityType.AddProperty(
"Architecture",
typeof(string),
propertyInfo: typeof(CveFixIndexEntity).GetProperty("Architecture", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CveFixIndexEntity).GetField("<Architecture>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
architecture.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
architecture.AddAnnotation("Relational:ColumnName", "architecture");
var state = runtimeEntityType.AddProperty(
"State",
typeof(string),
propertyInfo: typeof(CveFixIndexEntity).GetProperty("State", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CveFixIndexEntity).GetField("<State>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
state.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
state.AddAnnotation("Relational:ColumnName", "state");
var fixedVersion = runtimeEntityType.AddProperty(
"FixedVersion",
typeof(string),
propertyInfo: typeof(CveFixIndexEntity).GetProperty("FixedVersion", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CveFixIndexEntity).GetField("<FixedVersion>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
fixedVersion.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
fixedVersion.AddAnnotation("Relational:ColumnName", "fixed_version");
var method = runtimeEntityType.AddProperty(
"Method",
typeof(string),
propertyInfo: typeof(CveFixIndexEntity).GetProperty("Method", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CveFixIndexEntity).GetField("<Method>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
method.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
method.AddAnnotation("Relational:ColumnName", "method");
var confidence = runtimeEntityType.AddProperty(
"Confidence",
typeof(decimal),
propertyInfo: typeof(CveFixIndexEntity).GetProperty("Confidence", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CveFixIndexEntity).GetField("<Confidence>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: 0m);
confidence.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
confidence.AddAnnotation("Relational:ColumnName", "confidence");
var evidenceId = runtimeEntityType.AddProperty(
"EvidenceId",
typeof(Guid?),
propertyInfo: typeof(CveFixIndexEntity).GetProperty("EvidenceId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CveFixIndexEntity).GetField("<EvidenceId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
evidenceId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
evidenceId.AddAnnotation("Relational:ColumnName", "evidence_id");
var snapshotId = runtimeEntityType.AddProperty(
"SnapshotId",
typeof(Guid?),
propertyInfo: typeof(CveFixIndexEntity).GetProperty("SnapshotId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CveFixIndexEntity).GetField("<SnapshotId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
snapshotId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
snapshotId.AddAnnotation("Relational:ColumnName", "snapshot_id");
var indexedAt = runtimeEntityType.AddProperty(
"IndexedAt",
typeof(DateTime),
propertyInfo: typeof(CveFixIndexEntity).GetProperty("IndexedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CveFixIndexEntity).GetField("<IndexedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
indexedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
indexedAt.AddAnnotation("Relational:ColumnName", "indexed_at");
indexedAt.AddAnnotation("Relational:DefaultValueSql", "now()");
var updatedAt = runtimeEntityType.AddProperty(
"UpdatedAt",
typeof(DateTime),
propertyInfo: typeof(CveFixIndexEntity).GetProperty("UpdatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(CveFixIndexEntity).GetField("<UpdatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
updatedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
updatedAt.AddAnnotation("Relational:ColumnName", "updated_at");
updatedAt.AddAnnotation("Relational:DefaultValueSql", "now()");
var key = runtimeEntityType.AddKey(
new[] { id });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "cve_fix_index_pkey");
var idx_cve_fix_lookup = runtimeEntityType.AddIndex(
new[] { tenantId, distro, release, sourcePkg, cveId },
name: "idx_cve_fix_lookup");
var idx_cve_fix_by_cve = runtimeEntityType.AddIndex(
new[] { tenantId, cveId, distro, release },
name: "idx_cve_fix_by_cve");
var cve_fix_index_unique = runtimeEntityType.AddIndex(
new[] { tenantId, distro, release, sourcePkg, cveId, architecture },
name: "cve_fix_index_unique",
unique: true);
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "binaries");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "cve_fix_index");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,218 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class DeltaSigMatchDbEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.Persistence.EfCore.Models.DeltaSigMatchDbEntity",
typeof(DeltaSigMatchDbEntity),
baseEntityType,
propertyCount: 15,
namedIndexCount: 4,
keyCount: 1);
var id = runtimeEntityType.AddProperty(
"Id",
typeof(Guid),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<Id>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: Guid.Empty);
id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
id.AddAnnotation("Relational:ColumnName", "id");
id.AddAnnotation("Relational:DefaultValueSql", "gen_random_uuid()");
var tenantId = runtimeEntityType.AddProperty(
"TenantId",
typeof(Guid),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("TenantId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<TenantId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: Guid.Empty);
tenantId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
tenantId.AddAnnotation("Relational:ColumnName", "tenant_id");
var binaryIdentityId = runtimeEntityType.AddProperty(
"BinaryIdentityId",
typeof(Guid?),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("BinaryIdentityId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<BinaryIdentityId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
binaryIdentityId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
binaryIdentityId.AddAnnotation("Relational:ColumnName", "binary_identity_id");
var binaryKey = runtimeEntityType.AddProperty(
"BinaryKey",
typeof(string),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("BinaryKey", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<BinaryKey>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
binaryKey.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
binaryKey.AddAnnotation("Relational:ColumnName", "binary_key");
var binarySha256 = runtimeEntityType.AddProperty(
"BinarySha256",
typeof(string),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("BinarySha256", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<BinarySha256>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true,
maxLength: 64);
binarySha256.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
binarySha256.AddAnnotation("Relational:ColumnName", "binary_sha256");
var signatureId = runtimeEntityType.AddProperty(
"SignatureId",
typeof(Guid?),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("SignatureId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<SignatureId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
signatureId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
signatureId.AddAnnotation("Relational:ColumnName", "signature_id");
var cveId = runtimeEntityType.AddProperty(
"CveId",
typeof(string),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("CveId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<CveId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 20);
cveId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
cveId.AddAnnotation("Relational:ColumnName", "cve_id");
var symbolName = runtimeEntityType.AddProperty(
"SymbolName",
typeof(string),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("SymbolName", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<SymbolName>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 255);
symbolName.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
symbolName.AddAnnotation("Relational:ColumnName", "symbol_name");
var matchType = runtimeEntityType.AddProperty(
"MatchType",
typeof(string),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("MatchType", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<MatchType>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 20);
matchType.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
matchType.AddAnnotation("Relational:ColumnName", "match_type");
var confidence = runtimeEntityType.AddProperty(
"Confidence",
typeof(decimal),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("Confidence", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<Confidence>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: 0m);
confidence.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
confidence.AddAnnotation("Relational:ColumnName", "confidence");
var chunkMatchRatio = runtimeEntityType.AddProperty(
"ChunkMatchRatio",
typeof(decimal?),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("ChunkMatchRatio", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<ChunkMatchRatio>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
chunkMatchRatio.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
chunkMatchRatio.AddAnnotation("Relational:ColumnName", "chunk_match_ratio");
var matchedState = runtimeEntityType.AddProperty(
"MatchedState",
typeof(string),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("MatchedState", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<MatchedState>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 20);
matchedState.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
matchedState.AddAnnotation("Relational:ColumnName", "matched_state");
var scanId = runtimeEntityType.AddProperty(
"ScanId",
typeof(Guid?),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("ScanId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<ScanId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
scanId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
scanId.AddAnnotation("Relational:ColumnName", "scan_id");
var scannedAt = runtimeEntityType.AddProperty(
"ScannedAt",
typeof(DateTime),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("ScannedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<ScannedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
scannedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
scannedAt.AddAnnotation("Relational:ColumnName", "scanned_at");
scannedAt.AddAnnotation("Relational:DefaultValueSql", "NOW()");
var explanation = runtimeEntityType.AddProperty(
"Explanation",
typeof(string),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("Explanation", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<Explanation>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
explanation.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
explanation.AddAnnotation("Relational:ColumnName", "explanation");
var metadata = runtimeEntityType.AddProperty(
"Metadata",
typeof(string),
propertyInfo: typeof(DeltaSigMatchDbEntity).GetProperty("Metadata", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSigMatchDbEntity).GetField("<Metadata>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
metadata.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
metadata.AddAnnotation("Relational:ColumnName", "metadata");
metadata.AddAnnotation("Relational:ColumnType", "jsonb");
var key = runtimeEntityType.AddKey(
new[] { id });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "delta_sig_match_pkey");
var idx_delta_match_tenant = runtimeEntityType.AddIndex(
new[] { tenantId },
name: "idx_delta_match_tenant");
var idx_delta_match_cve = runtimeEntityType.AddIndex(
new[] { cveId },
name: "idx_delta_match_cve");
var idx_delta_match_binary = runtimeEntityType.AddIndex(
new[] { binaryKey },
name: "idx_delta_match_binary");
var idx_delta_match_scan = runtimeEntityType.AddIndex(
new[] { scanId },
name: "idx_delta_match_scan");
var idx_delta_match_state = runtimeEntityType.AddIndex(
new[] { matchedState },
name: "idx_delta_match_state");
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "binaries");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "delta_sig_match");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,281 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class DeltaSignatureDbEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.Persistence.EfCore.Models.DeltaSignatureDbEntity",
typeof(DeltaSignatureDbEntity),
baseEntityType,
propertyCount: 20,
namedIndexCount: 5,
keyCount: 1);
var id = runtimeEntityType.AddProperty(
"Id",
typeof(Guid),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<Id>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: Guid.Empty);
id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
id.AddAnnotation("Relational:ColumnName", "id");
id.AddAnnotation("Relational:DefaultValueSql", "gen_random_uuid()");
var tenantId = runtimeEntityType.AddProperty(
"TenantId",
typeof(Guid),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("TenantId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<TenantId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: Guid.Empty);
tenantId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
tenantId.AddAnnotation("Relational:ColumnName", "tenant_id");
var cveId = runtimeEntityType.AddProperty(
"CveId",
typeof(string),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("CveId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<CveId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 20);
cveId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
cveId.AddAnnotation("Relational:ColumnName", "cve_id");
var packageName = runtimeEntityType.AddProperty(
"PackageName",
typeof(string),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("PackageName", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<PackageName>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 255);
packageName.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
packageName.AddAnnotation("Relational:ColumnName", "package_name");
var soname = runtimeEntityType.AddProperty(
"Soname",
typeof(string),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("Soname", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<Soname>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true,
maxLength: 255);
soname.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
soname.AddAnnotation("Relational:ColumnName", "soname");
var arch = runtimeEntityType.AddProperty(
"Arch",
typeof(string),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("Arch", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<Arch>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 20);
arch.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
arch.AddAnnotation("Relational:ColumnName", "arch");
var abi = runtimeEntityType.AddProperty(
"Abi",
typeof(string),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("Abi", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<Abi>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 20);
abi.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
abi.AddAnnotation("Relational:ColumnName", "abi");
var recipeId = runtimeEntityType.AddProperty(
"RecipeId",
typeof(string),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("RecipeId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<RecipeId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 50);
recipeId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
recipeId.AddAnnotation("Relational:ColumnName", "recipe_id");
var recipeVersion = runtimeEntityType.AddProperty(
"RecipeVersion",
typeof(string),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("RecipeVersion", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<RecipeVersion>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 10);
recipeVersion.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
recipeVersion.AddAnnotation("Relational:ColumnName", "recipe_version");
var symbolName = runtimeEntityType.AddProperty(
"SymbolName",
typeof(string),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("SymbolName", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<SymbolName>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 255);
symbolName.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
symbolName.AddAnnotation("Relational:ColumnName", "symbol_name");
var scope = runtimeEntityType.AddProperty(
"Scope",
typeof(string),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("Scope", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<Scope>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 20);
scope.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
scope.AddAnnotation("Relational:ColumnName", "scope");
var hashAlg = runtimeEntityType.AddProperty(
"HashAlg",
typeof(string),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("HashAlg", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<HashAlg>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 20);
hashAlg.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
hashAlg.AddAnnotation("Relational:ColumnName", "hash_alg");
var hashHex = runtimeEntityType.AddProperty(
"HashHex",
typeof(string),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("HashHex", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<HashHex>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 128);
hashHex.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
hashHex.AddAnnotation("Relational:ColumnName", "hash_hex");
var sizeBytes = runtimeEntityType.AddProperty(
"SizeBytes",
typeof(int),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("SizeBytes", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<SizeBytes>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: 0);
sizeBytes.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
sizeBytes.AddAnnotation("Relational:ColumnName", "size_bytes");
var cfgBbCount = runtimeEntityType.AddProperty(
"CfgBbCount",
typeof(int?),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("CfgBbCount", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<CfgBbCount>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
cfgBbCount.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
cfgBbCount.AddAnnotation("Relational:ColumnName", "cfg_bb_count");
var cfgEdgeHash = runtimeEntityType.AddProperty(
"CfgEdgeHash",
typeof(string),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("CfgEdgeHash", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<CfgEdgeHash>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true,
maxLength: 128);
cfgEdgeHash.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
cfgEdgeHash.AddAnnotation("Relational:ColumnName", "cfg_edge_hash");
var chunkHashes = runtimeEntityType.AddProperty(
"ChunkHashes",
typeof(string),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("ChunkHashes", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<ChunkHashes>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
chunkHashes.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
chunkHashes.AddAnnotation("Relational:ColumnName", "chunk_hashes");
chunkHashes.AddAnnotation("Relational:ColumnType", "jsonb");
var signatureState = runtimeEntityType.AddProperty(
"SignatureState",
typeof(string),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("SignatureState", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<SignatureState>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 20);
signatureState.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
signatureState.AddAnnotation("Relational:ColumnName", "signature_state");
var createdAt = runtimeEntityType.AddProperty(
"CreatedAt",
typeof(DateTime),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("CreatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<CreatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
createdAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
createdAt.AddAnnotation("Relational:ColumnName", "created_at");
createdAt.AddAnnotation("Relational:DefaultValueSql", "NOW()");
var updatedAt = runtimeEntityType.AddProperty(
"UpdatedAt",
typeof(DateTime),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("UpdatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<UpdatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
updatedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
updatedAt.AddAnnotation("Relational:ColumnName", "updated_at");
updatedAt.AddAnnotation("Relational:DefaultValueSql", "NOW()");
var attestationDsse = runtimeEntityType.AddProperty(
"AttestationDsse",
typeof(byte[]),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("AttestationDsse", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<AttestationDsse>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
attestationDsse.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
attestationDsse.AddAnnotation("Relational:ColumnName", "attestation_dsse");
var metadata = runtimeEntityType.AddProperty(
"Metadata",
typeof(string),
propertyInfo: typeof(DeltaSignatureDbEntity).GetProperty("Metadata", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(DeltaSignatureDbEntity).GetField("<Metadata>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
metadata.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
metadata.AddAnnotation("Relational:ColumnName", "metadata");
metadata.AddAnnotation("Relational:ColumnType", "jsonb");
var key = runtimeEntityType.AddKey(
new[] { id });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "delta_signature_pkey");
var idx_delta_sig_tenant = runtimeEntityType.AddIndex(
new[] { tenantId },
name: "idx_delta_sig_tenant");
var idx_delta_sig_cve = runtimeEntityType.AddIndex(
new[] { cveId },
name: "idx_delta_sig_cve");
var idx_delta_sig_pkg = runtimeEntityType.AddIndex(
new[] { packageName, soname },
name: "idx_delta_sig_pkg");
var idx_delta_sig_hash = runtimeEntityType.AddIndex(
new[] { hashHex },
name: "idx_delta_sig_hash");
var idx_delta_sig_state = runtimeEntityType.AddIndex(
new[] { signatureState },
name: "idx_delta_sig_state");
var idx_delta_sig_arch = runtimeEntityType.AddIndex(
new[] { arch, abi },
name: "idx_delta_sig_arch");
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "binaries");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "delta_signature");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,164 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class FingerprintCorpusMetadataEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.Persistence.EfCore.Models.FingerprintCorpusMetadataEntity",
typeof(FingerprintCorpusMetadataEntity),
baseEntityType,
propertyCount: 10,
namedIndexCount: 2,
keyCount: 1);
var id = runtimeEntityType.AddProperty(
"Id",
typeof(Guid),
propertyInfo: typeof(FingerprintCorpusMetadataEntity).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintCorpusMetadataEntity).GetField("<Id>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: Guid.Empty);
id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
id.AddAnnotation("Relational:ColumnName", "id");
id.AddAnnotation("Relational:DefaultValueSql", "gen_random_uuid()");
var tenantId = runtimeEntityType.AddProperty(
"TenantId",
typeof(Guid),
propertyInfo: typeof(FingerprintCorpusMetadataEntity).GetProperty("TenantId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintCorpusMetadataEntity).GetField("<TenantId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: Guid.Empty);
tenantId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
tenantId.AddAnnotation("Relational:ColumnName", "tenant_id");
var purl = runtimeEntityType.AddProperty(
"Purl",
typeof(string),
propertyInfo: typeof(FingerprintCorpusMetadataEntity).GetProperty("Purl", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintCorpusMetadataEntity).GetField("<Purl>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
purl.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
purl.AddAnnotation("Relational:ColumnName", "purl");
var version = runtimeEntityType.AddProperty(
"Version",
typeof(string),
propertyInfo: typeof(FingerprintCorpusMetadataEntity).GetProperty("Version", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintCorpusMetadataEntity).GetField("<Version>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
version.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
version.AddAnnotation("Relational:ColumnName", "version");
var algorithm = runtimeEntityType.AddProperty(
"Algorithm",
typeof(string),
propertyInfo: typeof(FingerprintCorpusMetadataEntity).GetProperty("Algorithm", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintCorpusMetadataEntity).GetField("<Algorithm>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
algorithm.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
algorithm.AddAnnotation("Relational:ColumnName", "algorithm");
var binaryDigest = runtimeEntityType.AddProperty(
"BinaryDigest",
typeof(string),
propertyInfo: typeof(FingerprintCorpusMetadataEntity).GetProperty("BinaryDigest", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintCorpusMetadataEntity).GetField("<BinaryDigest>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
binaryDigest.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
binaryDigest.AddAnnotation("Relational:ColumnName", "binary_digest");
var functionCount = runtimeEntityType.AddProperty(
"FunctionCount",
typeof(int),
propertyInfo: typeof(FingerprintCorpusMetadataEntity).GetProperty("FunctionCount", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintCorpusMetadataEntity).GetField("<FunctionCount>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: 0);
functionCount.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
functionCount.AddAnnotation("Relational:ColumnName", "function_count");
var fingerprintsIndexed = runtimeEntityType.AddProperty(
"FingerprintsIndexed",
typeof(int),
propertyInfo: typeof(FingerprintCorpusMetadataEntity).GetProperty("FingerprintsIndexed", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintCorpusMetadataEntity).GetField("<FingerprintsIndexed>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: 0);
fingerprintsIndexed.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
fingerprintsIndexed.AddAnnotation("Relational:ColumnName", "fingerprints_indexed");
var indexedBy = runtimeEntityType.AddProperty(
"IndexedBy",
typeof(string),
propertyInfo: typeof(FingerprintCorpusMetadataEntity).GetProperty("IndexedBy", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintCorpusMetadataEntity).GetField("<IndexedBy>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
indexedBy.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
indexedBy.AddAnnotation("Relational:ColumnName", "indexed_by");
var indexedAt = runtimeEntityType.AddProperty(
"IndexedAt",
typeof(DateTime),
propertyInfo: typeof(FingerprintCorpusMetadataEntity).GetProperty("IndexedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintCorpusMetadataEntity).GetField("<IndexedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
indexedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
indexedAt.AddAnnotation("Relational:ColumnName", "indexed_at");
indexedAt.AddAnnotation("Relational:DefaultValueSql", "NOW()");
var createdAt = runtimeEntityType.AddProperty(
"CreatedAt",
typeof(DateTime),
propertyInfo: typeof(FingerprintCorpusMetadataEntity).GetProperty("CreatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintCorpusMetadataEntity).GetField("<CreatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
createdAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
createdAt.AddAnnotation("Relational:ColumnName", "created_at");
createdAt.AddAnnotation("Relational:DefaultValueSql", "NOW()");
var key = runtimeEntityType.AddKey(
new[] { id });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "fingerprint_corpus_metadata_pkey");
var idx_fingerprint_corpus_tenant = runtimeEntityType.AddIndex(
new[] { tenantId },
name: "idx_fingerprint_corpus_tenant");
var idx_fingerprint_corpus_purl = runtimeEntityType.AddIndex(
new[] { purl, version },
name: "idx_fingerprint_corpus_purl");
var fingerprint_corpus_metadata_unique = runtimeEntityType.AddIndex(
new[] { tenantId, purl, version, algorithm },
name: "fingerprint_corpus_metadata_unique",
unique: true);
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "binaries");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "fingerprint_corpus_metadata");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,207 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class FingerprintMatchEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.Persistence.EfCore.Models.FingerprintMatchEntity",
typeof(FingerprintMatchEntity),
baseEntityType,
propertyCount: 16,
namedIndexCount: 2,
keyCount: 1);
var id = runtimeEntityType.AddProperty(
"Id",
typeof(Guid),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<Id>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: Guid.Empty);
id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
id.AddAnnotation("Relational:ColumnName", "id");
id.AddAnnotation("Relational:DefaultValueSql", "gen_random_uuid()");
var tenantId = runtimeEntityType.AddProperty(
"TenantId",
typeof(string),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("TenantId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<TenantId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
tenantId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
tenantId.AddAnnotation("Relational:ColumnName", "tenant_id");
var scanId = runtimeEntityType.AddProperty(
"ScanId",
typeof(Guid),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("ScanId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<ScanId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: Guid.Empty);
scanId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
scanId.AddAnnotation("Relational:ColumnName", "scan_id");
var matchType = runtimeEntityType.AddProperty(
"MatchType",
typeof(string),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("MatchType", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<MatchType>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
matchType.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
matchType.AddAnnotation("Relational:ColumnName", "match_type");
var binaryKey = runtimeEntityType.AddProperty(
"BinaryKey",
typeof(string),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("BinaryKey", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<BinaryKey>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
binaryKey.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
binaryKey.AddAnnotation("Relational:ColumnName", "binary_key");
var binaryIdentityId = runtimeEntityType.AddProperty(
"BinaryIdentityId",
typeof(Guid?),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("BinaryIdentityId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<BinaryIdentityId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
binaryIdentityId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
binaryIdentityId.AddAnnotation("Relational:ColumnName", "binary_identity_id");
var vulnerablePurl = runtimeEntityType.AddProperty(
"VulnerablePurl",
typeof(string),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("VulnerablePurl", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<VulnerablePurl>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
vulnerablePurl.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
vulnerablePurl.AddAnnotation("Relational:ColumnName", "vulnerable_purl");
var vulnerableVersion = runtimeEntityType.AddProperty(
"VulnerableVersion",
typeof(string),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("VulnerableVersion", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<VulnerableVersion>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
vulnerableVersion.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
vulnerableVersion.AddAnnotation("Relational:ColumnName", "vulnerable_version");
var matchedFingerprintId = runtimeEntityType.AddProperty(
"MatchedFingerprintId",
typeof(Guid?),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("MatchedFingerprintId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<MatchedFingerprintId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
matchedFingerprintId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
matchedFingerprintId.AddAnnotation("Relational:ColumnName", "matched_fingerprint_id");
var matchedFunction = runtimeEntityType.AddProperty(
"MatchedFunction",
typeof(string),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("MatchedFunction", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<MatchedFunction>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
matchedFunction.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
matchedFunction.AddAnnotation("Relational:ColumnName", "matched_function");
var similarity = runtimeEntityType.AddProperty(
"Similarity",
typeof(decimal?),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("Similarity", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<Similarity>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
similarity.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
similarity.AddAnnotation("Relational:ColumnName", "similarity");
var advisoryIds = runtimeEntityType.AddProperty(
"AdvisoryIds",
typeof(string[]),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("AdvisoryIds", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<AdvisoryIds>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
advisoryIds.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
advisoryIds.AddAnnotation("Relational:ColumnName", "advisory_ids");
var reachabilityStatus = runtimeEntityType.AddProperty(
"ReachabilityStatus",
typeof(string),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("ReachabilityStatus", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<ReachabilityStatus>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
reachabilityStatus.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
reachabilityStatus.AddAnnotation("Relational:ColumnName", "reachability_status");
var evidence = runtimeEntityType.AddProperty(
"Evidence",
typeof(string),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("Evidence", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<Evidence>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
evidence.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
evidence.AddAnnotation("Relational:ColumnName", "evidence");
evidence.AddAnnotation("Relational:ColumnType", "jsonb");
var matchedAt = runtimeEntityType.AddProperty(
"MatchedAt",
typeof(DateTime),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("MatchedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<MatchedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
matchedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
matchedAt.AddAnnotation("Relational:ColumnName", "matched_at");
matchedAt.AddAnnotation("Relational:DefaultValueSql", "now()");
var createdAt = runtimeEntityType.AddProperty(
"CreatedAt",
typeof(DateTime),
propertyInfo: typeof(FingerprintMatchEntity).GetProperty("CreatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FingerprintMatchEntity).GetField("<CreatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
createdAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
createdAt.AddAnnotation("Relational:ColumnName", "created_at");
createdAt.AddAnnotation("Relational:DefaultValueSql", "NOW()");
var key = runtimeEntityType.AddKey(
new[] { id });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "fingerprint_matches_pkey");
var idx_match_scan = runtimeEntityType.AddIndex(
new[] { tenantId, scanId },
name: "idx_match_scan");
var idx_match_fingerprint = runtimeEntityType.AddIndex(
new[] { matchedFingerprintId },
name: "idx_match_fingerprint");
var idx_match_binary = runtimeEntityType.AddIndex(
new[] { tenantId, binaryKey },
name: "idx_match_binary");
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "binaries");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "fingerprint_matches");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,138 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class FixEvidenceEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.Persistence.EfCore.Models.FixEvidenceEntity",
typeof(FixEvidenceEntity),
baseEntityType,
propertyCount: 8,
namedIndexCount: 1,
keyCount: 1);
var id = runtimeEntityType.AddProperty(
"Id",
typeof(Guid),
propertyInfo: typeof(FixEvidenceEntity).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FixEvidenceEntity).GetField("<Id>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: Guid.Empty);
id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
id.AddAnnotation("Relational:ColumnName", "id");
id.AddAnnotation("Relational:DefaultValueSql", "gen_random_uuid()");
var tenantId = runtimeEntityType.AddProperty(
"TenantId",
typeof(string),
propertyInfo: typeof(FixEvidenceEntity).GetProperty("TenantId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FixEvidenceEntity).GetField("<TenantId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
tenantId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
tenantId.AddAnnotation("Relational:ColumnName", "tenant_id");
var evidenceType = runtimeEntityType.AddProperty(
"EvidenceType",
typeof(string),
propertyInfo: typeof(FixEvidenceEntity).GetProperty("EvidenceType", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FixEvidenceEntity).GetField("<EvidenceType>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
evidenceType.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
evidenceType.AddAnnotation("Relational:ColumnName", "evidence_type");
var sourceFile = runtimeEntityType.AddProperty(
"SourceFile",
typeof(string),
propertyInfo: typeof(FixEvidenceEntity).GetProperty("SourceFile", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FixEvidenceEntity).GetField("<SourceFile>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
sourceFile.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
sourceFile.AddAnnotation("Relational:ColumnName", "source_file");
var sourceSha256 = runtimeEntityType.AddProperty(
"SourceSha256",
typeof(string),
propertyInfo: typeof(FixEvidenceEntity).GetProperty("SourceSha256", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FixEvidenceEntity).GetField("<SourceSha256>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
sourceSha256.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
sourceSha256.AddAnnotation("Relational:ColumnName", "source_sha256");
var excerpt = runtimeEntityType.AddProperty(
"Excerpt",
typeof(string),
propertyInfo: typeof(FixEvidenceEntity).GetProperty("Excerpt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FixEvidenceEntity).GetField("<Excerpt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
excerpt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
excerpt.AddAnnotation("Relational:ColumnName", "excerpt");
var metadata = runtimeEntityType.AddProperty(
"Metadata",
typeof(string),
propertyInfo: typeof(FixEvidenceEntity).GetProperty("Metadata", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FixEvidenceEntity).GetField("<Metadata>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd);
metadata.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
metadata.AddAnnotation("Relational:ColumnName", "metadata");
metadata.AddAnnotation("Relational:ColumnType", "jsonb");
metadata.AddAnnotation("Relational:DefaultValueSql", "'{}'::jsonb");
var snapshotId = runtimeEntityType.AddProperty(
"SnapshotId",
typeof(Guid?),
propertyInfo: typeof(FixEvidenceEntity).GetProperty("SnapshotId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FixEvidenceEntity).GetField("<SnapshotId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
snapshotId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
snapshotId.AddAnnotation("Relational:ColumnName", "snapshot_id");
var createdAt = runtimeEntityType.AddProperty(
"CreatedAt",
typeof(DateTime),
propertyInfo: typeof(FixEvidenceEntity).GetProperty("CreatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(FixEvidenceEntity).GetField("<CreatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
createdAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
createdAt.AddAnnotation("Relational:ColumnName", "created_at");
createdAt.AddAnnotation("Relational:DefaultValueSql", "now()");
var key = runtimeEntityType.AddKey(
new[] { id });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "fix_evidence_pkey");
var idx_fix_evidence_snapshot = runtimeEntityType.AddIndex(
new[] { tenantId, snapshotId },
name: "idx_fix_evidence_snapshot");
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "binaries");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "fix_evidence");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,160 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class RawDocumentEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.Persistence.EfCore.Models.RawDocumentEntity",
typeof(RawDocumentEntity),
baseEntityType,
propertyCount: 11,
namedIndexCount: 3,
keyCount: 1);
var digest = runtimeEntityType.AddProperty(
"Digest",
typeof(string),
propertyInfo: typeof(RawDocumentEntity).GetProperty("Digest", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(RawDocumentEntity).GetField("<Digest>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
afterSaveBehavior: PropertySaveBehavior.Throw);
digest.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
digest.AddAnnotation("Relational:ColumnName", "digest");
var sourceId = runtimeEntityType.AddProperty(
"SourceId",
typeof(string),
propertyInfo: typeof(RawDocumentEntity).GetProperty("SourceId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(RawDocumentEntity).GetField("<SourceId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
sourceId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
sourceId.AddAnnotation("Relational:ColumnName", "source_id");
var documentUri = runtimeEntityType.AddProperty(
"DocumentUri",
typeof(string),
propertyInfo: typeof(RawDocumentEntity).GetProperty("DocumentUri", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(RawDocumentEntity).GetField("<DocumentUri>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
documentUri.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
documentUri.AddAnnotation("Relational:ColumnName", "document_uri");
var contentType = runtimeEntityType.AddProperty(
"ContentType",
typeof(string),
propertyInfo: typeof(RawDocumentEntity).GetProperty("ContentType", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(RawDocumentEntity).GetField("<ContentType>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
contentType.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
contentType.AddAnnotation("Relational:ColumnName", "content_type");
var contentSize = runtimeEntityType.AddProperty(
"ContentSize",
typeof(long),
propertyInfo: typeof(RawDocumentEntity).GetProperty("ContentSize", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(RawDocumentEntity).GetField("<ContentSize>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: 0L);
contentSize.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
contentSize.AddAnnotation("Relational:ColumnName", "content_size");
var etag = runtimeEntityType.AddProperty(
"Etag",
typeof(string),
propertyInfo: typeof(RawDocumentEntity).GetProperty("Etag", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(RawDocumentEntity).GetField("<Etag>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
etag.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
etag.AddAnnotation("Relational:ColumnName", "etag");
var fetchedAt = runtimeEntityType.AddProperty(
"FetchedAt",
typeof(DateTime),
propertyInfo: typeof(RawDocumentEntity).GetProperty("FetchedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(RawDocumentEntity).GetField("<FetchedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
fetchedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
fetchedAt.AddAnnotation("Relational:ColumnName", "fetched_at");
var recordedAt = runtimeEntityType.AddProperty(
"RecordedAt",
typeof(DateTime),
propertyInfo: typeof(RawDocumentEntity).GetProperty("RecordedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(RawDocumentEntity).GetField("<RecordedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
recordedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
recordedAt.AddAnnotation("Relational:ColumnName", "recorded_at");
recordedAt.AddAnnotation("Relational:DefaultValueSql", "now()");
var status = runtimeEntityType.AddProperty(
"Status",
typeof(string),
propertyInfo: typeof(RawDocumentEntity).GetProperty("Status", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(RawDocumentEntity).GetField("<Status>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
status.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
status.AddAnnotation("Relational:ColumnName", "status");
var payloadId = runtimeEntityType.AddProperty(
"PayloadId",
typeof(Guid?),
propertyInfo: typeof(RawDocumentEntity).GetProperty("PayloadId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(RawDocumentEntity).GetField("<PayloadId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
payloadId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
payloadId.AddAnnotation("Relational:ColumnName", "payload_id");
var metadata = runtimeEntityType.AddProperty(
"Metadata",
typeof(string),
propertyInfo: typeof(RawDocumentEntity).GetProperty("Metadata", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(RawDocumentEntity).GetField("<Metadata>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd);
metadata.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
metadata.AddAnnotation("Relational:ColumnName", "metadata");
metadata.AddAnnotation("Relational:ColumnType", "jsonb");
metadata.AddAnnotation("Relational:DefaultValueSql", "'{}'::jsonb");
var key = runtimeEntityType.AddKey(
new[] { digest });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "raw_documents_pkey");
var idx_raw_documents_source_id = runtimeEntityType.AddIndex(
new[] { sourceId },
name: "idx_raw_documents_source_id");
var idx_raw_documents_status = runtimeEntityType.AddIndex(
new[] { status },
name: "idx_raw_documents_status");
var idx_raw_documents_fetched_at = runtimeEntityType.AddIndex(
new[] { fetchedAt },
name: "idx_raw_documents_fetched_at");
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "groundtruth");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "raw_documents");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,221 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class SecurityPairEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.Persistence.EfCore.Models.SecurityPairEntity",
typeof(SecurityPairEntity),
baseEntityType,
propertyCount: 16,
namedIndexCount: 3,
keyCount: 1);
var pairId = runtimeEntityType.AddProperty(
"PairId",
typeof(Guid),
propertyInfo: typeof(SecurityPairEntity).GetProperty("PairId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<PairId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: Guid.Empty);
pairId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
pairId.AddAnnotation("Relational:ColumnName", "pair_id");
pairId.AddAnnotation("Relational:DefaultValueSql", "gen_random_uuid()");
var cveId = runtimeEntityType.AddProperty(
"CveId",
typeof(string),
propertyInfo: typeof(SecurityPairEntity).GetProperty("CveId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<CveId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
cveId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
cveId.AddAnnotation("Relational:ColumnName", "cve_id");
var packageName = runtimeEntityType.AddProperty(
"PackageName",
typeof(string),
propertyInfo: typeof(SecurityPairEntity).GetProperty("PackageName", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<PackageName>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
packageName.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
packageName.AddAnnotation("Relational:ColumnName", "package_name");
var distro = runtimeEntityType.AddProperty(
"Distro",
typeof(string),
propertyInfo: typeof(SecurityPairEntity).GetProperty("Distro", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<Distro>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
distro.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
distro.AddAnnotation("Relational:ColumnName", "distro");
var distroVersion = runtimeEntityType.AddProperty(
"DistroVersion",
typeof(string),
propertyInfo: typeof(SecurityPairEntity).GetProperty("DistroVersion", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<DistroVersion>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
distroVersion.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
distroVersion.AddAnnotation("Relational:ColumnName", "distro_version");
var vulnerableVersion = runtimeEntityType.AddProperty(
"VulnerableVersion",
typeof(string),
propertyInfo: typeof(SecurityPairEntity).GetProperty("VulnerableVersion", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<VulnerableVersion>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
vulnerableVersion.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
vulnerableVersion.AddAnnotation("Relational:ColumnName", "vulnerable_version");
var vulnerableDebugId = runtimeEntityType.AddProperty(
"VulnerableDebugId",
typeof(string),
propertyInfo: typeof(SecurityPairEntity).GetProperty("VulnerableDebugId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<VulnerableDebugId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
vulnerableDebugId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
vulnerableDebugId.AddAnnotation("Relational:ColumnName", "vulnerable_debug_id");
var vulnerableObservationId = runtimeEntityType.AddProperty(
"VulnerableObservationId",
typeof(string),
propertyInfo: typeof(SecurityPairEntity).GetProperty("VulnerableObservationId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<VulnerableObservationId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
vulnerableObservationId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
vulnerableObservationId.AddAnnotation("Relational:ColumnName", "vulnerable_observation_id");
var fixedVersion = runtimeEntityType.AddProperty(
"FixedVersion",
typeof(string),
propertyInfo: typeof(SecurityPairEntity).GetProperty("FixedVersion", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<FixedVersion>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
fixedVersion.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
fixedVersion.AddAnnotation("Relational:ColumnName", "fixed_version");
var fixedDebugId = runtimeEntityType.AddProperty(
"FixedDebugId",
typeof(string),
propertyInfo: typeof(SecurityPairEntity).GetProperty("FixedDebugId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<FixedDebugId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
fixedDebugId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
fixedDebugId.AddAnnotation("Relational:ColumnName", "fixed_debug_id");
var fixedObservationId = runtimeEntityType.AddProperty(
"FixedObservationId",
typeof(string),
propertyInfo: typeof(SecurityPairEntity).GetProperty("FixedObservationId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<FixedObservationId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
fixedObservationId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
fixedObservationId.AddAnnotation("Relational:ColumnName", "fixed_observation_id");
var upstreamDiffUrl = runtimeEntityType.AddProperty(
"UpstreamDiffUrl",
typeof(string),
propertyInfo: typeof(SecurityPairEntity).GetProperty("UpstreamDiffUrl", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<UpstreamDiffUrl>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
upstreamDiffUrl.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
upstreamDiffUrl.AddAnnotation("Relational:ColumnName", "upstream_diff_url");
var patchFunctions = runtimeEntityType.AddProperty(
"PatchFunctions",
typeof(string[]),
propertyInfo: typeof(SecurityPairEntity).GetProperty("PatchFunctions", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<PatchFunctions>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
patchFunctions.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
patchFunctions.AddAnnotation("Relational:ColumnName", "patch_functions");
var verificationStatus = runtimeEntityType.AddProperty(
"VerificationStatus",
typeof(string),
propertyInfo: typeof(SecurityPairEntity).GetProperty("VerificationStatus", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<VerificationStatus>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
verificationStatus.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
verificationStatus.AddAnnotation("Relational:ColumnName", "verification_status");
var metadata = runtimeEntityType.AddProperty(
"Metadata",
typeof(string),
propertyInfo: typeof(SecurityPairEntity).GetProperty("Metadata", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<Metadata>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd);
metadata.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
metadata.AddAnnotation("Relational:ColumnName", "metadata");
metadata.AddAnnotation("Relational:ColumnType", "jsonb");
metadata.AddAnnotation("Relational:DefaultValueSql", "'{}'::jsonb");
var createdAt = runtimeEntityType.AddProperty(
"CreatedAt",
typeof(DateTime),
propertyInfo: typeof(SecurityPairEntity).GetProperty("CreatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<CreatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
createdAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
createdAt.AddAnnotation("Relational:ColumnName", "created_at");
createdAt.AddAnnotation("Relational:DefaultValueSql", "now()");
var updatedAt = runtimeEntityType.AddProperty(
"UpdatedAt",
typeof(DateTime),
propertyInfo: typeof(SecurityPairEntity).GetProperty("UpdatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SecurityPairEntity).GetField("<UpdatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
updatedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
updatedAt.AddAnnotation("Relational:ColumnName", "updated_at");
updatedAt.AddAnnotation("Relational:DefaultValueSql", "now()");
var key = runtimeEntityType.AddKey(
new[] { pairId });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "security_pairs_pkey");
var idx_security_pairs_cve_id = runtimeEntityType.AddIndex(
new[] { cveId },
name: "idx_security_pairs_cve_id");
var idx_security_pairs_package = runtimeEntityType.AddIndex(
new[] { packageName, distro },
name: "idx_security_pairs_package");
var idx_security_pairs_status = runtimeEntityType.AddIndex(
new[] { verificationStatus },
name: "idx_security_pairs_status");
var uq_security_pair = runtimeEntityType.AddIndex(
new[] { cveId, packageName, distro, vulnerableVersion, fixedVersion },
name: "uq_security_pair",
unique: true);
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "groundtruth");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "security_pairs");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,132 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class SourceStateEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.Persistence.EfCore.Models.SourceStateEntity",
typeof(SourceStateEntity),
baseEntityType,
propertyCount: 8,
namedIndexCount: 0,
keyCount: 1);
var sourceId = runtimeEntityType.AddProperty(
"SourceId",
typeof(string),
propertyInfo: typeof(SourceStateEntity).GetProperty("SourceId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SourceStateEntity).GetField("<SourceId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
afterSaveBehavior: PropertySaveBehavior.Throw);
sourceId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
sourceId.AddAnnotation("Relational:ColumnName", "source_id");
var lastSyncAt = runtimeEntityType.AddProperty(
"LastSyncAt",
typeof(DateTime?),
propertyInfo: typeof(SourceStateEntity).GetProperty("LastSyncAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SourceStateEntity).GetField("<LastSyncAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
lastSyncAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
lastSyncAt.AddAnnotation("Relational:ColumnName", "last_sync_at");
var cursorPosition = runtimeEntityType.AddProperty(
"CursorPosition",
typeof(string),
propertyInfo: typeof(SourceStateEntity).GetProperty("CursorPosition", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SourceStateEntity).GetField("<CursorPosition>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
cursorPosition.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
cursorPosition.AddAnnotation("Relational:ColumnName", "cursor_position");
var cursorMetadata = runtimeEntityType.AddProperty(
"CursorMetadata",
typeof(string),
propertyInfo: typeof(SourceStateEntity).GetProperty("CursorMetadata", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SourceStateEntity).GetField("<CursorMetadata>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
cursorMetadata.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
cursorMetadata.AddAnnotation("Relational:ColumnName", "cursor_metadata");
cursorMetadata.AddAnnotation("Relational:ColumnType", "jsonb");
var syncStatus = runtimeEntityType.AddProperty(
"SyncStatus",
typeof(string),
propertyInfo: typeof(SourceStateEntity).GetProperty("SyncStatus", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SourceStateEntity).GetField("<SyncStatus>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
syncStatus.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
syncStatus.AddAnnotation("Relational:ColumnName", "sync_status");
var lastError = runtimeEntityType.AddProperty(
"LastError",
typeof(string),
propertyInfo: typeof(SourceStateEntity).GetProperty("LastError", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SourceStateEntity).GetField("<LastError>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
lastError.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
lastError.AddAnnotation("Relational:ColumnName", "last_error");
var documentCount = runtimeEntityType.AddProperty(
"DocumentCount",
typeof(long),
propertyInfo: typeof(SourceStateEntity).GetProperty("DocumentCount", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SourceStateEntity).GetField("<DocumentCount>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: 0L);
documentCount.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
documentCount.AddAnnotation("Relational:ColumnName", "document_count");
var observationCount = runtimeEntityType.AddProperty(
"ObservationCount",
typeof(long),
propertyInfo: typeof(SourceStateEntity).GetProperty("ObservationCount", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SourceStateEntity).GetField("<ObservationCount>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: 0L);
observationCount.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
observationCount.AddAnnotation("Relational:ColumnName", "observation_count");
var updatedAt = runtimeEntityType.AddProperty(
"UpdatedAt",
typeof(DateTime),
propertyInfo: typeof(SourceStateEntity).GetProperty("UpdatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SourceStateEntity).GetField("<UpdatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
updatedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
updatedAt.AddAnnotation("Relational:ColumnName", "updated_at");
updatedAt.AddAnnotation("Relational:DefaultValueSql", "now()");
var key = runtimeEntityType.AddKey(
new[] { sourceId });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "source_state_pkey");
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "groundtruth");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "source_state");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,238 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class SymbolObservationEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.Persistence.EfCore.Models.SymbolObservationEntity",
typeof(SymbolObservationEntity),
baseEntityType,
propertyCount: 18,
namedIndexCount: 6,
keyCount: 1);
var observationId = runtimeEntityType.AddProperty(
"ObservationId",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("ObservationId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<ObservationId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
afterSaveBehavior: PropertySaveBehavior.Throw);
observationId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
observationId.AddAnnotation("Relational:ColumnName", "observation_id");
var sourceId = runtimeEntityType.AddProperty(
"SourceId",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("SourceId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<SourceId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
sourceId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
sourceId.AddAnnotation("Relational:ColumnName", "source_id");
var debugId = runtimeEntityType.AddProperty(
"DebugId",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("DebugId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<DebugId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
debugId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
debugId.AddAnnotation("Relational:ColumnName", "debug_id");
var codeId = runtimeEntityType.AddProperty(
"CodeId",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("CodeId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<CodeId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
codeId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
codeId.AddAnnotation("Relational:ColumnName", "code_id");
var binaryName = runtimeEntityType.AddProperty(
"BinaryName",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("BinaryName", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<BinaryName>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
binaryName.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
binaryName.AddAnnotation("Relational:ColumnName", "binary_name");
var binaryPath = runtimeEntityType.AddProperty(
"BinaryPath",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("BinaryPath", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<BinaryPath>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
binaryPath.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
binaryPath.AddAnnotation("Relational:ColumnName", "binary_path");
var architecture = runtimeEntityType.AddProperty(
"Architecture",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("Architecture", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<Architecture>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
architecture.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
architecture.AddAnnotation("Relational:ColumnName", "architecture");
var distro = runtimeEntityType.AddProperty(
"Distro",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("Distro", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<Distro>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
distro.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
distro.AddAnnotation("Relational:ColumnName", "distro");
var distroVersion = runtimeEntityType.AddProperty(
"DistroVersion",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("DistroVersion", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<DistroVersion>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
distroVersion.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
distroVersion.AddAnnotation("Relational:ColumnName", "distro_version");
var packageName = runtimeEntityType.AddProperty(
"PackageName",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("PackageName", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<PackageName>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
packageName.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
packageName.AddAnnotation("Relational:ColumnName", "package_name");
var packageVersion = runtimeEntityType.AddProperty(
"PackageVersion",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("PackageVersion", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<PackageVersion>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
packageVersion.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
packageVersion.AddAnnotation("Relational:ColumnName", "package_version");
var symbolCount = runtimeEntityType.AddProperty(
"SymbolCount",
typeof(int),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("SymbolCount", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<SymbolCount>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: 0);
symbolCount.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
symbolCount.AddAnnotation("Relational:ColumnName", "symbol_count");
var symbols = runtimeEntityType.AddProperty(
"Symbols",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("Symbols", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<Symbols>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
symbols.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
symbols.AddAnnotation("Relational:ColumnName", "symbols");
symbols.AddAnnotation("Relational:ColumnType", "jsonb");
var buildMetadata = runtimeEntityType.AddProperty(
"BuildMetadata",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("BuildMetadata", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<BuildMetadata>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
buildMetadata.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
buildMetadata.AddAnnotation("Relational:ColumnName", "build_metadata");
buildMetadata.AddAnnotation("Relational:ColumnType", "jsonb");
var provenance = runtimeEntityType.AddProperty(
"Provenance",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("Provenance", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<Provenance>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
provenance.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
provenance.AddAnnotation("Relational:ColumnName", "provenance");
provenance.AddAnnotation("Relational:ColumnType", "jsonb");
var contentHash = runtimeEntityType.AddProperty(
"ContentHash",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("ContentHash", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<ContentHash>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
contentHash.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
contentHash.AddAnnotation("Relational:ColumnName", "content_hash");
var supersedesId = runtimeEntityType.AddProperty(
"SupersedesId",
typeof(string),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("SupersedesId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<SupersedesId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
supersedesId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
supersedesId.AddAnnotation("Relational:ColumnName", "supersedes_id");
var createdAt = runtimeEntityType.AddProperty(
"CreatedAt",
typeof(DateTime),
propertyInfo: typeof(SymbolObservationEntity).GetProperty("CreatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolObservationEntity).GetField("<CreatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
createdAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
createdAt.AddAnnotation("Relational:ColumnName", "created_at");
createdAt.AddAnnotation("Relational:DefaultValueSql", "now()");
var key = runtimeEntityType.AddKey(
new[] { observationId });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "symbol_observations_pkey");
var idx_symbol_observations_debug_id = runtimeEntityType.AddIndex(
new[] { debugId },
name: "idx_symbol_observations_debug_id");
var idx_symbol_observations_source_id = runtimeEntityType.AddIndex(
new[] { sourceId },
name: "idx_symbol_observations_source_id");
var idx_symbol_observations_binary_name = runtimeEntityType.AddIndex(
new[] { binaryName },
name: "idx_symbol_observations_binary_name");
var idx_symbol_observations_package = runtimeEntityType.AddIndex(
new[] { packageName, packageVersion },
name: "idx_symbol_observations_package");
var idx_symbol_observations_distro = runtimeEntityType.AddIndex(
new[] { distro, distroVersion },
name: "idx_symbol_observations_distro");
var idx_symbol_observations_created_at = runtimeEntityType.AddIndex(
new[] { createdAt },
name: "idx_symbol_observations_created_at");
var uq_content_hash = runtimeEntityType.AddIndex(
new[] { contentHash },
name: "uq_content_hash",
unique: true);
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "groundtruth");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "symbol_observations");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,131 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class SymbolSourceEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.Persistence.EfCore.Models.SymbolSourceEntity",
typeof(SymbolSourceEntity),
baseEntityType,
propertyCount: 9,
namedIndexCount: 0,
keyCount: 1);
var sourceId = runtimeEntityType.AddProperty(
"SourceId",
typeof(string),
propertyInfo: typeof(SymbolSourceEntity).GetProperty("SourceId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolSourceEntity).GetField("<SourceId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
afterSaveBehavior: PropertySaveBehavior.Throw);
sourceId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
sourceId.AddAnnotation("Relational:ColumnName", "source_id");
var displayName = runtimeEntityType.AddProperty(
"DisplayName",
typeof(string),
propertyInfo: typeof(SymbolSourceEntity).GetProperty("DisplayName", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolSourceEntity).GetField("<DisplayName>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
displayName.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
displayName.AddAnnotation("Relational:ColumnName", "display_name");
var sourceType = runtimeEntityType.AddProperty(
"SourceType",
typeof(string),
propertyInfo: typeof(SymbolSourceEntity).GetProperty("SourceType", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolSourceEntity).GetField("<SourceType>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
sourceType.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
sourceType.AddAnnotation("Relational:ColumnName", "source_type");
var baseUrl = runtimeEntityType.AddProperty(
"BaseUrl",
typeof(string),
propertyInfo: typeof(SymbolSourceEntity).GetProperty("BaseUrl", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolSourceEntity).GetField("<BaseUrl>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
baseUrl.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
baseUrl.AddAnnotation("Relational:ColumnName", "base_url");
var supportedDistros = runtimeEntityType.AddProperty(
"SupportedDistros",
typeof(string[]),
propertyInfo: typeof(SymbolSourceEntity).GetProperty("SupportedDistros", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolSourceEntity).GetField("<SupportedDistros>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
supportedDistros.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
supportedDistros.AddAnnotation("Relational:ColumnName", "supported_distros");
var isEnabled = runtimeEntityType.AddProperty(
"IsEnabled",
typeof(bool),
propertyInfo: typeof(SymbolSourceEntity).GetProperty("IsEnabled", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolSourceEntity).GetField("<IsEnabled>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
sentinel: false);
isEnabled.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
isEnabled.AddAnnotation("Relational:ColumnName", "is_enabled");
var configJson = runtimeEntityType.AddProperty(
"ConfigJson",
typeof(string),
propertyInfo: typeof(SymbolSourceEntity).GetProperty("ConfigJson", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolSourceEntity).GetField("<ConfigJson>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
configJson.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
configJson.AddAnnotation("Relational:ColumnName", "config_json");
configJson.AddAnnotation("Relational:ColumnType", "jsonb");
var createdAt = runtimeEntityType.AddProperty(
"CreatedAt",
typeof(DateTime),
propertyInfo: typeof(SymbolSourceEntity).GetProperty("CreatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolSourceEntity).GetField("<CreatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
createdAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
createdAt.AddAnnotation("Relational:ColumnName", "created_at");
createdAt.AddAnnotation("Relational:DefaultValueSql", "now()");
var updatedAt = runtimeEntityType.AddProperty(
"UpdatedAt",
typeof(DateTime),
propertyInfo: typeof(SymbolSourceEntity).GetProperty("UpdatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(SymbolSourceEntity).GetField("<UpdatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
updatedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
updatedAt.AddAnnotation("Relational:ColumnName", "updated_at");
updatedAt.AddAnnotation("Relational:DefaultValueSql", "now()");
var key = runtimeEntityType.AddKey(
new[] { sourceId });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "symbol_sources_pkey");
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "groundtruth");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "symbol_sources");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,264 @@
// <auto-generated />
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
#pragma warning disable 219, 612, 618
#nullable disable
namespace StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels
{
[EntityFrameworkInternal]
public partial class VulnerableFingerprintEntityType
{
public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
{
var runtimeEntityType = model.AddEntityType(
"StellaOps.BinaryIndex.Persistence.EfCore.Models.VulnerableFingerprintEntity",
typeof(VulnerableFingerprintEntity),
baseEntityType,
propertyCount: 21,
namedIndexCount: 3,
keyCount: 1);
var id = runtimeEntityType.AddProperty(
"Id",
typeof(Guid),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<Id>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: Guid.Empty);
id.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
id.AddAnnotation("Relational:ColumnName", "id");
id.AddAnnotation("Relational:DefaultValueSql", "gen_random_uuid()");
var tenantId = runtimeEntityType.AddProperty(
"TenantId",
typeof(string),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("TenantId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<TenantId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
tenantId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
tenantId.AddAnnotation("Relational:ColumnName", "tenant_id");
var cveId = runtimeEntityType.AddProperty(
"CveId",
typeof(string),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("CveId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<CveId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
cveId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
cveId.AddAnnotation("Relational:ColumnName", "cve_id");
var component = runtimeEntityType.AddProperty(
"Component",
typeof(string),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("Component", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<Component>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
component.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
component.AddAnnotation("Relational:ColumnName", "component");
var purl = runtimeEntityType.AddProperty(
"Purl",
typeof(string),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("Purl", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<Purl>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
purl.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
purl.AddAnnotation("Relational:ColumnName", "purl");
var algorithm = runtimeEntityType.AddProperty(
"Algorithm",
typeof(string),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("Algorithm", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<Algorithm>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
algorithm.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
algorithm.AddAnnotation("Relational:ColumnName", "algorithm");
var fingerprintId = runtimeEntityType.AddProperty(
"FingerprintId",
typeof(string),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("FingerprintId", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<FingerprintId>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
fingerprintId.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
fingerprintId.AddAnnotation("Relational:ColumnName", "fingerprint_id");
var fingerprintHash = runtimeEntityType.AddProperty(
"FingerprintHash",
typeof(byte[]),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("FingerprintHash", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<FingerprintHash>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
fingerprintHash.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
fingerprintHash.AddAnnotation("Relational:ColumnName", "fingerprint_hash");
var architecture = runtimeEntityType.AddProperty(
"Architecture",
typeof(string),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("Architecture", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<Architecture>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly));
architecture.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
architecture.AddAnnotation("Relational:ColumnName", "architecture");
var functionName = runtimeEntityType.AddProperty(
"FunctionName",
typeof(string),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("FunctionName", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<FunctionName>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
functionName.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
functionName.AddAnnotation("Relational:ColumnName", "function_name");
var sourceFile = runtimeEntityType.AddProperty(
"SourceFile",
typeof(string),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("SourceFile", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<SourceFile>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
sourceFile.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
sourceFile.AddAnnotation("Relational:ColumnName", "source_file");
var sourceLine = runtimeEntityType.AddProperty(
"SourceLine",
typeof(int?),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("SourceLine", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<SourceLine>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
sourceLine.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
sourceLine.AddAnnotation("Relational:ColumnName", "source_line");
var similarityThreshold = runtimeEntityType.AddProperty(
"SimilarityThreshold",
typeof(decimal?),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("SimilarityThreshold", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<SimilarityThreshold>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
similarityThreshold.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
similarityThreshold.AddAnnotation("Relational:ColumnName", "similarity_threshold");
var confidence = runtimeEntityType.AddProperty(
"Confidence",
typeof(decimal?),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("Confidence", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<Confidence>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
confidence.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
confidence.AddAnnotation("Relational:ColumnName", "confidence");
var validated = runtimeEntityType.AddProperty(
"Validated",
typeof(bool?),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("Validated", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<Validated>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
validated.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
validated.AddAnnotation("Relational:ColumnName", "validated");
var validationStats = runtimeEntityType.AddProperty(
"ValidationStats",
typeof(string),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("ValidationStats", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<ValidationStats>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
validationStats.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
validationStats.AddAnnotation("Relational:ColumnName", "validation_stats");
validationStats.AddAnnotation("Relational:ColumnType", "jsonb");
var vulnBuildRef = runtimeEntityType.AddProperty(
"VulnBuildRef",
typeof(string),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("VulnBuildRef", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<VulnBuildRef>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
vulnBuildRef.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
vulnBuildRef.AddAnnotation("Relational:ColumnName", "vuln_build_ref");
var fixedBuildRef = runtimeEntityType.AddProperty(
"FixedBuildRef",
typeof(string),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("FixedBuildRef", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<FixedBuildRef>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
fixedBuildRef.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
fixedBuildRef.AddAnnotation("Relational:ColumnName", "fixed_build_ref");
var notes = runtimeEntityType.AddProperty(
"Notes",
typeof(string),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("Notes", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<Notes>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
notes.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
notes.AddAnnotation("Relational:ColumnName", "notes");
var evidenceRef = runtimeEntityType.AddProperty(
"EvidenceRef",
typeof(string),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("EvidenceRef", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<EvidenceRef>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
nullable: true);
evidenceRef.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
evidenceRef.AddAnnotation("Relational:ColumnName", "evidence_ref");
var indexedAt = runtimeEntityType.AddProperty(
"IndexedAt",
typeof(DateTime),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("IndexedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<IndexedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
indexedAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
indexedAt.AddAnnotation("Relational:ColumnName", "indexed_at");
indexedAt.AddAnnotation("Relational:DefaultValueSql", "now()");
var createdAt = runtimeEntityType.AddProperty(
"CreatedAt",
typeof(DateTime),
propertyInfo: typeof(VulnerableFingerprintEntity).GetProperty("CreatedAt", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(VulnerableFingerprintEntity).GetField("<CreatedAt>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
createdAt.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);
createdAt.AddAnnotation("Relational:ColumnName", "created_at");
createdAt.AddAnnotation("Relational:DefaultValueSql", "NOW()");
var key = runtimeEntityType.AddKey(
new[] { id });
runtimeEntityType.SetPrimaryKey(key);
key.AddAnnotation("Relational:Name", "vulnerable_fingerprints_pkey");
var idx_fingerprint_cve = runtimeEntityType.AddIndex(
new[] { tenantId, cveId },
name: "idx_fingerprint_cve");
var idx_fingerprint_component = runtimeEntityType.AddIndex(
new[] { tenantId, component },
name: "idx_fingerprint_component");
var idx_fingerprint_algorithm = runtimeEntityType.AddIndex(
new[] { tenantId, algorithm, architecture },
name: "idx_fingerprint_algorithm");
var vulnerable_fingerprints_unique = runtimeEntityType.AddIndex(
new[] { tenantId, fingerprintId },
name: "vulnerable_fingerprints_unique",
unique: true);
return runtimeEntityType;
}
public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
{
runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
runtimeEntityType.AddAnnotation("Relational:Schema", "binaries");
runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
runtimeEntityType.AddAnnotation("Relational:TableName", "vulnerable_fingerprints");
runtimeEntityType.AddAnnotation("Relational:ViewName", null);
runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);
Customize(runtimeEntityType);
}
static partial void Customize(RuntimeEntityType runtimeEntityType);
}
}

View File

@@ -0,0 +1,489 @@
using Microsoft.EntityFrameworkCore;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
namespace StellaOps.BinaryIndex.Persistence.EfCore.Context;
/// <summary>
/// EF Core DbContext for the BinaryIndex Persistence module.
/// Covers tables in the binaries and groundtruth schemas.
/// </summary>
public partial class BinaryIndexPersistenceDbContext : DbContext
{
private readonly string _binariesSchema;
private readonly string _groundtruthSchema;
public BinaryIndexPersistenceDbContext(
DbContextOptions<BinaryIndexPersistenceDbContext> options,
string? binariesSchema = null,
string? groundtruthSchema = null)
: base(options)
{
_binariesSchema = string.IsNullOrWhiteSpace(binariesSchema) ? "binaries" : binariesSchema.Trim();
_groundtruthSchema = string.IsNullOrWhiteSpace(groundtruthSchema) ? "groundtruth" : groundtruthSchema.Trim();
}
// --- binaries schema ---
public virtual DbSet<BinaryIdentityEntity> BinaryIdentities { get; set; }
public virtual DbSet<CorpusSnapshotEntity> CorpusSnapshots { get; set; }
public virtual DbSet<BinaryVulnAssertionEntity> BinaryVulnAssertions { get; set; }
public virtual DbSet<DeltaSignatureDbEntity> DeltaSignatures { get; set; }
public virtual DbSet<DeltaSigMatchDbEntity> DeltaSigMatches { get; set; }
public virtual DbSet<VulnerableFingerprintEntity> VulnerableFingerprints { get; set; }
public virtual DbSet<FingerprintMatchEntity> FingerprintMatches { get; set; }
public virtual DbSet<FingerprintCorpusMetadataEntity> FingerprintCorpusMetadata { get; set; }
public virtual DbSet<CveFixIndexEntity> CveFixIndexes { get; set; }
public virtual DbSet<FixEvidenceEntity> FixEvidences { get; set; }
// --- groundtruth schema ---
public virtual DbSet<SymbolSourceEntity> SymbolSources { get; set; }
public virtual DbSet<SourceStateEntity> SourceStates { get; set; }
public virtual DbSet<RawDocumentEntity> RawDocuments { get; set; }
public virtual DbSet<SymbolObservationEntity> SymbolObservations { get; set; }
public virtual DbSet<SecurityPairEntity> SecurityPairs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var binaries = _binariesSchema;
var groundtruth = _groundtruthSchema;
// =====================================================================
// binaries.binary_identity
// =====================================================================
modelBuilder.Entity<BinaryIdentityEntity>(entity =>
{
entity.HasKey(e => e.Id).HasName("binary_identity_pkey");
entity.ToTable("binary_identity", binaries);
entity.HasIndex(e => e.TenantId, "idx_binary_identity_tenant");
entity.HasIndex(e => e.BuildId, "idx_binary_identity_buildid")
.HasFilter("(build_id IS NOT NULL)");
entity.HasIndex(e => e.FileSha256, "idx_binary_identity_sha256");
entity.HasIndex(e => e.BinaryKey, "idx_binary_identity_key");
entity.HasIndex(e => new { e.TenantId, e.BinaryKey }, "binary_identity_key_unique").IsUnique();
entity.Property(e => e.Id).HasDefaultValueSql("gen_random_uuid()").HasColumnName("id");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.BinaryKey).HasColumnName("binary_key");
entity.Property(e => e.BuildId).HasColumnName("build_id");
entity.Property(e => e.BuildIdType).HasColumnName("build_id_type");
entity.Property(e => e.FileSha256).HasColumnName("file_sha256");
entity.Property(e => e.TextSha256).HasColumnName("text_sha256");
entity.Property(e => e.Blake3Hash).HasColumnName("blake3_hash");
entity.Property(e => e.Format).HasColumnName("format");
entity.Property(e => e.Architecture).HasColumnName("architecture");
entity.Property(e => e.Osabi).HasColumnName("osabi");
entity.Property(e => e.BinaryType).HasColumnName("binary_type");
entity.Property(e => e.IsStripped).HasColumnName("is_stripped");
entity.Property(e => e.FirstSeenSnapshotId).HasColumnName("first_seen_snapshot_id");
entity.Property(e => e.LastSeenSnapshotId).HasColumnName("last_seen_snapshot_id");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("NOW()").HasColumnName("created_at");
entity.Property(e => e.UpdatedAt).HasDefaultValueSql("NOW()").HasColumnName("updated_at");
});
// =====================================================================
// binaries.corpus_snapshots
// =====================================================================
modelBuilder.Entity<CorpusSnapshotEntity>(entity =>
{
entity.HasKey(e => e.Id).HasName("corpus_snapshots_pkey");
entity.ToTable("corpus_snapshots", binaries);
entity.HasIndex(e => e.TenantId, "idx_corpus_snapshots_tenant");
entity.HasIndex(e => new { e.Distro, e.Release, e.Architecture }, "idx_corpus_snapshots_distro");
entity.HasIndex(e => new { e.TenantId, e.Distro, e.Release, e.Architecture, e.SnapshotId }, "corpus_snapshots_unique").IsUnique();
entity.Property(e => e.Id).HasDefaultValueSql("gen_random_uuid()").HasColumnName("id");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.Distro).HasColumnName("distro");
entity.Property(e => e.Release).HasColumnName("release");
entity.Property(e => e.Architecture).HasColumnName("architecture");
entity.Property(e => e.SnapshotId).HasColumnName("snapshot_id");
entity.Property(e => e.PackagesProcessed).HasColumnName("packages_processed");
entity.Property(e => e.BinariesIndexed).HasColumnName("binaries_indexed");
entity.Property(e => e.RepoMetadataDigest).HasColumnName("repo_metadata_digest");
entity.Property(e => e.SigningKeyId).HasColumnName("signing_key_id");
entity.Property(e => e.DsseEnvelopeRef).HasColumnName("dsse_envelope_ref");
entity.Property(e => e.Status).HasColumnName("status");
entity.Property(e => e.Error).HasColumnName("error");
entity.Property(e => e.StartedAt).HasColumnName("started_at");
entity.Property(e => e.CompletedAt).HasColumnName("completed_at");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("NOW()").HasColumnName("created_at");
});
// =====================================================================
// binaries.binary_vuln_assertion
// =====================================================================
modelBuilder.Entity<BinaryVulnAssertionEntity>(entity =>
{
entity.HasKey(e => e.Id).HasName("binary_vuln_assertion_pkey");
entity.ToTable("binary_vuln_assertion", binaries);
entity.HasIndex(e => e.TenantId, "idx_binary_vuln_assertion_tenant");
entity.HasIndex(e => e.BinaryKey, "idx_binary_vuln_assertion_binary");
entity.HasIndex(e => e.CveId, "idx_binary_vuln_assertion_cve");
entity.HasIndex(e => new { e.TenantId, e.BinaryKey, e.CveId }, "binary_vuln_assertion_unique").IsUnique();
entity.Property(e => e.Id).HasDefaultValueSql("gen_random_uuid()").HasColumnName("id");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.BinaryKey).HasColumnName("binary_key");
entity.Property(e => e.BinaryIdentityId).HasColumnName("binary_identity_id");
entity.Property(e => e.CveId).HasColumnName("cve_id");
entity.Property(e => e.AdvisoryId).HasColumnName("advisory_id");
entity.Property(e => e.Status).HasColumnName("status");
entity.Property(e => e.Method).HasColumnName("method");
entity.Property(e => e.Confidence).HasColumnName("confidence");
entity.Property(e => e.EvidenceRef).HasColumnName("evidence_ref");
entity.Property(e => e.EvidenceDigest).HasColumnName("evidence_digest");
entity.Property(e => e.EvaluatedAt).HasDefaultValueSql("NOW()").HasColumnName("evaluated_at");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("NOW()").HasColumnName("created_at");
});
// =====================================================================
// binaries.delta_signature
// =====================================================================
modelBuilder.Entity<DeltaSignatureDbEntity>(entity =>
{
entity.HasKey(e => e.Id).HasName("delta_signature_pkey");
entity.ToTable("delta_signature", binaries);
entity.HasIndex(e => e.TenantId, "idx_delta_sig_tenant");
entity.HasIndex(e => e.CveId, "idx_delta_sig_cve");
entity.HasIndex(e => new { e.PackageName, e.Soname }, "idx_delta_sig_pkg");
entity.HasIndex(e => e.HashHex, "idx_delta_sig_hash");
entity.HasIndex(e => e.SignatureState, "idx_delta_sig_state");
entity.HasIndex(e => new { e.Arch, e.Abi }, "idx_delta_sig_arch");
entity.Property(e => e.Id).HasDefaultValueSql("gen_random_uuid()").HasColumnName("id");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.CveId).HasMaxLength(20).HasColumnName("cve_id");
entity.Property(e => e.PackageName).HasMaxLength(255).HasColumnName("package_name");
entity.Property(e => e.Soname).HasMaxLength(255).HasColumnName("soname");
entity.Property(e => e.Arch).HasMaxLength(20).HasColumnName("arch");
entity.Property(e => e.Abi).HasMaxLength(20).HasColumnName("abi");
entity.Property(e => e.RecipeId).HasMaxLength(50).HasColumnName("recipe_id");
entity.Property(e => e.RecipeVersion).HasMaxLength(10).HasColumnName("recipe_version");
entity.Property(e => e.SymbolName).HasMaxLength(255).HasColumnName("symbol_name");
entity.Property(e => e.Scope).HasMaxLength(20).HasColumnName("scope");
entity.Property(e => e.HashAlg).HasMaxLength(20).HasColumnName("hash_alg");
entity.Property(e => e.HashHex).HasMaxLength(128).HasColumnName("hash_hex");
entity.Property(e => e.SizeBytes).HasColumnName("size_bytes");
entity.Property(e => e.CfgBbCount).HasColumnName("cfg_bb_count");
entity.Property(e => e.CfgEdgeHash).HasMaxLength(128).HasColumnName("cfg_edge_hash");
entity.Property(e => e.ChunkHashes).HasColumnType("jsonb").HasColumnName("chunk_hashes");
entity.Property(e => e.SignatureState).HasMaxLength(20).HasColumnName("signature_state");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("NOW()").HasColumnName("created_at");
entity.Property(e => e.UpdatedAt).HasDefaultValueSql("NOW()").HasColumnName("updated_at");
entity.Property(e => e.AttestationDsse).HasColumnName("attestation_dsse");
entity.Property(e => e.Metadata).HasColumnType("jsonb").HasColumnName("metadata");
});
// =====================================================================
// binaries.delta_sig_match
// =====================================================================
modelBuilder.Entity<DeltaSigMatchDbEntity>(entity =>
{
entity.HasKey(e => e.Id).HasName("delta_sig_match_pkey");
entity.ToTable("delta_sig_match", binaries);
entity.HasIndex(e => e.TenantId, "idx_delta_match_tenant");
entity.HasIndex(e => e.CveId, "idx_delta_match_cve");
entity.HasIndex(e => e.BinaryKey, "idx_delta_match_binary");
entity.HasIndex(e => e.ScanId, "idx_delta_match_scan");
entity.HasIndex(e => e.MatchedState, "idx_delta_match_state");
entity.Property(e => e.Id).HasDefaultValueSql("gen_random_uuid()").HasColumnName("id");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.BinaryIdentityId).HasColumnName("binary_identity_id");
entity.Property(e => e.BinaryKey).HasColumnName("binary_key");
entity.Property(e => e.BinarySha256).HasMaxLength(64).HasColumnName("binary_sha256");
entity.Property(e => e.SignatureId).HasColumnName("signature_id");
entity.Property(e => e.CveId).HasMaxLength(20).HasColumnName("cve_id");
entity.Property(e => e.SymbolName).HasMaxLength(255).HasColumnName("symbol_name");
entity.Property(e => e.MatchType).HasMaxLength(20).HasColumnName("match_type");
entity.Property(e => e.Confidence).HasColumnName("confidence");
entity.Property(e => e.ChunkMatchRatio).HasColumnName("chunk_match_ratio");
entity.Property(e => e.MatchedState).HasMaxLength(20).HasColumnName("matched_state");
entity.Property(e => e.ScanId).HasColumnName("scan_id");
entity.Property(e => e.ScannedAt).HasDefaultValueSql("NOW()").HasColumnName("scanned_at");
entity.Property(e => e.Explanation).HasColumnName("explanation");
entity.Property(e => e.Metadata).HasColumnType("jsonb").HasColumnName("metadata");
});
// =====================================================================
// binaries.vulnerable_fingerprints
// =====================================================================
modelBuilder.Entity<VulnerableFingerprintEntity>(entity =>
{
entity.HasKey(e => e.Id).HasName("vulnerable_fingerprints_pkey");
entity.ToTable("vulnerable_fingerprints", binaries);
entity.HasIndex(e => new { e.TenantId, e.CveId }, "idx_fingerprint_cve");
entity.HasIndex(e => new { e.TenantId, e.Component }, "idx_fingerprint_component");
entity.HasIndex(e => new { e.TenantId, e.Algorithm, e.Architecture }, "idx_fingerprint_algorithm");
entity.HasIndex(e => new { e.TenantId, e.FingerprintId }, "vulnerable_fingerprints_unique").IsUnique();
entity.Property(e => e.Id).HasDefaultValueSql("gen_random_uuid()").HasColumnName("id");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.CveId).HasColumnName("cve_id");
entity.Property(e => e.Component).HasColumnName("component");
entity.Property(e => e.Purl).HasColumnName("purl");
entity.Property(e => e.Algorithm).HasColumnName("algorithm");
entity.Property(e => e.FingerprintId).HasColumnName("fingerprint_id");
entity.Property(e => e.FingerprintHash).HasColumnName("fingerprint_hash");
entity.Property(e => e.Architecture).HasColumnName("architecture");
entity.Property(e => e.FunctionName).HasColumnName("function_name");
entity.Property(e => e.SourceFile).HasColumnName("source_file");
entity.Property(e => e.SourceLine).HasColumnName("source_line");
entity.Property(e => e.SimilarityThreshold).HasColumnName("similarity_threshold");
entity.Property(e => e.Confidence).HasColumnName("confidence");
entity.Property(e => e.Validated).HasColumnName("validated");
entity.Property(e => e.ValidationStats).HasColumnType("jsonb").HasColumnName("validation_stats");
entity.Property(e => e.VulnBuildRef).HasColumnName("vuln_build_ref");
entity.Property(e => e.FixedBuildRef).HasColumnName("fixed_build_ref");
entity.Property(e => e.Notes).HasColumnName("notes");
entity.Property(e => e.EvidenceRef).HasColumnName("evidence_ref");
entity.Property(e => e.IndexedAt).HasDefaultValueSql("now()").HasColumnName("indexed_at");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("NOW()").HasColumnName("created_at");
});
// =====================================================================
// binaries.fingerprint_matches
// =====================================================================
modelBuilder.Entity<FingerprintMatchEntity>(entity =>
{
entity.HasKey(e => e.Id).HasName("fingerprint_matches_pkey");
entity.ToTable("fingerprint_matches", binaries);
entity.HasIndex(e => new { e.TenantId, e.ScanId }, "idx_match_scan");
entity.HasIndex(e => e.MatchedFingerprintId, "idx_match_fingerprint");
entity.HasIndex(e => new { e.TenantId, e.BinaryKey }, "idx_match_binary");
entity.Property(e => e.Id).HasDefaultValueSql("gen_random_uuid()").HasColumnName("id");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.ScanId).HasColumnName("scan_id");
entity.Property(e => e.MatchType).HasColumnName("match_type");
entity.Property(e => e.BinaryKey).HasColumnName("binary_key");
entity.Property(e => e.BinaryIdentityId).HasColumnName("binary_identity_id");
entity.Property(e => e.VulnerablePurl).HasColumnName("vulnerable_purl");
entity.Property(e => e.VulnerableVersion).HasColumnName("vulnerable_version");
entity.Property(e => e.MatchedFingerprintId).HasColumnName("matched_fingerprint_id");
entity.Property(e => e.MatchedFunction).HasColumnName("matched_function");
entity.Property(e => e.Similarity).HasColumnName("similarity");
entity.Property(e => e.AdvisoryIds).HasColumnName("advisory_ids");
entity.Property(e => e.ReachabilityStatus).HasColumnName("reachability_status");
entity.Property(e => e.Evidence).HasColumnType("jsonb").HasColumnName("evidence");
entity.Property(e => e.MatchedAt).HasDefaultValueSql("now()").HasColumnName("matched_at");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("NOW()").HasColumnName("created_at");
});
// =====================================================================
// binaries.fingerprint_corpus_metadata
// =====================================================================
modelBuilder.Entity<FingerprintCorpusMetadataEntity>(entity =>
{
entity.HasKey(e => e.Id).HasName("fingerprint_corpus_metadata_pkey");
entity.ToTable("fingerprint_corpus_metadata", binaries);
entity.HasIndex(e => e.TenantId, "idx_fingerprint_corpus_tenant");
entity.HasIndex(e => new { e.Purl, e.Version }, "idx_fingerprint_corpus_purl");
entity.HasIndex(e => new { e.TenantId, e.Purl, e.Version, e.Algorithm }, "fingerprint_corpus_metadata_unique").IsUnique();
entity.Property(e => e.Id).HasDefaultValueSql("gen_random_uuid()").HasColumnName("id");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.Purl).HasColumnName("purl");
entity.Property(e => e.Version).HasColumnName("version");
entity.Property(e => e.Algorithm).HasColumnName("algorithm");
entity.Property(e => e.BinaryDigest).HasColumnName("binary_digest");
entity.Property(e => e.FunctionCount).HasColumnName("function_count");
entity.Property(e => e.FingerprintsIndexed).HasColumnName("fingerprints_indexed");
entity.Property(e => e.IndexedBy).HasColumnName("indexed_by");
entity.Property(e => e.IndexedAt).HasDefaultValueSql("NOW()").HasColumnName("indexed_at");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("NOW()").HasColumnName("created_at");
});
// =====================================================================
// binaries.cve_fix_index
// =====================================================================
modelBuilder.Entity<CveFixIndexEntity>(entity =>
{
entity.HasKey(e => e.Id).HasName("cve_fix_index_pkey");
entity.ToTable("cve_fix_index", binaries);
entity.HasIndex(e => new { e.TenantId, e.Distro, e.Release, e.SourcePkg, e.CveId }, "idx_cve_fix_lookup");
entity.HasIndex(e => new { e.TenantId, e.CveId, e.Distro, e.Release }, "idx_cve_fix_by_cve");
entity.HasIndex(e => new { e.TenantId, e.Distro, e.Release, e.SourcePkg, e.CveId, e.Architecture }, "cve_fix_index_unique").IsUnique();
entity.Property(e => e.Id).HasDefaultValueSql("gen_random_uuid()").HasColumnName("id");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.Distro).HasColumnName("distro");
entity.Property(e => e.Release).HasColumnName("release");
entity.Property(e => e.SourcePkg).HasColumnName("source_pkg");
entity.Property(e => e.CveId).HasColumnName("cve_id");
entity.Property(e => e.Architecture).HasColumnName("architecture");
entity.Property(e => e.State).HasColumnName("state");
entity.Property(e => e.FixedVersion).HasColumnName("fixed_version");
entity.Property(e => e.Method).HasColumnName("method");
entity.Property(e => e.Confidence).HasColumnName("confidence");
entity.Property(e => e.EvidenceId).HasColumnName("evidence_id");
entity.Property(e => e.SnapshotId).HasColumnName("snapshot_id");
entity.Property(e => e.IndexedAt).HasDefaultValueSql("now()").HasColumnName("indexed_at");
entity.Property(e => e.UpdatedAt).HasDefaultValueSql("now()").HasColumnName("updated_at");
});
// =====================================================================
// binaries.fix_evidence
// =====================================================================
modelBuilder.Entity<FixEvidenceEntity>(entity =>
{
entity.HasKey(e => e.Id).HasName("fix_evidence_pkey");
entity.ToTable("fix_evidence", binaries);
entity.HasIndex(e => new { e.TenantId, e.SnapshotId }, "idx_fix_evidence_snapshot");
entity.Property(e => e.Id).HasDefaultValueSql("gen_random_uuid()").HasColumnName("id");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.EvidenceType).HasColumnName("evidence_type");
entity.Property(e => e.SourceFile).HasColumnName("source_file");
entity.Property(e => e.SourceSha256).HasColumnName("source_sha256");
entity.Property(e => e.Excerpt).HasColumnName("excerpt");
entity.Property(e => e.Metadata).HasColumnType("jsonb").HasDefaultValueSql("'{}'::jsonb").HasColumnName("metadata");
entity.Property(e => e.SnapshotId).HasColumnName("snapshot_id");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("now()").HasColumnName("created_at");
});
// =====================================================================
// groundtruth.symbol_sources
// =====================================================================
modelBuilder.Entity<SymbolSourceEntity>(entity =>
{
entity.HasKey(e => e.SourceId).HasName("symbol_sources_pkey");
entity.ToTable("symbol_sources", groundtruth);
entity.Property(e => e.SourceId).HasColumnName("source_id");
entity.Property(e => e.DisplayName).HasColumnName("display_name");
entity.Property(e => e.SourceType).HasColumnName("source_type");
entity.Property(e => e.BaseUrl).HasColumnName("base_url");
entity.Property(e => e.SupportedDistros).HasColumnName("supported_distros");
entity.Property(e => e.IsEnabled).HasColumnName("is_enabled");
entity.Property(e => e.ConfigJson).HasColumnType("jsonb").HasColumnName("config_json");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("now()").HasColumnName("created_at");
entity.Property(e => e.UpdatedAt).HasDefaultValueSql("now()").HasColumnName("updated_at");
});
// =====================================================================
// groundtruth.source_state
// =====================================================================
modelBuilder.Entity<SourceStateEntity>(entity =>
{
entity.HasKey(e => e.SourceId).HasName("source_state_pkey");
entity.ToTable("source_state", groundtruth);
entity.Property(e => e.SourceId).HasColumnName("source_id");
entity.Property(e => e.LastSyncAt).HasColumnName("last_sync_at");
entity.Property(e => e.CursorPosition).HasColumnName("cursor_position");
entity.Property(e => e.CursorMetadata).HasColumnType("jsonb").HasColumnName("cursor_metadata");
entity.Property(e => e.SyncStatus).HasColumnName("sync_status");
entity.Property(e => e.LastError).HasColumnName("last_error");
entity.Property(e => e.DocumentCount).HasColumnName("document_count");
entity.Property(e => e.ObservationCount).HasColumnName("observation_count");
entity.Property(e => e.UpdatedAt).HasDefaultValueSql("now()").HasColumnName("updated_at");
});
// =====================================================================
// groundtruth.raw_documents
// =====================================================================
modelBuilder.Entity<RawDocumentEntity>(entity =>
{
entity.HasKey(e => e.Digest).HasName("raw_documents_pkey");
entity.ToTable("raw_documents", groundtruth);
entity.HasIndex(e => e.SourceId, "idx_raw_documents_source_id");
entity.HasIndex(e => e.Status, "idx_raw_documents_status");
entity.HasIndex(e => e.FetchedAt, "idx_raw_documents_fetched_at");
entity.Property(e => e.Digest).HasColumnName("digest");
entity.Property(e => e.SourceId).HasColumnName("source_id");
entity.Property(e => e.DocumentUri).HasColumnName("document_uri");
entity.Property(e => e.ContentType).HasColumnName("content_type");
entity.Property(e => e.ContentSize).HasColumnName("content_size");
entity.Property(e => e.Etag).HasColumnName("etag");
entity.Property(e => e.FetchedAt).HasColumnName("fetched_at");
entity.Property(e => e.RecordedAt).HasDefaultValueSql("now()").HasColumnName("recorded_at");
entity.Property(e => e.Status).HasColumnName("status");
entity.Property(e => e.PayloadId).HasColumnName("payload_id");
entity.Property(e => e.Metadata).HasColumnType("jsonb").HasDefaultValueSql("'{}'::jsonb").HasColumnName("metadata");
});
// =====================================================================
// groundtruth.symbol_observations
// =====================================================================
modelBuilder.Entity<SymbolObservationEntity>(entity =>
{
entity.HasKey(e => e.ObservationId).HasName("symbol_observations_pkey");
entity.ToTable("symbol_observations", groundtruth);
entity.HasIndex(e => e.DebugId, "idx_symbol_observations_debug_id");
entity.HasIndex(e => e.SourceId, "idx_symbol_observations_source_id");
entity.HasIndex(e => e.BinaryName, "idx_symbol_observations_binary_name");
entity.HasIndex(e => new { e.PackageName, e.PackageVersion }, "idx_symbol_observations_package");
entity.HasIndex(e => new { e.Distro, e.DistroVersion }, "idx_symbol_observations_distro");
entity.HasIndex(e => e.CreatedAt, "idx_symbol_observations_created_at");
entity.HasIndex(e => e.ContentHash, "uq_content_hash").IsUnique();
entity.Property(e => e.ObservationId).HasColumnName("observation_id");
entity.Property(e => e.SourceId).HasColumnName("source_id");
entity.Property(e => e.DebugId).HasColumnName("debug_id");
entity.Property(e => e.CodeId).HasColumnName("code_id");
entity.Property(e => e.BinaryName).HasColumnName("binary_name");
entity.Property(e => e.BinaryPath).HasColumnName("binary_path");
entity.Property(e => e.Architecture).HasColumnName("architecture");
entity.Property(e => e.Distro).HasColumnName("distro");
entity.Property(e => e.DistroVersion).HasColumnName("distro_version");
entity.Property(e => e.PackageName).HasColumnName("package_name");
entity.Property(e => e.PackageVersion).HasColumnName("package_version");
entity.Property(e => e.SymbolCount).HasColumnName("symbol_count");
entity.Property(e => e.Symbols).HasColumnType("jsonb").HasColumnName("symbols");
entity.Property(e => e.BuildMetadata).HasColumnType("jsonb").HasColumnName("build_metadata");
entity.Property(e => e.Provenance).HasColumnType("jsonb").HasColumnName("provenance");
entity.Property(e => e.ContentHash).HasColumnName("content_hash");
entity.Property(e => e.SupersedesId).HasColumnName("supersedes_id");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("now()").HasColumnName("created_at");
});
// =====================================================================
// groundtruth.security_pairs
// =====================================================================
modelBuilder.Entity<SecurityPairEntity>(entity =>
{
entity.HasKey(e => e.PairId).HasName("security_pairs_pkey");
entity.ToTable("security_pairs", groundtruth);
entity.HasIndex(e => e.CveId, "idx_security_pairs_cve_id");
entity.HasIndex(e => new { e.PackageName, e.Distro }, "idx_security_pairs_package");
entity.HasIndex(e => e.VerificationStatus, "idx_security_pairs_status");
entity.HasIndex(e => new { e.CveId, e.PackageName, e.Distro, e.VulnerableVersion, e.FixedVersion }, "uq_security_pair").IsUnique();
entity.Property(e => e.PairId).HasDefaultValueSql("gen_random_uuid()").HasColumnName("pair_id");
entity.Property(e => e.CveId).HasColumnName("cve_id");
entity.Property(e => e.PackageName).HasColumnName("package_name");
entity.Property(e => e.Distro).HasColumnName("distro");
entity.Property(e => e.DistroVersion).HasColumnName("distro_version");
entity.Property(e => e.VulnerableVersion).HasColumnName("vulnerable_version");
entity.Property(e => e.VulnerableDebugId).HasColumnName("vulnerable_debug_id");
entity.Property(e => e.VulnerableObservationId).HasColumnName("vulnerable_observation_id");
entity.Property(e => e.FixedVersion).HasColumnName("fixed_version");
entity.Property(e => e.FixedDebugId).HasColumnName("fixed_debug_id");
entity.Property(e => e.FixedObservationId).HasColumnName("fixed_observation_id");
entity.Property(e => e.UpstreamDiffUrl).HasColumnName("upstream_diff_url");
entity.Property(e => e.PatchFunctions).HasColumnName("patch_functions");
entity.Property(e => e.VerificationStatus).HasColumnName("verification_status");
entity.Property(e => e.Metadata).HasColumnType("jsonb").HasDefaultValueSql("'{}'::jsonb").HasColumnName("metadata");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("now()").HasColumnName("created_at");
entity.Property(e => e.UpdatedAt).HasDefaultValueSql("now()").HasColumnName("updated_at");
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

View File

@@ -0,0 +1,32 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
namespace StellaOps.BinaryIndex.Persistence.EfCore.Context;
/// <summary>
/// Design-time factory for EF Core CLI tooling (scaffold, optimize).
/// </summary>
public sealed class BinaryIndexPersistenceDesignTimeDbContextFactory
: IDesignTimeDbContextFactory<BinaryIndexPersistenceDbContext>
{
private const string DefaultConnectionString =
"Host=localhost;Port=55433;Database=postgres;Username=postgres;Password=postgres;Search Path=binaries,groundtruth,public";
private const string ConnectionStringEnvironmentVariable =
"STELLAOPS_BINARYINDEX_EF_CONNECTION";
public BinaryIndexPersistenceDbContext CreateDbContext(string[] args)
{
var connectionString = ResolveConnectionString();
var options = new DbContextOptionsBuilder<BinaryIndexPersistenceDbContext>()
.UseNpgsql(connectionString)
.Options;
return new BinaryIndexPersistenceDbContext(options);
}
private static string ResolveConnectionString()
{
var fromEnvironment = Environment.GetEnvironmentVariable(ConnectionStringEnvironmentVariable);
return string.IsNullOrWhiteSpace(fromEnvironment) ? DefaultConnectionString : fromEnvironment;
}
}

View File

@@ -0,0 +1,25 @@
namespace StellaOps.BinaryIndex.Persistence.EfCore.Models;
/// <summary>
/// EF Core entity for binaries.binary_identity table.
/// </summary>
public partial class BinaryIdentityEntity
{
public Guid Id { get; set; }
public Guid TenantId { get; set; }
public string BinaryKey { get; set; } = null!;
public string? BuildId { get; set; }
public string? BuildIdType { get; set; }
public string FileSha256 { get; set; } = null!;
public string? TextSha256 { get; set; }
public string? Blake3Hash { get; set; }
public string Format { get; set; } = null!;
public string Architecture { get; set; } = null!;
public string? Osabi { get; set; }
public string? BinaryType { get; set; }
public bool? IsStripped { get; set; }
public Guid? FirstSeenSnapshotId { get; set; }
public Guid? LastSeenSnapshotId { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}

View File

@@ -0,0 +1,21 @@
namespace StellaOps.BinaryIndex.Persistence.EfCore.Models;
/// <summary>
/// EF Core entity for binaries.binary_vuln_assertion table.
/// </summary>
public partial class BinaryVulnAssertionEntity
{
public Guid Id { get; set; }
public Guid TenantId { get; set; }
public string BinaryKey { get; set; } = null!;
public Guid? BinaryIdentityId { get; set; }
public string CveId { get; set; } = null!;
public Guid? AdvisoryId { get; set; }
public string Status { get; set; } = null!;
public string Method { get; set; } = null!;
public decimal? Confidence { get; set; }
public string? EvidenceRef { get; set; }
public string? EvidenceDigest { get; set; }
public DateTime EvaluatedAt { get; set; }
public DateTime CreatedAt { get; set; }
}

View File

@@ -0,0 +1,24 @@
namespace StellaOps.BinaryIndex.Persistence.EfCore.Models;
/// <summary>
/// EF Core entity for binaries.corpus_snapshots table.
/// </summary>
public partial class CorpusSnapshotEntity
{
public Guid Id { get; set; }
public Guid TenantId { get; set; }
public string Distro { get; set; } = null!;
public string Release { get; set; } = null!;
public string Architecture { get; set; } = null!;
public string SnapshotId { get; set; } = null!;
public int PackagesProcessed { get; set; }
public int BinariesIndexed { get; set; }
public string? RepoMetadataDigest { get; set; }
public string? SigningKeyId { get; set; }
public string? DsseEnvelopeRef { get; set; }
public string Status { get; set; } = null!;
public string? Error { get; set; }
public DateTime? StartedAt { get; set; }
public DateTime? CompletedAt { get; set; }
public DateTime CreatedAt { get; set; }
}

View File

@@ -0,0 +1,23 @@
namespace StellaOps.BinaryIndex.Persistence.EfCore.Models;
/// <summary>
/// EF Core entity for binaries.cve_fix_index table.
/// </summary>
public partial class CveFixIndexEntity
{
public Guid Id { get; set; }
public string TenantId { get; set; } = null!;
public string Distro { get; set; } = null!;
public string Release { get; set; } = null!;
public string SourcePkg { get; set; } = null!;
public string CveId { get; set; } = null!;
public string? Architecture { get; set; }
public string State { get; set; } = null!;
public string? FixedVersion { get; set; }
public string Method { get; set; } = null!;
public decimal Confidence { get; set; }
public Guid? EvidenceId { get; set; }
public Guid? SnapshotId { get; set; }
public DateTime IndexedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}

View File

@@ -0,0 +1,24 @@
namespace StellaOps.BinaryIndex.Persistence.EfCore.Models;
/// <summary>
/// EF Core entity for binaries.delta_sig_match table.
/// </summary>
public partial class DeltaSigMatchDbEntity
{
public Guid Id { get; set; }
public Guid TenantId { get; set; }
public Guid? BinaryIdentityId { get; set; }
public string BinaryKey { get; set; } = null!;
public string? BinarySha256 { get; set; }
public Guid? SignatureId { get; set; }
public string CveId { get; set; } = null!;
public string SymbolName { get; set; } = null!;
public string MatchType { get; set; } = null!;
public decimal Confidence { get; set; }
public decimal? ChunkMatchRatio { get; set; }
public string MatchedState { get; set; } = null!;
public Guid? ScanId { get; set; }
public DateTime ScannedAt { get; set; }
public string? Explanation { get; set; }
public string? Metadata { get; set; }
}

View File

@@ -0,0 +1,30 @@
namespace StellaOps.BinaryIndex.Persistence.EfCore.Models;
/// <summary>
/// EF Core entity for binaries.delta_signature table.
/// </summary>
public partial class DeltaSignatureDbEntity
{
public Guid Id { get; set; }
public Guid TenantId { get; set; }
public string CveId { get; set; } = null!;
public string PackageName { get; set; } = null!;
public string? Soname { get; set; }
public string Arch { get; set; } = null!;
public string Abi { get; set; } = null!;
public string RecipeId { get; set; } = null!;
public string RecipeVersion { get; set; } = null!;
public string SymbolName { get; set; } = null!;
public string Scope { get; set; } = null!;
public string HashAlg { get; set; } = null!;
public string HashHex { get; set; } = null!;
public int SizeBytes { get; set; }
public int? CfgBbCount { get; set; }
public string? CfgEdgeHash { get; set; }
public string? ChunkHashes { get; set; }
public string SignatureState { get; set; } = null!;
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public byte[]? AttestationDsse { get; set; }
public string? Metadata { get; set; }
}

View File

@@ -0,0 +1,19 @@
namespace StellaOps.BinaryIndex.Persistence.EfCore.Models;
/// <summary>
/// EF Core entity for binaries.fingerprint_corpus_metadata table.
/// </summary>
public partial class FingerprintCorpusMetadataEntity
{
public Guid Id { get; set; }
public Guid TenantId { get; set; }
public string Purl { get; set; } = null!;
public string Version { get; set; } = null!;
public string Algorithm { get; set; } = null!;
public string? BinaryDigest { get; set; }
public int FunctionCount { get; set; }
public int FingerprintsIndexed { get; set; }
public string? IndexedBy { get; set; }
public DateTime IndexedAt { get; set; }
public DateTime CreatedAt { get; set; }
}

View File

@@ -0,0 +1,24 @@
namespace StellaOps.BinaryIndex.Persistence.EfCore.Models;
/// <summary>
/// EF Core entity for binaries.fingerprint_matches table.
/// </summary>
public partial class FingerprintMatchEntity
{
public Guid Id { get; set; }
public string TenantId { get; set; } = null!;
public Guid ScanId { get; set; }
public string MatchType { get; set; } = null!;
public string BinaryKey { get; set; } = null!;
public Guid? BinaryIdentityId { get; set; }
public string VulnerablePurl { get; set; } = null!;
public string VulnerableVersion { get; set; } = null!;
public Guid? MatchedFingerprintId { get; set; }
public string? MatchedFunction { get; set; }
public decimal? Similarity { get; set; }
public string[]? AdvisoryIds { get; set; }
public string? ReachabilityStatus { get; set; }
public string? Evidence { get; set; }
public DateTime MatchedAt { get; set; }
public DateTime CreatedAt { get; set; }
}

View File

@@ -0,0 +1,17 @@
namespace StellaOps.BinaryIndex.Persistence.EfCore.Models;
/// <summary>
/// EF Core entity for binaries.fix_evidence table.
/// </summary>
public partial class FixEvidenceEntity
{
public Guid Id { get; set; }
public string TenantId { get; set; } = null!;
public string EvidenceType { get; set; } = null!;
public string? SourceFile { get; set; }
public string? SourceSha256 { get; set; }
public string? Excerpt { get; set; }
public string Metadata { get; set; } = null!;
public Guid? SnapshotId { get; set; }
public DateTime CreatedAt { get; set; }
}

View File

@@ -0,0 +1,19 @@
namespace StellaOps.BinaryIndex.Persistence.EfCore.Models;
/// <summary>
/// EF Core entity for groundtruth.raw_documents table.
/// </summary>
public partial class RawDocumentEntity
{
public string Digest { get; set; } = null!;
public string SourceId { get; set; } = null!;
public string DocumentUri { get; set; } = null!;
public string ContentType { get; set; } = null!;
public long ContentSize { get; set; }
public string? Etag { get; set; }
public DateTime FetchedAt { get; set; }
public DateTime RecordedAt { get; set; }
public string Status { get; set; } = null!;
public Guid? PayloadId { get; set; }
public string Metadata { get; set; } = null!;
}

View File

@@ -0,0 +1,25 @@
namespace StellaOps.BinaryIndex.Persistence.EfCore.Models;
/// <summary>
/// EF Core entity for groundtruth.security_pairs table.
/// </summary>
public partial class SecurityPairEntity
{
public Guid PairId { get; set; }
public string CveId { get; set; } = null!;
public string PackageName { get; set; } = null!;
public string Distro { get; set; } = null!;
public string? DistroVersion { get; set; }
public string VulnerableVersion { get; set; } = null!;
public string? VulnerableDebugId { get; set; }
public string? VulnerableObservationId { get; set; }
public string FixedVersion { get; set; } = null!;
public string? FixedDebugId { get; set; }
public string? FixedObservationId { get; set; }
public string? UpstreamDiffUrl { get; set; }
public string[]? PatchFunctions { get; set; }
public string VerificationStatus { get; set; } = null!;
public string Metadata { get; set; } = null!;
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}

View File

@@ -0,0 +1,17 @@
namespace StellaOps.BinaryIndex.Persistence.EfCore.Models;
/// <summary>
/// EF Core entity for groundtruth.source_state table.
/// </summary>
public partial class SourceStateEntity
{
public string SourceId { get; set; } = null!;
public DateTime? LastSyncAt { get; set; }
public string? CursorPosition { get; set; }
public string? CursorMetadata { get; set; }
public string SyncStatus { get; set; } = null!;
public string? LastError { get; set; }
public long DocumentCount { get; set; }
public long ObservationCount { get; set; }
public DateTime UpdatedAt { get; set; }
}

View File

@@ -0,0 +1,26 @@
namespace StellaOps.BinaryIndex.Persistence.EfCore.Models;
/// <summary>
/// EF Core entity for groundtruth.symbol_observations table.
/// </summary>
public partial class SymbolObservationEntity
{
public string ObservationId { get; set; } = null!;
public string SourceId { get; set; } = null!;
public string DebugId { get; set; } = null!;
public string? CodeId { get; set; }
public string BinaryName { get; set; } = null!;
public string? BinaryPath { get; set; }
public string Architecture { get; set; } = null!;
public string? Distro { get; set; }
public string? DistroVersion { get; set; }
public string? PackageName { get; set; }
public string? PackageVersion { get; set; }
public int SymbolCount { get; set; }
public string Symbols { get; set; } = null!;
public string? BuildMetadata { get; set; }
public string Provenance { get; set; } = null!;
public string ContentHash { get; set; } = null!;
public string? SupersedesId { get; set; }
public DateTime CreatedAt { get; set; }
}

View File

@@ -0,0 +1,17 @@
namespace StellaOps.BinaryIndex.Persistence.EfCore.Models;
/// <summary>
/// EF Core entity for groundtruth.symbol_sources table.
/// </summary>
public partial class SymbolSourceEntity
{
public string SourceId { get; set; } = null!;
public string DisplayName { get; set; } = null!;
public string SourceType { get; set; } = null!;
public string BaseUrl { get; set; } = null!;
public string[] SupportedDistros { get; set; } = null!;
public bool IsEnabled { get; set; }
public string? ConfigJson { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}

View File

@@ -0,0 +1,30 @@
namespace StellaOps.BinaryIndex.Persistence.EfCore.Models;
/// <summary>
/// EF Core entity for binaries.vulnerable_fingerprints table.
/// </summary>
public partial class VulnerableFingerprintEntity
{
public Guid Id { get; set; }
public string TenantId { get; set; } = null!;
public string CveId { get; set; } = null!;
public string Component { get; set; } = null!;
public string? Purl { get; set; }
public string Algorithm { get; set; } = null!;
public string FingerprintId { get; set; } = null!;
public byte[] FingerprintHash { get; set; } = null!;
public string Architecture { get; set; } = null!;
public string? FunctionName { get; set; }
public string? SourceFile { get; set; }
public int? SourceLine { get; set; }
public decimal? SimilarityThreshold { get; set; }
public decimal? Confidence { get; set; }
public bool? Validated { get; set; }
public string? ValidationStats { get; set; }
public string? VulnBuildRef { get; set; }
public string? FixedBuildRef { get; set; }
public string? Notes { get; set; }
public string? EvidenceRef { get; set; }
public DateTime IndexedAt { get; set; }
public DateTime CreatedAt { get; set; }
}

View File

@@ -0,0 +1,45 @@
using System;
using Microsoft.EntityFrameworkCore;
using Npgsql;
using StellaOps.BinaryIndex.Persistence.EfCore.CompiledModels;
using StellaOps.BinaryIndex.Persistence.EfCore.Context;
namespace StellaOps.BinaryIndex.Persistence.Postgres;
/// <summary>
/// Runtime factory for BinaryIndex EF Core DbContext.
/// Uses compiled model for the default schema path.
/// </summary>
internal static class BinaryIndexPersistenceDbContextFactory
{
public const string DefaultBinariesSchema = "binaries";
public const string DefaultGroundtruthSchema = "groundtruth";
public static BinaryIndexPersistenceDbContext Create(
NpgsqlConnection connection,
int commandTimeoutSeconds,
string? binariesSchema = null,
string? groundtruthSchema = null)
{
var normalizedBinaries = string.IsNullOrWhiteSpace(binariesSchema)
? DefaultBinariesSchema
: binariesSchema.Trim();
var normalizedGroundtruth = string.IsNullOrWhiteSpace(groundtruthSchema)
? DefaultGroundtruthSchema
: groundtruthSchema.Trim();
var optionsBuilder = new DbContextOptionsBuilder<BinaryIndexPersistenceDbContext>()
.UseNpgsql(connection, npgsql => npgsql.CommandTimeout(commandTimeoutSeconds));
if (string.Equals(normalizedBinaries, DefaultBinariesSchema, StringComparison.Ordinal)
&& string.Equals(normalizedGroundtruth, DefaultGroundtruthSchema, StringComparison.Ordinal))
{
// Use the static compiled model when schema mapping matches the defaults.
optionsBuilder.UseModel(BinaryIndexPersistenceDbContextModel.Instance);
}
return new BinaryIndexPersistenceDbContext(
optionsBuilder.Options, normalizedBinaries, normalizedGroundtruth);
}
}

View File

@@ -1,265 +1,135 @@
using Dapper;
using Microsoft.EntityFrameworkCore;
using StellaOps.BinaryIndex.Core.Models;
using StellaOps.BinaryIndex.Persistence.EfCore.Context;
using StellaOps.BinaryIndex.Persistence.Postgres;
using System.Collections.Immutable;
namespace StellaOps.BinaryIndex.Persistence.Repositories;
/// <summary>
/// Repository implementation for binary identity operations.
/// EF Core repository implementation for binary identity operations.
/// </summary>
public sealed class BinaryIdentityRepository : IBinaryIdentityRepository
{
private readonly BinaryIndexDbContext _dbContext;
private readonly BinaryIndexDbContext _connectionContext;
private const int CommandTimeoutSeconds = 30;
public BinaryIdentityRepository(BinaryIndexDbContext dbContext)
public BinaryIdentityRepository(BinaryIndexDbContext connectionContext)
{
_dbContext = dbContext;
_connectionContext = connectionContext;
}
public async Task<BinaryIdentity?> GetByBuildIdAsync(string buildId, string buildIdType, CancellationToken ct)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var conn = await _connectionContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT id AS "Id",
tenant_id AS "TenantId",
binary_key AS "BinaryKey",
build_id AS "BuildId",
build_id_type AS "BuildIdType",
file_sha256 AS "FileSha256",
text_sha256 AS "TextSha256",
blake3_hash AS "Blake3Hash",
format AS "Format",
architecture AS "Architecture",
osabi AS "OsAbi",
binary_type AS "BinaryType",
is_stripped AS "IsStripped",
first_seen_snapshot_id AS "FirstSeenSnapshotId",
last_seen_snapshot_id AS "LastSeenSnapshotId",
created_at AS "CreatedAt",
updated_at AS "UpdatedAt"
FROM binaries.binary_identity
WHERE build_id = @BuildId AND build_id_type = @BuildIdType
LIMIT 1
""";
var entity = await dbContext.BinaryIdentities
.AsNoTracking()
.Where(e => e.BuildId == buildId && e.BuildIdType == buildIdType)
.FirstOrDefaultAsync(ct);
var command = new CommandDefinition(
sql,
new { BuildId = buildId, BuildIdType = buildIdType },
cancellationToken: ct);
var row = await conn.QuerySingleOrDefaultAsync<BinaryIdentityRow>(command);
return row?.ToModel();
return entity is null ? null : ToModel(entity);
}
public async Task<BinaryIdentity?> GetByKeyAsync(string binaryKey, CancellationToken ct)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var conn = await _connectionContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT id AS "Id",
tenant_id AS "TenantId",
binary_key AS "BinaryKey",
build_id AS "BuildId",
build_id_type AS "BuildIdType",
file_sha256 AS "FileSha256",
text_sha256 AS "TextSha256",
blake3_hash AS "Blake3Hash",
format AS "Format",
architecture AS "Architecture",
osabi AS "OsAbi",
binary_type AS "BinaryType",
is_stripped AS "IsStripped",
first_seen_snapshot_id AS "FirstSeenSnapshotId",
last_seen_snapshot_id AS "LastSeenSnapshotId",
created_at AS "CreatedAt",
updated_at AS "UpdatedAt"
FROM binaries.binary_identity
WHERE binary_key = @BinaryKey
LIMIT 1
""";
var entity = await dbContext.BinaryIdentities
.AsNoTracking()
.Where(e => e.BinaryKey == binaryKey)
.FirstOrDefaultAsync(ct);
var command = new CommandDefinition(
sql,
new { BinaryKey = binaryKey },
cancellationToken: ct);
var row = await conn.QuerySingleOrDefaultAsync<BinaryIdentityRow>(command);
return row?.ToModel();
return entity is null ? null : ToModel(entity);
}
public async Task<BinaryIdentity?> GetByFileSha256Async(string fileSha256, CancellationToken ct)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var conn = await _connectionContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT id AS "Id",
tenant_id AS "TenantId",
binary_key AS "BinaryKey",
build_id AS "BuildId",
build_id_type AS "BuildIdType",
file_sha256 AS "FileSha256",
text_sha256 AS "TextSha256",
blake3_hash AS "Blake3Hash",
format AS "Format",
architecture AS "Architecture",
osabi AS "OsAbi",
binary_type AS "BinaryType",
is_stripped AS "IsStripped",
first_seen_snapshot_id AS "FirstSeenSnapshotId",
last_seen_snapshot_id AS "LastSeenSnapshotId",
created_at AS "CreatedAt",
updated_at AS "UpdatedAt"
FROM binaries.binary_identity
WHERE file_sha256 = @FileSha256
ORDER BY updated_at DESC
LIMIT 1
""";
var entity = await dbContext.BinaryIdentities
.AsNoTracking()
.Where(e => e.FileSha256 == fileSha256)
.OrderByDescending(e => e.UpdatedAt)
.FirstOrDefaultAsync(ct);
var command = new CommandDefinition(
sql,
new { FileSha256 = fileSha256 },
cancellationToken: ct);
var row = await conn.QuerySingleOrDefaultAsync<BinaryIdentityRow>(command);
return row?.ToModel();
return entity is null ? null : ToModel(entity);
}
public async Task<BinaryIdentity> UpsertAsync(BinaryIdentity identity, CancellationToken ct)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
// Complex UPSERT with ON CONFLICT requires raw SQL through EF Core
await using var conn = await _connectionContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
INSERT INTO binaries.binary_identity (
tenant_id, binary_key, build_id, build_id_type, file_sha256, text_sha256, blake3_hash,
format, architecture, osabi, binary_type, is_stripped, first_seen_snapshot_id,
last_seen_snapshot_id, created_at, updated_at
) VALUES (
current_setting('app.tenant_id')::uuid, @BinaryKey, @BuildId, @BuildIdType, @FileSha256,
@TextSha256, @Blake3Hash, @Format, @Architecture, @OsAbi, @BinaryType, @IsStripped,
@FirstSeenSnapshotId, @LastSeenSnapshotId, @CreatedAt, @UpdatedAt
)
ON CONFLICT (tenant_id, binary_key) DO UPDATE SET
updated_at = EXCLUDED.updated_at,
last_seen_snapshot_id = EXCLUDED.last_seen_snapshot_id
RETURNING id AS "Id",
tenant_id AS "TenantId",
binary_key AS "BinaryKey",
build_id AS "BuildId",
build_id_type AS "BuildIdType",
file_sha256 AS "FileSha256",
text_sha256 AS "TextSha256",
blake3_hash AS "Blake3Hash",
format AS "Format",
architecture AS "Architecture",
osabi AS "OsAbi",
binary_type AS "BinaryType",
is_stripped AS "IsStripped",
first_seen_snapshot_id AS "FirstSeenSnapshotId",
last_seen_snapshot_id AS "LastSeenSnapshotId",
created_at AS "CreatedAt",
updated_at AS "UpdatedAt"
""";
var results = await dbContext.BinaryIdentities
.FromSqlInterpolated($"""
INSERT INTO binaries.binary_identity (
tenant_id, binary_key, build_id, build_id_type, file_sha256, text_sha256, blake3_hash,
format, architecture, osabi, binary_type, is_stripped, first_seen_snapshot_id,
last_seen_snapshot_id, created_at, updated_at
) VALUES (
current_setting('app.tenant_id')::uuid, {identity.BinaryKey}, {identity.BuildId}, {identity.BuildIdType}, {identity.FileSha256},
{identity.TextSha256}, {identity.Blake3Hash}, {identity.Format.ToString().ToLowerInvariant()}, {identity.Architecture}, {identity.OsAbi}, {ToDbBinaryType(identity.Type)}, {identity.IsStripped},
{identity.FirstSeenSnapshotId}, {identity.LastSeenSnapshotId}, {identity.CreatedAt}, {identity.UpdatedAt}
)
ON CONFLICT (tenant_id, binary_key) DO UPDATE SET
updated_at = EXCLUDED.updated_at,
last_seen_snapshot_id = EXCLUDED.last_seen_snapshot_id
RETURNING id, tenant_id, binary_key, build_id, build_id_type, file_sha256, text_sha256,
blake3_hash, format, architecture, osabi, binary_type, is_stripped,
first_seen_snapshot_id, last_seen_snapshot_id, created_at, updated_at
""")
.AsNoTracking()
.ToListAsync(ct);
var command = new CommandDefinition(
sql,
new
{
identity.BinaryKey,
identity.BuildId,
identity.BuildIdType,
identity.FileSha256,
identity.TextSha256,
identity.Blake3Hash,
Format = identity.Format.ToString().ToLowerInvariant(),
identity.Architecture,
identity.OsAbi,
BinaryType = ToDbBinaryType(identity.Type),
identity.IsStripped,
identity.FirstSeenSnapshotId,
identity.LastSeenSnapshotId,
identity.CreatedAt,
identity.UpdatedAt
},
cancellationToken: ct);
var row = await conn.QuerySingleAsync<BinaryIdentityRow>(command);
return row.ToModel();
var row = results.First();
return ToModel(row);
}
public async Task<ImmutableArray<BinaryIdentity>> GetBatchAsync(IEnumerable<string> binaryKeys, CancellationToken ct)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
const string sql = """
SELECT id AS "Id",
tenant_id AS "TenantId",
binary_key AS "BinaryKey",
build_id AS "BuildId",
build_id_type AS "BuildIdType",
file_sha256 AS "FileSha256",
text_sha256 AS "TextSha256",
blake3_hash AS "Blake3Hash",
format AS "Format",
architecture AS "Architecture",
osabi AS "OsAbi",
binary_type AS "BinaryType",
is_stripped AS "IsStripped",
first_seen_snapshot_id AS "FirstSeenSnapshotId",
last_seen_snapshot_id AS "LastSeenSnapshotId",
created_at AS "CreatedAt",
updated_at AS "UpdatedAt"
FROM binaries.binary_identity
WHERE binary_key = ANY(@BinaryKeys)
""";
var command = new CommandDefinition(
sql,
new { BinaryKeys = binaryKeys.ToArray() },
cancellationToken: ct);
var rows = await conn.QueryAsync<BinaryIdentityRow>(command);
return rows.Select(r => r.ToModel()).ToImmutableArray();
}
private sealed class BinaryIdentityRow
{
public Guid Id { get; set; }
public Guid TenantId { get; set; }
public string BinaryKey { get; set; } = string.Empty;
public string? BuildId { get; set; }
public string? BuildIdType { get; set; }
public string FileSha256 { get; set; } = string.Empty;
public string? TextSha256 { get; set; }
public string? Blake3Hash { get; set; }
public string Format { get; set; } = string.Empty;
public string Architecture { get; set; } = string.Empty;
public string? OsAbi { get; set; }
public string? BinaryType { get; set; }
public bool IsStripped { get; set; }
public Guid? FirstSeenSnapshotId { get; set; }
public Guid? LastSeenSnapshotId { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public DateTimeOffset UpdatedAt { get; set; }
public BinaryIdentity ToModel() => new()
var keys = binaryKeys.ToArray();
if (keys.Length == 0)
{
Id = Id,
BinaryKey = BinaryKey,
BuildId = BuildId,
BuildIdType = BuildIdType,
FileSha256 = FileSha256,
TextSha256 = TextSha256,
Blake3Hash = Blake3Hash,
Format = Enum.Parse<BinaryFormat>(Format, ignoreCase: true),
Architecture = Architecture,
OsAbi = OsAbi,
Type = FromDbBinaryType(BinaryType),
IsStripped = IsStripped,
FirstSeenSnapshotId = FirstSeenSnapshotId,
LastSeenSnapshotId = LastSeenSnapshotId,
CreatedAt = CreatedAt,
UpdatedAt = UpdatedAt
};
return [];
}
await using var conn = await _connectionContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
var entities = await dbContext.BinaryIdentities
.AsNoTracking()
.Where(e => keys.Contains(e.BinaryKey))
.ToListAsync(ct);
return entities.Select(ToModel).ToImmutableArray();
}
private static BinaryIdentity ToModel(EfCore.Models.BinaryIdentityEntity entity) => new()
{
Id = entity.Id,
BinaryKey = entity.BinaryKey,
BuildId = entity.BuildId,
BuildIdType = entity.BuildIdType,
FileSha256 = entity.FileSha256,
TextSha256 = entity.TextSha256,
Blake3Hash = entity.Blake3Hash,
Format = Enum.Parse<BinaryFormat>(entity.Format, ignoreCase: true),
Architecture = entity.Architecture,
OsAbi = entity.Osabi,
Type = FromDbBinaryType(entity.BinaryType),
IsStripped = entity.IsStripped ?? false,
FirstSeenSnapshotId = entity.FirstSeenSnapshotId,
LastSeenSnapshotId = entity.LastSeenSnapshotId,
CreatedAt = entity.CreatedAt,
UpdatedAt = entity.UpdatedAt
};
private static string? ToDbBinaryType(BinaryType? type)
{
return type switch

View File

@@ -1,36 +1,39 @@
using Dapper;
using Microsoft.EntityFrameworkCore;
using StellaOps.BinaryIndex.Core.Services;
using StellaOps.BinaryIndex.Persistence.Postgres;
using System.Collections.Immutable;
namespace StellaOps.BinaryIndex.Persistence.Repositories;
public sealed class BinaryVulnAssertionRepository : IBinaryVulnAssertionRepository
{
private readonly BinaryIndexDbContext _dbContext;
private readonly BinaryIndexDbContext _connectionContext;
private const int CommandTimeoutSeconds = 30;
public BinaryVulnAssertionRepository(BinaryIndexDbContext dbContext)
public BinaryVulnAssertionRepository(BinaryIndexDbContext connectionContext)
{
_dbContext = dbContext;
_connectionContext = connectionContext;
}
public async Task<ImmutableArray<BinaryVulnAssertion>> GetByBinaryKeyAsync(string binaryKey, CancellationToken ct)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var conn = await _connectionContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT id AS "Id",
binary_key AS "BinaryKey",
cve_id AS "CveId",
status AS "Status",
method AS "Method",
confidence AS "Confidence"
FROM binaries.binary_vuln_assertion
WHERE binary_key = @BinaryKey
""";
var entities = await dbContext.BinaryVulnAssertions
.AsNoTracking()
.Where(e => e.BinaryKey == binaryKey)
.ToListAsync(ct);
var command = new CommandDefinition(sql, new { BinaryKey = binaryKey }, cancellationToken: ct);
var rows = await conn.QueryAsync<BinaryVulnAssertion>(command);
return rows.ToImmutableArray();
return entities.Select(e => new BinaryVulnAssertion
{
Id = e.Id,
BinaryKey = e.BinaryKey,
CveId = e.CveId,
Status = e.Status,
Method = e.Method,
Confidence = e.Confidence
}).ToImmutableArray();
}
}

View File

@@ -1,77 +1,63 @@
using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using StellaOps.BinaryIndex.Corpus;
using StellaOps.BinaryIndex.Persistence.EfCore.Models;
using StellaOps.BinaryIndex.Persistence.Postgres;
namespace StellaOps.BinaryIndex.Persistence.Repositories;
/// <summary>
/// Repository for corpus snapshots.
/// EF Core repository for corpus snapshots.
/// </summary>
public sealed class CorpusSnapshotRepository : ICorpusSnapshotRepository
{
private readonly BinaryIndexDbContext _dbContext;
private readonly BinaryIndexDbContext _connectionContext;
private readonly ILogger<CorpusSnapshotRepository> _logger;
private const int CommandTimeoutSeconds = 30;
public CorpusSnapshotRepository(
BinaryIndexDbContext dbContext,
BinaryIndexDbContext connectionContext,
ILogger<CorpusSnapshotRepository> logger)
{
_dbContext = dbContext;
_connectionContext = connectionContext;
_logger = logger;
}
public async Task<CorpusSnapshot> CreateAsync(CorpusSnapshot snapshot, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var conn = await _connectionContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
INSERT INTO binaries.corpus_snapshots (
id,
tenant_id,
distro,
release,
architecture,
snapshot_id,
repo_metadata_digest,
created_at
)
VALUES (
@Id,
binaries_app.require_current_tenant()::uuid,
@Distro,
@Release,
@Architecture,
@SnapshotId,
@MetadataDigest,
NOW()
)
RETURNING id AS "Id",
distro AS "Distro",
release AS "Release",
architecture AS "Architecture",
repo_metadata_digest AS "MetadataDigest",
created_at AS "CapturedAt"
""";
var snapshotIdValue = $"{snapshot.Distro}_{snapshot.Release}_{snapshot.Architecture}_{snapshot.CapturedAt:yyyyMMddHHmmss}";
var command = new CommandDefinition(
sql,
new
{
snapshot.Id,
snapshot.Distro,
snapshot.Release,
snapshot.Architecture,
SnapshotId = $"{snapshot.Distro}_{snapshot.Release}_{snapshot.Architecture}_{snapshot.CapturedAt:yyyyMMddHHmmss}",
snapshot.MetadataDigest
},
cancellationToken: ct);
var row = await conn.QuerySingleAsync<CorpusSnapshotRow>(command);
// Use raw SQL for INSERT ... RETURNING with tenant function
var results = await dbContext.CorpusSnapshots
.FromSqlInterpolated($"""
INSERT INTO binaries.corpus_snapshots (
id, tenant_id, distro, release, architecture,
snapshot_id, repo_metadata_digest, created_at
)
VALUES (
{snapshot.Id},
binaries_app.require_current_tenant()::uuid,
{snapshot.Distro}, {snapshot.Release}, {snapshot.Architecture},
{snapshotIdValue}, {snapshot.MetadataDigest}, NOW()
)
RETURNING id, tenant_id, distro, release, architecture, snapshot_id,
packages_processed, binaries_indexed, repo_metadata_digest,
signing_key_id, dsse_envelope_ref, status, error,
started_at, completed_at, created_at
""")
.AsNoTracking()
.ToListAsync(ct);
var entity = results.First();
_logger.LogInformation(
"Created corpus snapshot {Id} for {Distro} {Release}/{Architecture}",
row.Id, row.Distro, row.Release, row.Architecture);
entity.Id, entity.Distro, entity.Release, entity.Architecture);
return row.ToModel();
return ToModel(entity);
}
public async Task<CorpusSnapshot?> FindByKeyAsync(
@@ -80,75 +66,38 @@ public sealed class CorpusSnapshotRepository : ICorpusSnapshotRepository
string architecture,
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var conn = await _connectionContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT id AS "Id",
distro AS "Distro",
release AS "Release",
architecture AS "Architecture",
repo_metadata_digest AS "MetadataDigest",
created_at AS "CapturedAt"
FROM binaries.corpus_snapshots
WHERE distro = @Distro
AND release = @Release
AND architecture = @Architecture
ORDER BY created_at DESC
LIMIT 1
""";
var entity = await dbContext.CorpusSnapshots
.AsNoTracking()
.Where(e => e.Distro == distro && e.Release == release && e.Architecture == architecture)
.OrderByDescending(e => e.CreatedAt)
.FirstOrDefaultAsync(ct);
var command = new CommandDefinition(
sql,
new
{
Distro = distro,
Release = release,
Architecture = architecture
},
cancellationToken: ct);
var row = await conn.QuerySingleOrDefaultAsync<CorpusSnapshotRow>(command);
return row?.ToModel();
return entity is null ? null : ToModel(entity);
}
public async Task<CorpusSnapshot?> GetByIdAsync(Guid id, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var conn = await _connectionContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT id AS "Id",
distro AS "Distro",
release AS "Release",
architecture AS "Architecture",
repo_metadata_digest AS "MetadataDigest",
created_at AS "CapturedAt"
FROM binaries.corpus_snapshots
WHERE id = @Id
""";
var entity = await dbContext.CorpusSnapshots
.AsNoTracking()
.Where(e => e.Id == id)
.FirstOrDefaultAsync(ct);
var command = new CommandDefinition(sql, new { Id = id }, cancellationToken: ct);
var row = await conn.QuerySingleOrDefaultAsync<CorpusSnapshotRow>(command);
return row?.ToModel();
return entity is null ? null : ToModel(entity);
}
private sealed class CorpusSnapshotRow
private static CorpusSnapshot ToModel(CorpusSnapshotEntity entity) => new()
{
public Guid Id { get; set; }
public string Distro { get; set; } = string.Empty;
public string Release { get; set; } = string.Empty;
public string Architecture { get; set; } = string.Empty;
public string MetadataDigest { get; set; } = string.Empty;
public DateTimeOffset CapturedAt { get; set; }
public CorpusSnapshot ToModel() => new()
{
Id = Id,
Distro = Distro,
Release = Release,
Architecture = Architecture,
MetadataDigest = MetadataDigest,
CapturedAt = CapturedAt
};
}
Id = entity.Id,
Distro = entity.Distro,
Release = entity.Release,
Architecture = entity.Architecture,
MetadataDigest = entity.RepoMetadataDigest ?? string.Empty,
CapturedAt = entity.CreatedAt
};
}

View File

@@ -1,19 +1,18 @@
// Copyright (c) StellaOps. All rights reserved.
// Licensed under BUSL-1.1. See LICENSE in the project root.
using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using StellaOps.BinaryIndex.DeltaSig;
using StellaOps.BinaryIndex.Persistence.Postgres;
using StellaOps.Determinism;
using System.Collections.Immutable;
using System.Globalization;
using System.Text.Json;
namespace StellaOps.BinaryIndex.Persistence.Repositories;
/// <summary>
/// PostgreSQL repository implementation for delta signatures.
/// EF Core repository implementation for delta signatures.
/// </summary>
public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
{
@@ -21,6 +20,7 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
private readonly ILogger<DeltaSignatureRepository> _logger;
private readonly TimeProvider _timeProvider;
private readonly IGuidProvider _guidProvider;
private const int CommandTimeoutSeconds = 30;
private static readonly JsonSerializerOptions s_jsonOptions = new()
{
@@ -46,73 +46,51 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
const string sql = """
INSERT INTO binaries.delta_signature (
id, tenant_id, cve_id, package_name, soname, arch, abi,
recipe_id, recipe_version, symbol_name, scope,
hash_alg, hash_hex, size_bytes,
cfg_bb_count, cfg_edge_hash, chunk_hashes,
signature_state, created_at, updated_at,
attestation_dsse, metadata
)
VALUES (
@Id, binaries_app.require_current_tenant()::uuid, @CveId, @PackageName, @Soname, @Arch, @Abi,
@RecipeId, @RecipeVersion, @SymbolName, @Scope,
@HashAlg, @HashHex, @SizeBytes,
@CfgBbCount, @CfgEdgeHash, @ChunkHashes::jsonb,
@SignatureState, @CreatedAt, @UpdatedAt,
@AttestationDsse, @Metadata::jsonb
)
RETURNING id, created_at, updated_at
""";
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
var now = _timeProvider.GetUtcNow();
var id = entity.Id != Guid.Empty ? entity.Id : _guidProvider.NewGuid();
var chunkHashesJson = entity.ChunkHashes.HasValue
? JsonSerializer.Serialize(entity.ChunkHashes.Value, s_jsonOptions)
: (string?)null;
var metadataJson = entity.Metadata != null
? JsonSerializer.Serialize(entity.Metadata, s_jsonOptions)
: (string?)null;
var command = new CommandDefinition(
sql,
new
{
Id = id,
entity.CveId,
entity.PackageName,
entity.Soname,
entity.Arch,
entity.Abi,
entity.RecipeId,
entity.RecipeVersion,
entity.SymbolName,
entity.Scope,
entity.HashAlg,
entity.HashHex,
entity.SizeBytes,
entity.CfgBbCount,
entity.CfgEdgeHash,
ChunkHashes = entity.ChunkHashes.HasValue
? JsonSerializer.Serialize(entity.ChunkHashes.Value, s_jsonOptions)
: null,
entity.SignatureState,
CreatedAt = now,
UpdatedAt = now,
entity.AttestationDsse,
Metadata = entity.Metadata != null
? JsonSerializer.Serialize(entity.Metadata, s_jsonOptions)
: null
},
cancellationToken: ct);
var result = await conn.QuerySingleAsync<(Guid Id, DateTimeOffset CreatedAt, DateTimeOffset UpdatedAt)>(command);
var results = await efContext.DeltaSignatures
.FromSqlInterpolated($"""
INSERT INTO binaries.delta_signature (
id, tenant_id, cve_id, package_name, soname, arch, abi,
recipe_id, recipe_version, symbol_name, scope,
hash_alg, hash_hex, size_bytes,
cfg_bb_count, cfg_edge_hash, chunk_hashes,
signature_state, created_at, updated_at,
attestation_dsse, metadata
)
VALUES (
{id}, binaries_app.require_current_tenant()::uuid, {entity.CveId}, {entity.PackageName}, {entity.Soname}, {entity.Arch}, {entity.Abi},
{entity.RecipeId}, {entity.RecipeVersion}, {entity.SymbolName}, {entity.Scope},
{entity.HashAlg}, {entity.HashHex}, {entity.SizeBytes},
{entity.CfgBbCount}, {entity.CfgEdgeHash}, {chunkHashesJson}::jsonb,
{entity.SignatureState}, {now}, {now},
{entity.AttestationDsse}, {metadataJson}::jsonb
)
RETURNING id, tenant_id, cve_id, package_name, soname, arch, abi,
recipe_id, recipe_version, symbol_name, scope,
hash_alg, hash_hex, size_bytes,
cfg_bb_count, cfg_edge_hash, chunk_hashes,
signature_state, created_at, updated_at,
attestation_dsse, metadata
""")
.AsNoTracking()
.ToListAsync(ct);
var row = results.First();
_logger.LogDebug(
"Created delta signature {Id} for {CveId}/{SymbolName} ({State})",
result.Id, entity.CveId, entity.SymbolName, entity.SignatureState);
row.Id, row.CveId, row.SymbolName, row.SignatureState);
return entity with
{
Id = result.Id,
CreatedAt = result.CreatedAt,
UpdatedAt = result.UpdatedAt
};
return ToModel(row);
}
/// <inheritdoc />
@@ -138,22 +116,14 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT id, cve_id as CveId, package_name as PackageName, soname as Soname,
arch as Arch, abi as Abi, recipe_id as RecipeId, recipe_version as RecipeVersion,
symbol_name as SymbolName, scope as Scope, hash_alg as HashAlg, hash_hex as HashHex,
size_bytes as SizeBytes, cfg_bb_count as CfgBbCount, cfg_edge_hash as CfgEdgeHash,
chunk_hashes as ChunkHashesJson, signature_state as SignatureState,
created_at as CreatedAt, updated_at as UpdatedAt,
attestation_dsse as AttestationDsse, metadata as MetadataJson
FROM binaries.delta_signature
WHERE id = @Id
""";
var entity = await efContext.DeltaSignatures
.AsNoTracking()
.Where(e => e.Id == id)
.FirstOrDefaultAsync(ct);
var command = new CommandDefinition(sql, new { Id = id }, cancellationToken: ct);
var row = await conn.QuerySingleOrDefaultAsync<DeltaSignatureRow>(command);
return row?.ToEntity();
return entity is null ? null : ToModel(entity);
}
/// <inheritdoc />
@@ -162,23 +132,15 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT id, cve_id as CveId, package_name as PackageName, soname as Soname,
arch as Arch, abi as Abi, recipe_id as RecipeId, recipe_version as RecipeVersion,
symbol_name as SymbolName, scope as Scope, hash_alg as HashAlg, hash_hex as HashHex,
size_bytes as SizeBytes, cfg_bb_count as CfgBbCount, cfg_edge_hash as CfgEdgeHash,
chunk_hashes as ChunkHashesJson, signature_state as SignatureState,
created_at as CreatedAt, updated_at as UpdatedAt,
attestation_dsse as AttestationDsse, metadata as MetadataJson
FROM binaries.delta_signature
WHERE cve_id = @CveId
ORDER BY package_name, symbol_name, signature_state
""";
var entities = await efContext.DeltaSignatures
.AsNoTracking()
.Where(e => e.CveId == cveId)
.OrderBy(e => e.PackageName).ThenBy(e => e.SymbolName).ThenBy(e => e.SignatureState)
.ToListAsync(ct);
var command = new CommandDefinition(sql, new { CveId = cveId }, cancellationToken: ct);
var rows = await conn.QueryAsync<DeltaSignatureRow>(command);
return rows.Select(r => r.ToEntity()).ToList();
return entities.Select(ToModel).ToList();
}
/// <inheritdoc />
@@ -188,33 +150,22 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
var sql = """
SELECT id, cve_id as CveId, package_name as PackageName, soname as Soname,
arch as Arch, abi as Abi, recipe_id as RecipeId, recipe_version as RecipeVersion,
symbol_name as SymbolName, scope as Scope, hash_alg as HashAlg, hash_hex as HashHex,
size_bytes as SizeBytes, cfg_bb_count as CfgBbCount, cfg_edge_hash as CfgEdgeHash,
chunk_hashes as ChunkHashesJson, signature_state as SignatureState,
created_at as CreatedAt, updated_at as UpdatedAt,
attestation_dsse as AttestationDsse, metadata as MetadataJson
FROM binaries.delta_signature
WHERE package_name = @PackageName
""";
var query = efContext.DeltaSignatures
.AsNoTracking()
.Where(e => e.PackageName == packageName);
if (soname != null)
{
sql += " AND soname = @Soname";
query = query.Where(e => e.Soname == soname);
}
sql += " ORDER BY cve_id, symbol_name, signature_state";
var entities = await query
.OrderBy(e => e.CveId).ThenBy(e => e.SymbolName).ThenBy(e => e.SignatureState)
.ToListAsync(ct);
var command = new CommandDefinition(
sql,
new { PackageName = packageName, Soname = soname },
cancellationToken: ct);
var rows = await conn.QueryAsync<DeltaSignatureRow>(command);
return rows.Select(r => r.ToEntity()).ToList();
return entities.Select(ToModel).ToList();
}
/// <inheritdoc />
@@ -223,26 +174,15 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT id, cve_id as CveId, package_name as PackageName, soname as Soname,
arch as Arch, abi as Abi, recipe_id as RecipeId, recipe_version as RecipeVersion,
symbol_name as SymbolName, scope as Scope, hash_alg as HashAlg, hash_hex as HashHex,
size_bytes as SizeBytes, cfg_bb_count as CfgBbCount, cfg_edge_hash as CfgEdgeHash,
chunk_hashes as ChunkHashesJson, signature_state as SignatureState,
created_at as CreatedAt, updated_at as UpdatedAt,
attestation_dsse as AttestationDsse, metadata as MetadataJson
FROM binaries.delta_signature
WHERE hash_hex = @HashHex
""";
var normalizedHash = hashHex.ToLowerInvariant();
var entities = await efContext.DeltaSignatures
.AsNoTracking()
.Where(e => e.HashHex == normalizedHash)
.ToListAsync(ct);
var command = new CommandDefinition(
sql,
new { HashHex = hashHex.ToLowerInvariant() },
cancellationToken: ct);
var rows = await conn.QueryAsync<DeltaSignatureRow>(command);
return rows.Select(r => r.ToEntity()).ToList();
return entities.Select(ToModel).ToList();
}
/// <inheritdoc />
@@ -252,36 +192,22 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
IEnumerable<string> symbolNames,
CancellationToken ct = default)
{
var symbolList = symbolNames.ToList();
if (symbolList.Count == 0)
var symbolList = symbolNames.ToArray();
if (symbolList.Length == 0)
{
return [];
}
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT id, cve_id as CveId, package_name as PackageName, soname as Soname,
arch as Arch, abi as Abi, recipe_id as RecipeId, recipe_version as RecipeVersion,
symbol_name as SymbolName, scope as Scope, hash_alg as HashAlg, hash_hex as HashHex,
size_bytes as SizeBytes, cfg_bb_count as CfgBbCount, cfg_edge_hash as CfgEdgeHash,
chunk_hashes as ChunkHashesJson, signature_state as SignatureState,
created_at as CreatedAt, updated_at as UpdatedAt,
attestation_dsse as AttestationDsse, metadata as MetadataJson
FROM binaries.delta_signature
WHERE arch = @Arch
AND abi = @Abi
AND symbol_name = ANY(@SymbolNames)
ORDER BY cve_id, symbol_name, signature_state
""";
var entities = await efContext.DeltaSignatures
.AsNoTracking()
.Where(e => e.Arch == arch && e.Abi == abi && symbolList.Contains(e.SymbolName))
.OrderBy(e => e.CveId).ThenBy(e => e.SymbolName).ThenBy(e => e.SignatureState)
.ToListAsync(ct);
var command = new CommandDefinition(
sql,
new { Arch = arch, Abi = abi, SymbolNames = symbolList.ToArray() },
cancellationToken: ct);
var rows = await conn.QueryAsync<DeltaSignatureRow>(command);
return rows.Select(r => r.ToEntity()).ToList();
return entities.Select(ToModel).ToList();
}
/// <inheritdoc />
@@ -292,50 +218,31 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
var conditions = new List<string>();
var parameters = new DynamicParameters();
IQueryable<EfCore.Models.DeltaSignatureDbEntity> query = efContext.DeltaSignatures.AsNoTracking();
if (cveFilter is { Count: > 0 })
{
conditions.Add("cve_id = ANY(@CveIds)");
parameters.Add("CveIds", cveFilter.ToArray());
query = query.Where(e => cveFilter.Contains(e.CveId));
}
if (!string.IsNullOrWhiteSpace(packageFilter))
{
conditions.Add("package_name = @PackageName");
parameters.Add("PackageName", packageFilter);
query = query.Where(e => e.PackageName == packageFilter);
}
if (!string.IsNullOrWhiteSpace(archFilter))
{
conditions.Add("arch = @Arch");
parameters.Add("Arch", archFilter);
query = query.Where(e => e.Arch == archFilter);
}
var whereClause = conditions.Count > 0
? "WHERE " + string.Join(" AND ", conditions)
: string.Empty;
var entities = await query
.OrderBy(e => e.CveId).ThenBy(e => e.SymbolName).ThenBy(e => e.SignatureState)
.ToListAsync(ct);
var sql = $"""
SELECT id, cve_id as CveId, package_name as PackageName, soname as Soname,
arch as Arch, abi as Abi, recipe_id as RecipeId, recipe_version as RecipeVersion,
symbol_name as SymbolName, scope as Scope, hash_alg as HashAlg, hash_hex as HashHex,
size_bytes as SizeBytes, cfg_bb_count as CfgBbCount, cfg_edge_hash as CfgEdgeHash,
chunk_hashes as ChunkHashesJson, signature_state as SignatureState,
created_at as CreatedAt, updated_at as UpdatedAt,
attestation_dsse as AttestationDsse, metadata as MetadataJson
FROM binaries.delta_signature
{whereClause}
ORDER BY cve_id, symbol_name, signature_state
""";
var command = new CommandDefinition(sql, parameters, cancellationToken: ct);
var rows = await conn.QueryAsync<DeltaSignatureRow>(command);
_logger.LogDebug("GetAllMatchingAsync returned {Count} signatures", rows.Count());
return rows.Select(r => r.ToEntity()).ToList();
_logger.LogDebug("GetAllMatchingAsync returned {Count} signatures", entities.Count);
return entities.Select(ToModel).ToList();
}
/// <inheritdoc />
@@ -344,68 +251,51 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
const string sql = """
UPDATE binaries.delta_signature
SET cve_id = @CveId,
package_name = @PackageName,
soname = @Soname,
arch = @Arch,
abi = @Abi,
recipe_id = @RecipeId,
recipe_version = @RecipeVersion,
symbol_name = @SymbolName,
scope = @Scope,
hash_alg = @HashAlg,
hash_hex = @HashHex,
size_bytes = @SizeBytes,
cfg_bb_count = @CfgBbCount,
cfg_edge_hash = @CfgEdgeHash,
chunk_hashes = @ChunkHashes::jsonb,
signature_state = @SignatureState,
updated_at = @UpdatedAt,
attestation_dsse = @AttestationDsse,
metadata = @Metadata::jsonb
WHERE id = @Id
RETURNING updated_at
""";
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
var now = _timeProvider.GetUtcNow();
var chunkHashesJson = entity.ChunkHashes.HasValue
? JsonSerializer.Serialize(entity.ChunkHashes.Value, s_jsonOptions)
: (string?)null;
var metadataJson = entity.Metadata != null
? JsonSerializer.Serialize(entity.Metadata, s_jsonOptions)
: (string?)null;
var command = new CommandDefinition(
sql,
new
{
entity.Id,
entity.CveId,
entity.PackageName,
entity.Soname,
entity.Arch,
entity.Abi,
entity.RecipeId,
entity.RecipeVersion,
entity.SymbolName,
entity.Scope,
entity.HashAlg,
entity.HashHex,
entity.SizeBytes,
entity.CfgBbCount,
entity.CfgEdgeHash,
ChunkHashes = entity.ChunkHashes.HasValue
? JsonSerializer.Serialize(entity.ChunkHashes.Value, s_jsonOptions)
: null,
entity.SignatureState,
UpdatedAt = now,
entity.AttestationDsse,
Metadata = entity.Metadata != null
? JsonSerializer.Serialize(entity.Metadata, s_jsonOptions)
: null
},
cancellationToken: ct);
var updatedAt = await conn.ExecuteScalarAsync<DateTimeOffset>(command);
var results = await efContext.DeltaSignatures
.FromSqlInterpolated($"""
UPDATE binaries.delta_signature
SET cve_id = {entity.CveId},
package_name = {entity.PackageName},
soname = {entity.Soname},
arch = {entity.Arch},
abi = {entity.Abi},
recipe_id = {entity.RecipeId},
recipe_version = {entity.RecipeVersion},
symbol_name = {entity.SymbolName},
scope = {entity.Scope},
hash_alg = {entity.HashAlg},
hash_hex = {entity.HashHex},
size_bytes = {entity.SizeBytes},
cfg_bb_count = {entity.CfgBbCount},
cfg_edge_hash = {entity.CfgEdgeHash},
chunk_hashes = {chunkHashesJson}::jsonb,
signature_state = {entity.SignatureState},
updated_at = {now},
attestation_dsse = {entity.AttestationDsse},
metadata = {metadataJson}::jsonb
WHERE id = {entity.Id}
RETURNING id, tenant_id, cve_id, package_name, soname, arch, abi,
recipe_id, recipe_version, symbol_name, scope,
hash_alg, hash_hex, size_bytes,
cfg_bb_count, cfg_edge_hash, chunk_hashes,
signature_state, created_at, updated_at,
attestation_dsse, metadata
""")
.AsNoTracking()
.ToListAsync(ct);
_logger.LogDebug("Updated delta signature {Id}", entity.Id);
return entity with { UpdatedAt = updatedAt };
return ToModel(results.First());
}
/// <inheritdoc />
@@ -414,10 +304,10 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = "DELETE FROM binaries.delta_signature WHERE id = @Id";
var command = new CommandDefinition(sql, new { Id = id }, cancellationToken: ct);
var rows = await conn.ExecuteAsync(command);
var rows = await efContext.Database.ExecuteSqlInterpolatedAsync(
$"DELETE FROM binaries.delta_signature WHERE id = {id}", ct);
if (rows > 0)
{
@@ -432,16 +322,15 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT signature_state as State, COUNT(*) as Count
FROM binaries.delta_signature
GROUP BY signature_state
""";
var groups = await efContext.DeltaSignatures
.AsNoTracking()
.GroupBy(e => e.SignatureState)
.Select(g => new { State = g.Key, Count = g.Count() })
.ToListAsync(ct);
var command = new CommandDefinition(sql, cancellationToken: ct);
var rows = await conn.QueryAsync<(string State, int Count)>(command);
return rows.ToDictionary(r => r.State, r => r.Count);
return groups.ToDictionary(g => g.State, g => g.Count);
}
// -------------------------------------------------------------------------
@@ -457,37 +346,59 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
var conditions = new List<string>();
var parameters = new DynamicParameters();
// Build LINQ query for filtering
IQueryable<EfCore.Models.DeltaSignatureDbEntity> baseQuery = efContext.DeltaSignatures.AsNoTracking();
if (cveFilter is { Count: > 0 })
{
conditions.Add("ds.cve_id = ANY(@CveIds)");
parameters.Add("CveIds", cveFilter.ToArray());
baseQuery = baseQuery.Where(e => cveFilter.Contains(e.CveId));
}
if (!string.IsNullOrWhiteSpace(packageFilter))
{
conditions.Add("ds.package_name = @PackageName");
parameters.Add("PackageName", packageFilter);
baseQuery = baseQuery.Where(e => e.PackageName == packageFilter);
}
// Count total CVEs matching filter
var totalCount = await baseQuery
.Select(e => e.CveId)
.Distinct()
.CountAsync(ct);
// Get aggregated coverage by CVE -- use raw SQL for the CTE with FILTER aggregation
// which EF Core cannot translate directly
var cveIds = cveFilter is { Count: > 0 } ? cveFilter.ToArray() : (string[]?)null;
// Build WHERE conditions dynamically based on filters
var conditions = new List<string>();
var parameters = new List<object>();
var paramIndex = 0;
if (cveIds is not null)
{
conditions.Add($"ds.cve_id = ANY(@p{paramIndex})");
parameters.Add(cveIds);
paramIndex++;
}
if (!string.IsNullOrWhiteSpace(packageFilter))
{
conditions.Add($"ds.package_name = @p{paramIndex}");
parameters.Add(packageFilter);
paramIndex++;
}
var whereClause = conditions.Count > 0
? "WHERE " + string.Join(" AND ", conditions)
: string.Empty;
// Count total CVEs matching filter
var countSql = $"""
SELECT COUNT(DISTINCT ds.cve_id)
FROM binaries.delta_signature ds
{whereClause}
""";
var limitParamIdx = paramIndex;
var offsetParamIdx = paramIndex + 1;
parameters.Add(limit);
parameters.Add(offset);
var countCommand = new CommandDefinition(countSql, parameters, cancellationToken: ct);
var totalCount = await conn.ExecuteScalarAsync<int>(countCommand);
// Get aggregated coverage by CVE
var sql = $"""
WITH cve_stats AS (
SELECT
@@ -503,35 +414,35 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
GROUP BY ds.cve_id, ds.package_name
)
SELECT
cve_id as CveId,
package_name as PackageName,
vulnerable_count as VulnerableCount,
patched_count as PatchedCount,
unknown_count as UnknownCount,
symbol_count as SymbolCount,
cve_id as "CveId",
package_name as "PackageName",
vulnerable_count as "VulnerableCount",
patched_count as "PatchedCount",
unknown_count as "UnknownCount",
symbol_count as "SymbolCount",
CASE WHEN (vulnerable_count + patched_count + unknown_count) > 0
THEN (patched_count * 100.0 / (vulnerable_count + patched_count + unknown_count))
ELSE 0
END as CoveragePercent,
last_updated_at as LastUpdatedAt
END as "CoveragePercent",
last_updated_at as "LastUpdatedAt"
FROM cve_stats
ORDER BY cve_id
LIMIT @Limit OFFSET @Offset
LIMIT @p{limitParamIdx} OFFSET @p{offsetParamIdx}
""";
parameters.Add("Limit", limit);
parameters.Add("Offset", offset);
var command = new CommandDefinition(sql, parameters, cancellationToken: ct);
var rows = await conn.QueryAsync<PatchCoverageEntry>(command);
#pragma warning disable EF1002 // SQL built dynamically from safe parameters
var entries = await efContext.Database
.SqlQueryRaw<PatchCoverageEntry>(sql, parameters.ToArray())
.ToListAsync(ct);
#pragma warning restore EF1002
_logger.LogDebug(
"GetPatchCoverageAsync returned {Count} entries (total: {Total})",
rows.Count(), totalCount);
entries.Count, totalCount);
return new PatchCoverageResult
{
Entries = rows.ToList(),
Entries = entries,
TotalCount = totalCount,
Offset = offset,
Limit = limit
@@ -544,28 +455,25 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
// Get function-level breakdown
const string functionSql = """
SELECT
ds.symbol_name as SymbolName,
ds.soname as Soname,
COUNT(*) FILTER (WHERE ds.signature_state = 'vulnerable') as VulnerableCount,
COUNT(*) FILTER (WHERE ds.signature_state = 'patched') as PatchedCount,
COUNT(*) FILTER (WHERE ds.signature_state NOT IN ('vulnerable', 'patched')) as UnknownCount,
(COUNT(*) FILTER (WHERE ds.signature_state = 'vulnerable') > 0
AND COUNT(*) FILTER (WHERE ds.signature_state = 'patched') > 0) as HasDelta
FROM binaries.delta_signature ds
WHERE ds.cve_id = @CveId
GROUP BY ds.symbol_name, ds.soname
ORDER BY ds.symbol_name
""";
var functionCommand = new CommandDefinition(
functionSql,
new { CveId = cveId },
cancellationToken: ct);
var functions = (await conn.QueryAsync<FunctionCoverageEntry>(functionCommand)).ToList();
// Get function-level breakdown -- requires FILTER aggregation (raw SQL)
var functions = await efContext.Database
.SqlQueryRaw<FunctionCoverageEntry>("""
SELECT
ds.symbol_name as "SymbolName",
ds.soname as "Soname",
COUNT(*) FILTER (WHERE ds.signature_state = 'vulnerable') as "VulnerableCount",
COUNT(*) FILTER (WHERE ds.signature_state = 'patched') as "PatchedCount",
COUNT(*) FILTER (WHERE ds.signature_state NOT IN ('vulnerable', 'patched')) as "UnknownCount",
(COUNT(*) FILTER (WHERE ds.signature_state = 'vulnerable') > 0
AND COUNT(*) FILTER (WHERE ds.signature_state = 'patched') > 0) as "HasDelta"
FROM binaries.delta_signature ds
WHERE ds.cve_id = @p0
GROUP BY ds.symbol_name, ds.soname
ORDER BY ds.symbol_name
""", cveId)
.ToListAsync(ct);
if (functions.Count == 0)
{
@@ -573,14 +481,11 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
}
// Get package name
const string packageSql = """
SELECT DISTINCT package_name
FROM binaries.delta_signature
WHERE cve_id = @CveId
LIMIT 1
""";
var packageName = await conn.ExecuteScalarAsync<string>(
new CommandDefinition(packageSql, new { CveId = cveId }, cancellationToken: ct)) ?? "unknown";
var packageName = await efContext.DeltaSignatures
.AsNoTracking()
.Where(e => e.CveId == cveId)
.Select(e => e.PackageName)
.FirstOrDefaultAsync(ct) ?? "unknown";
// Compute summary
var totalVulnerable = functions.Sum(f => f.VulnerableCount);
@@ -625,144 +530,96 @@ public sealed class DeltaSignatureRepository : IDeltaSignatureRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
var conditions = new List<string> { "m.cve_id = @CveId" };
var parameters = new DynamicParameters();
parameters.Add("CveId", cveId);
// Build filter query for delta_sig_match
IQueryable<EfCore.Models.DeltaSigMatchDbEntity> query = efContext.DeltaSigMatches
.AsNoTracking()
.Where(e => e.CveId == cveId);
if (!string.IsNullOrWhiteSpace(symbolName))
{
conditions.Add("m.symbol_name = @SymbolName");
parameters.Add("SymbolName", symbolName);
query = query.Where(e => e.SymbolName == symbolName);
}
if (!string.IsNullOrWhiteSpace(matchState))
{
conditions.Add("m.matched_state = @MatchState");
parameters.Add("MatchState", matchState);
query = query.Where(e => e.MatchedState == matchState);
}
var whereClause = "WHERE " + string.Join(" AND ", conditions);
var totalCount = await query.CountAsync(ct);
// Count total matches
var countSql = $"""
SELECT COUNT(*)
FROM binaries.delta_sig_match m
{whereClause}
""";
var countCommand = new CommandDefinition(countSql, parameters, cancellationToken: ct);
var totalCount = await conn.ExecuteScalarAsync<int>(countCommand);
// Get paginated matches
var sql = $"""
SELECT
m.id as MatchId,
m.binary_key as BinaryKey,
m.binary_sha256 as BinarySha256,
m.symbol_name as SymbolName,
m.matched_state as MatchState,
m.confidence as Confidence,
m.scan_id as ScanId,
m.scanned_at as ScannedAt
FROM binaries.delta_sig_match m
{whereClause}
ORDER BY m.scanned_at DESC
LIMIT @Limit OFFSET @Offset
""";
parameters.Add("Limit", limit);
parameters.Add("Offset", offset);
var command = new CommandDefinition(sql, parameters, cancellationToken: ct);
var rows = await conn.QueryAsync<PatchMatchEntry>(command);
var matches = await query
.OrderByDescending(e => e.ScannedAt)
.Skip(offset)
.Take(limit)
.Select(m => new PatchMatchEntry
{
MatchId = m.Id,
BinaryKey = m.BinaryKey,
BinarySha256 = m.BinarySha256,
SymbolName = m.SymbolName,
MatchState = m.MatchedState,
Confidence = m.Confidence,
ScanId = m.ScanId,
ScannedAt = m.ScannedAt
})
.ToListAsync(ct);
_logger.LogDebug(
"GetMatchingImagesAsync for {CveId}: {Count} matches (total: {Total})",
cveId, rows.Count(), totalCount);
cveId, matches.Count, totalCount);
return new PatchMatchPage
{
Matches = rows.ToList(),
Matches = matches,
TotalCount = totalCount,
Offset = offset,
Limit = limit
};
}
/// <summary>
/// Internal row type for Dapper mapping.
/// </summary>
private sealed class DeltaSignatureRow
private static DeltaSignatureEntity ToModel(EfCore.Models.DeltaSignatureDbEntity entity)
{
public Guid Id { get; set; }
public string CveId { get; set; } = "";
public string PackageName { get; set; } = "";
public string? Soname { get; set; }
public string Arch { get; set; } = "";
public string Abi { get; set; } = "gnu";
public string RecipeId { get; set; } = "";
public string RecipeVersion { get; set; } = "";
public string SymbolName { get; set; } = "";
public string Scope { get; set; } = ".text";
public string HashAlg { get; set; } = "sha256";
public string HashHex { get; set; } = "";
public int SizeBytes { get; set; }
public int? CfgBbCount { get; set; }
public string? CfgEdgeHash { get; set; }
public string? ChunkHashesJson { get; set; }
public string SignatureState { get; set; } = "";
public DateTimeOffset CreatedAt { get; set; }
public DateTimeOffset UpdatedAt { get; set; }
public byte[]? AttestationDsse { get; set; }
public string? MetadataJson { get; set; }
public DeltaSignatureEntity ToEntity()
ImmutableArray<ChunkHash>? chunks = null;
if (!string.IsNullOrEmpty(entity.ChunkHashes))
{
ImmutableArray<ChunkHash>? chunks = null;
if (!string.IsNullOrEmpty(ChunkHashesJson))
var chunkList = JsonSerializer.Deserialize<List<ChunkHash>>(entity.ChunkHashes, s_jsonOptions);
if (chunkList != null)
{
var chunkList = JsonSerializer.Deserialize<List<ChunkHash>>(ChunkHashesJson, s_jsonOptions);
if (chunkList != null)
{
chunks = [.. chunkList];
}
chunks = [.. chunkList];
}
Dictionary<string, object>? metadata = null;
if (!string.IsNullOrEmpty(MetadataJson))
{
metadata = JsonSerializer.Deserialize<Dictionary<string, object>>(MetadataJson, s_jsonOptions);
}
return new DeltaSignatureEntity
{
Id = Id,
CveId = CveId,
PackageName = PackageName,
Soname = Soname,
Arch = Arch,
Abi = Abi,
RecipeId = RecipeId,
RecipeVersion = RecipeVersion,
SymbolName = SymbolName,
Scope = Scope,
HashAlg = HashAlg,
HashHex = HashHex,
SizeBytes = SizeBytes,
CfgBbCount = CfgBbCount,
CfgEdgeHash = CfgEdgeHash,
ChunkHashes = chunks,
SignatureState = SignatureState,
CreatedAt = CreatedAt,
UpdatedAt = UpdatedAt,
AttestationDsse = AttestationDsse,
Metadata = metadata
};
}
private static readonly JsonSerializerOptions s_jsonOptions = new()
Dictionary<string, object>? metadata = null;
if (!string.IsNullOrEmpty(entity.Metadata))
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
metadata = JsonSerializer.Deserialize<Dictionary<string, object>>(entity.Metadata, s_jsonOptions);
}
return new DeltaSignatureEntity
{
Id = entity.Id,
CveId = entity.CveId,
PackageName = entity.PackageName,
Soname = entity.Soname,
Arch = entity.Arch,
Abi = entity.Abi,
RecipeId = entity.RecipeId,
RecipeVersion = entity.RecipeVersion,
SymbolName = entity.SymbolName,
Scope = entity.Scope,
HashAlg = entity.HashAlg,
HashHex = entity.HashHex,
SizeBytes = entity.SizeBytes,
CfgBbCount = entity.CfgBbCount,
CfgEdgeHash = entity.CfgEdgeHash,
ChunkHashes = chunks,
SignatureState = entity.SignatureState,
CreatedAt = new DateTimeOffset(entity.CreatedAt, TimeSpan.Zero),
UpdatedAt = new DateTimeOffset(entity.UpdatedAt, TimeSpan.Zero),
AttestationDsse = entity.AttestationDsse,
Metadata = metadata
};
}
}

View File

@@ -1,8 +1,9 @@
using Dapper;
using Microsoft.EntityFrameworkCore;
using IGuidProvider = StellaOps.Determinism.IGuidProvider;
using StellaOps.BinaryIndex.Fingerprints;
using StellaOps.BinaryIndex.Fingerprints.Models;
using StellaOps.BinaryIndex.Persistence.Postgres;
using System.Collections.Immutable;
using System.Text.Json;
using SystemGuidProvider = StellaOps.Determinism.SystemGuidProvider;
@@ -10,12 +11,13 @@ using SystemGuidProvider = StellaOps.Determinism.SystemGuidProvider;
namespace StellaOps.BinaryIndex.Persistence.Repositories;
/// <summary>
/// Repository implementation for vulnerable fingerprints.
/// EF Core repository implementation for vulnerable fingerprints.
/// </summary>
public sealed class FingerprintRepository : IFingerprintRepository
{
private readonly BinaryIndexDbContext _dbContext;
private readonly IGuidProvider _guidProvider;
private const int CommandTimeoutSeconds = 30;
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
public FingerprintRepository(BinaryIndexDbContext dbContext, IGuidProvider? guidProvider = null)
@@ -27,92 +29,63 @@ public sealed class FingerprintRepository : IFingerprintRepository
public async Task<VulnFingerprint> CreateAsync(VulnFingerprint fingerprint, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
INSERT INTO binaries.vulnerable_fingerprints (
id, tenant_id, cve_id, component, purl, algorithm, fingerprint_id, fingerprint_hash,
architecture, function_name, source_file, source_line, similarity_threshold,
confidence, validated, validation_stats, vuln_build_ref, fixed_build_ref, indexed_at
)
VALUES (
@Id, binaries_app.require_current_tenant()::uuid, @CveId, @Component, @Purl, @Algorithm,
@FingerprintId, @FingerprintHash, @Architecture, @FunctionName, @SourceFile,
@SourceLine, @SimilarityThreshold, @Confidence, @Validated, @ValidationStats::jsonb,
@VulnBuildRef, @FixedBuildRef, @IndexedAt
)
RETURNING id
""";
var id = fingerprint.Id != Guid.Empty ? fingerprint.Id : _guidProvider.NewGuid();
var algorithm = ToDbAlgorithm(fingerprint.Algorithm);
var validationStats = fingerprint.ValidationStats != null
? JsonSerializer.Serialize(fingerprint.ValidationStats, JsonOptions)
: "{}";
var command = new CommandDefinition(
sql,
new
{
Id = fingerprint.Id != Guid.Empty ? fingerprint.Id : _guidProvider.NewGuid(),
fingerprint.CveId,
fingerprint.Component,
fingerprint.Purl,
Algorithm = ToDbAlgorithm(fingerprint.Algorithm),
fingerprint.FingerprintId,
fingerprint.FingerprintHash,
fingerprint.Architecture,
fingerprint.FunctionName,
fingerprint.SourceFile,
fingerprint.SourceLine,
fingerprint.SimilarityThreshold,
fingerprint.Confidence,
fingerprint.Validated,
ValidationStats = fingerprint.ValidationStats != null
? JsonSerializer.Serialize(fingerprint.ValidationStats, JsonOptions)
: "{}",
fingerprint.VulnBuildRef,
fingerprint.FixedBuildRef,
fingerprint.IndexedAt
},
cancellationToken: ct);
var id = await conn.ExecuteScalarAsync<Guid>(command);
var results = await efContext.VulnerableFingerprints
.FromSqlInterpolated($"""
INSERT INTO binaries.vulnerable_fingerprints (
id, tenant_id, cve_id, component, purl, algorithm, fingerprint_id, fingerprint_hash,
architecture, function_name, source_file, source_line, similarity_threshold,
confidence, validated, validation_stats, vuln_build_ref, fixed_build_ref, indexed_at
)
VALUES (
{id}, binaries_app.require_current_tenant()::uuid, {fingerprint.CveId}, {fingerprint.Component}, {fingerprint.Purl}, {algorithm},
{fingerprint.FingerprintId}, {fingerprint.FingerprintHash}, {fingerprint.Architecture}, {fingerprint.FunctionName}, {fingerprint.SourceFile},
{fingerprint.SourceLine}, {fingerprint.SimilarityThreshold}, {fingerprint.Confidence}, {fingerprint.Validated}, {validationStats}::jsonb,
{fingerprint.VulnBuildRef}, {fingerprint.FixedBuildRef}, {fingerprint.IndexedAt}
)
RETURNING id, tenant_id, cve_id, component, purl, algorithm, fingerprint_id, fingerprint_hash,
architecture, function_name, source_file, source_line, similarity_threshold,
confidence, validated, validation_stats, vuln_build_ref, fixed_build_ref,
notes, evidence_ref, indexed_at, created_at
""")
.AsNoTracking()
.ToListAsync(ct);
return fingerprint with { Id = id };
return ToModel(results.First());
}
public async Task<VulnFingerprint?> GetByIdAsync(Guid id, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT id, cve_id as CveId, component, purl, algorithm, fingerprint_id as FingerprintId,
fingerprint_hash as FingerprintHash, architecture, function_name as FunctionName,
source_file as SourceFile, source_line as SourceLine,
similarity_threshold as SimilarityThreshold, confidence, validated,
validation_stats as ValidationStats, vuln_build_ref as VulnBuildRef,
fixed_build_ref as FixedBuildRef, indexed_at as IndexedAt
FROM binaries.vulnerable_fingerprints
WHERE id = @Id
""";
var entity = await efContext.VulnerableFingerprints
.AsNoTracking()
.Where(e => e.Id == id)
.FirstOrDefaultAsync(ct);
var command = new CommandDefinition(sql, new { Id = id }, cancellationToken: ct);
var row = await conn.QuerySingleOrDefaultAsync<VulnFingerprintRow>(command);
return row?.ToModel();
return entity is null ? null : ToModel(entity);
}
public async Task<ImmutableArray<VulnFingerprint>> GetByCveAsync(string cveId, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT id, cve_id as CveId, component, purl, algorithm, fingerprint_id as FingerprintId,
fingerprint_hash as FingerprintHash, architecture, function_name as FunctionName,
source_file as SourceFile, source_line as SourceLine,
similarity_threshold as SimilarityThreshold, confidence, validated,
validation_stats as ValidationStats, vuln_build_ref as VulnBuildRef,
fixed_build_ref as FixedBuildRef, indexed_at as IndexedAt
FROM binaries.vulnerable_fingerprints
WHERE cve_id = @CveId
ORDER BY component, fingerprint_id
""";
var entities = await efContext.VulnerableFingerprints
.AsNoTracking()
.Where(e => e.CveId == cveId)
.OrderBy(e => e.Component).ThenBy(e => e.FingerprintId)
.ToListAsync(ct);
var command = new CommandDefinition(sql, new { CveId = cveId }, cancellationToken: ct);
var rows = await conn.QueryAsync<VulnFingerprintRow>(command);
return rows.Select(r => r.ToModel()).ToImmutableArray();
return entities.Select(ToModel).ToImmutableArray();
}
public async Task<ImmutableArray<VulnFingerprint>> SearchByHashAsync(
@@ -122,32 +95,21 @@ public sealed class FingerprintRepository : IFingerprintRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT id, cve_id as CveId, component, purl, algorithm, fingerprint_id as FingerprintId,
fingerprint_hash as FingerprintHash, architecture, function_name as FunctionName,
source_file as SourceFile, source_line as SourceLine,
similarity_threshold as SimilarityThreshold, confidence, validated,
validation_stats as ValidationStats, vuln_build_ref as VulnBuildRef,
fixed_build_ref as FixedBuildRef, indexed_at as IndexedAt
FROM binaries.vulnerable_fingerprints
WHERE fingerprint_hash = @Hash
AND algorithm = @Algorithm
AND (@Architecture IS NULL OR architecture = @Architecture)
""";
var dbAlgorithm = ToDbAlgorithm(algorithm);
var command = new CommandDefinition(
sql,
new
{
Hash = hash,
Algorithm = ToDbAlgorithm(algorithm),
Architecture = architecture
},
cancellationToken: ct);
var query = efContext.VulnerableFingerprints
.AsNoTracking()
.Where(e => e.FingerprintHash == hash && e.Algorithm == dbAlgorithm);
var rows = await conn.QueryAsync<VulnFingerprintRow>(command);
return rows.Select(r => r.ToModel()).ToImmutableArray();
if (architecture is not null)
{
query = query.Where(e => e.Architecture == architecture);
}
var entities = await query.ToListAsync(ct);
return entities.Select(ToModel).ToImmutableArray();
}
public async Task UpdateValidationStatsAsync(
@@ -156,24 +118,15 @@ public sealed class FingerprintRepository : IFingerprintRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
var statsJson = JsonSerializer.Serialize(stats, JsonOptions);
await efContext.Database.ExecuteSqlInterpolatedAsync($"""
UPDATE binaries.vulnerable_fingerprints
SET validation_stats = @Stats::jsonb,
SET validation_stats = {statsJson}::jsonb,
validated = TRUE
WHERE id = @Id
""";
var command = new CommandDefinition(
sql,
new
{
Id = id,
Stats = JsonSerializer.Serialize(stats, JsonOptions)
},
cancellationToken: ct);
await conn.ExecuteAsync(command);
WHERE id = {id}
""", ct);
}
private static string ToDbAlgorithm(FingerprintAlgorithm algorithm)
@@ -201,67 +154,46 @@ public sealed class FingerprintRepository : IFingerprintRepository
};
}
private sealed class VulnFingerprintRow
private static VulnFingerprint ToModel(EfCore.Models.VulnerableFingerprintEntity entity)
{
public Guid Id { get; init; }
public string CveId { get; init; } = string.Empty;
public string Component { get; init; } = string.Empty;
public string? Purl { get; init; }
public string Algorithm { get; init; } = string.Empty;
public string FingerprintId { get; init; } = string.Empty;
public byte[] FingerprintHash { get; init; } = Array.Empty<byte>();
public string Architecture { get; init; } = string.Empty;
public string? FunctionName { get; init; }
public string? SourceFile { get; init; }
public int? SourceLine { get; init; }
public decimal SimilarityThreshold { get; init; }
public decimal? Confidence { get; init; }
public bool Validated { get; init; }
public string? ValidationStats { get; init; }
public string? VulnBuildRef { get; init; }
public string? FixedBuildRef { get; init; }
public DateTimeOffset IndexedAt { get; init; }
public VulnFingerprint ToModel()
FingerprintValidationStats? stats = null;
if (!string.IsNullOrWhiteSpace(entity.ValidationStats))
{
FingerprintValidationStats? stats = null;
if (!string.IsNullOrWhiteSpace(ValidationStats))
{
stats = JsonSerializer.Deserialize<FingerprintValidationStats>(ValidationStats, JsonOptions);
}
return new VulnFingerprint
{
Id = Id,
CveId = CveId,
Component = Component,
Purl = Purl,
Algorithm = ParseAlgorithm(Algorithm),
FingerprintId = FingerprintId,
FingerprintHash = FingerprintHash,
Architecture = Architecture,
FunctionName = FunctionName,
SourceFile = SourceFile,
SourceLine = SourceLine,
SimilarityThreshold = SimilarityThreshold,
Confidence = Confidence,
Validated = Validated,
ValidationStats = stats,
VulnBuildRef = VulnBuildRef,
FixedBuildRef = FixedBuildRef,
IndexedAt = IndexedAt
};
stats = JsonSerializer.Deserialize<FingerprintValidationStats>(entity.ValidationStats, JsonOptions);
}
return new VulnFingerprint
{
Id = entity.Id,
CveId = entity.CveId,
Component = entity.Component,
Purl = entity.Purl,
Algorithm = ParseAlgorithm(entity.Algorithm),
FingerprintId = entity.FingerprintId,
FingerprintHash = entity.FingerprintHash,
Architecture = entity.Architecture,
FunctionName = entity.FunctionName,
SourceFile = entity.SourceFile,
SourceLine = entity.SourceLine,
SimilarityThreshold = entity.SimilarityThreshold ?? 0m,
Confidence = entity.Confidence,
Validated = entity.Validated ?? false,
ValidationStats = stats,
VulnBuildRef = entity.VulnBuildRef,
FixedBuildRef = entity.FixedBuildRef,
IndexedAt = new DateTimeOffset(entity.IndexedAt, TimeSpan.Zero)
};
}
}
/// <summary>
/// Repository implementation for fingerprint matches.
/// EF Core repository implementation for fingerprint matches.
/// </summary>
public sealed class FingerprintMatchRepository : IFingerprintMatchRepository
{
private readonly BinaryIndexDbContext _dbContext;
private readonly IGuidProvider _guidProvider;
private const int CommandTimeoutSeconds = 30;
public FingerprintMatchRepository(BinaryIndexDbContext dbContext, IGuidProvider? guidProvider = null)
{
@@ -272,43 +204,34 @@ public sealed class FingerprintMatchRepository : IFingerprintMatchRepository
public async Task<FingerprintMatch> CreateAsync(FingerprintMatch match, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
INSERT INTO binaries.fingerprint_matches (
id, tenant_id, scan_id, match_type, binary_key, binary_identity_id,
vulnerable_purl, vulnerable_version, matched_fingerprint_id, matched_function,
similarity, advisory_ids, reachability_status, matched_at
)
VALUES (
@Id, binaries_app.require_current_tenant()::uuid, @ScanId, @MatchType, @BinaryKey,
@BinaryIdentityId, @VulnerablePurl, @VulnerableVersion, @MatchedFingerprintId,
@MatchedFunction, @Similarity, @AdvisoryIds, @ReachabilityStatus, @MatchedAt
)
RETURNING id
""";
var id = match.Id != Guid.Empty ? match.Id : _guidProvider.NewGuid();
var matchType = match.Type.ToString().ToLowerInvariant();
var advisoryIds = match.AdvisoryIds.IsDefaultOrEmpty ? null : match.AdvisoryIds.ToArray();
var reachabilityStatus = match.ReachabilityStatus?.ToString().ToLowerInvariant();
var command = new CommandDefinition(
sql,
new
{
Id = match.Id != Guid.Empty ? match.Id : _guidProvider.NewGuid(),
match.ScanId,
MatchType = match.Type.ToString().ToLowerInvariant(),
match.BinaryKey,
BinaryIdentityId = (Guid?)null,
match.VulnerablePurl,
match.VulnerableVersion,
match.MatchedFingerprintId,
match.MatchedFunction,
match.Similarity,
AdvisoryIds = match.AdvisoryIds.IsDefaultOrEmpty ? null : match.AdvisoryIds.ToArray(),
ReachabilityStatus = match.ReachabilityStatus?.ToString().ToLowerInvariant(),
match.MatchedAt
},
cancellationToken: ct);
var id = await conn.ExecuteScalarAsync<Guid>(command);
var results = await efContext.FingerprintMatches
.FromSqlInterpolated($"""
INSERT INTO binaries.fingerprint_matches (
id, tenant_id, scan_id, match_type, binary_key, binary_identity_id,
vulnerable_purl, vulnerable_version, matched_fingerprint_id, matched_function,
similarity, advisory_ids, reachability_status, matched_at
)
VALUES (
{id}, binaries_app.require_current_tenant()::uuid, {match.ScanId}, {matchType}, {match.BinaryKey},
{(Guid?)null}, {match.VulnerablePurl}, {match.VulnerableVersion}, {match.MatchedFingerprintId},
{match.MatchedFunction}, {match.Similarity}, {advisoryIds}, {reachabilityStatus}, {match.MatchedAt}
)
RETURNING id, tenant_id, scan_id, match_type, binary_key, binary_identity_id,
vulnerable_purl, vulnerable_version, matched_fingerprint_id, matched_function,
similarity, advisory_ids, reachability_status, evidence, matched_at, created_at
""")
.AsNoTracking()
.ToListAsync(ct);
return match with { Id = id };
var row = results.First();
return match with { Id = row.Id };
}
public async Task<ImmutableArray<FingerprintMatch>> GetByScanAsync(Guid scanId, CancellationToken ct = default)
@@ -320,21 +243,13 @@ public sealed class FingerprintMatchRepository : IFingerprintMatchRepository
public async Task UpdateReachabilityAsync(Guid id, ReachabilityStatus status, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
var statusStr = status.ToString().ToLowerInvariant();
await efContext.Database.ExecuteSqlInterpolatedAsync($"""
UPDATE binaries.fingerprint_matches
SET reachability_status = @Status
WHERE id = @Id
""";
var command = new CommandDefinition(
sql,
new
{
Id = id,
Status = status.ToString().ToLowerInvariant()
},
cancellationToken: ct);
await conn.ExecuteAsync(command);
SET reachability_status = {statusStr}
WHERE id = {id}
""", ct);
}
}

View File

@@ -1,19 +1,20 @@
using Npgsql;
using NpgsqlTypes;
using Microsoft.EntityFrameworkCore;
using StellaOps.BinaryIndex.Core.Models;
using StellaOps.BinaryIndex.FixIndex.Models;
using StellaOps.BinaryIndex.FixIndex.Repositories;
using StellaOps.BinaryIndex.Persistence.Postgres;
using System.Text.Json;
namespace StellaOps.BinaryIndex.Persistence.Repositories;
/// <summary>
/// PostgreSQL implementation of <see cref="IFixIndexRepository"/>.
/// EF Core implementation of <see cref="IFixIndexRepository"/>.
/// </summary>
public sealed class FixIndexRepository : IFixIndexRepository
{
private readonly BinaryIndexDbContext _dbContext;
private const int CommandTimeoutSeconds = 30;
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web)
{
@@ -33,28 +34,16 @@ public sealed class FixIndexRepository : IFixIndexRepository
string cveId,
CancellationToken cancellationToken = default)
{
const string sql = """
SELECT id, distro, release, source_pkg, cve_id, state, fixed_version,
method, confidence, evidence_id, snapshot_id, indexed_at, updated_at
FROM binaries.cve_fix_index
WHERE distro = @distro AND release = @release
AND source_pkg = @sourcePkg AND cve_id = @cveId
""";
await using var conn = await _dbContext.OpenConnectionAsync(cancellationToken);
await using var cmd = new NpgsqlCommand(sql, conn);
cmd.Parameters.AddWithValue("distro", distro);
cmd.Parameters.AddWithValue("release", release);
cmd.Parameters.AddWithValue("sourcePkg", sourcePkg);
cmd.Parameters.AddWithValue("cveId", cveId);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
await using var reader = await cmd.ExecuteReaderAsync(cancellationToken);
if (await reader.ReadAsync(cancellationToken))
{
return MapToFixIndexEntry(reader);
}
var entity = await efContext.CveFixIndexes
.AsNoTracking()
.Where(e => e.Distro == distro && e.Release == release
&& e.SourcePkg == sourcePkg && e.CveId == cveId)
.FirstOrDefaultAsync(cancellationToken);
return null;
return entity is null ? null : ToModel(entity);
}
/// <inheritdoc />
@@ -64,28 +53,16 @@ public sealed class FixIndexRepository : IFixIndexRepository
string sourcePkg,
CancellationToken cancellationToken = default)
{
const string sql = """
SELECT id, distro, release, source_pkg, cve_id, state, fixed_version,
method, confidence, evidence_id, snapshot_id, indexed_at, updated_at
FROM binaries.cve_fix_index
WHERE distro = @distro AND release = @release AND source_pkg = @sourcePkg
ORDER BY cve_id
""";
await using var conn = await _dbContext.OpenConnectionAsync(cancellationToken);
await using var cmd = new NpgsqlCommand(sql, conn);
cmd.Parameters.AddWithValue("distro", distro);
cmd.Parameters.AddWithValue("release", release);
cmd.Parameters.AddWithValue("sourcePkg", sourcePkg);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
var results = new List<FixIndexEntry>();
await using var reader = await cmd.ExecuteReaderAsync(cancellationToken);
while (await reader.ReadAsync(cancellationToken))
{
results.Add(MapToFixIndexEntry(reader));
}
var entities = await efContext.CveFixIndexes
.AsNoTracking()
.Where(e => e.Distro == distro && e.Release == release && e.SourcePkg == sourcePkg)
.OrderBy(e => e.CveId)
.ToListAsync(cancellationToken);
return results;
return entities.Select(ToModel).ToList();
}
/// <inheritdoc />
@@ -93,26 +70,16 @@ public sealed class FixIndexRepository : IFixIndexRepository
string cveId,
CancellationToken cancellationToken = default)
{
const string sql = """
SELECT id, distro, release, source_pkg, cve_id, state, fixed_version,
method, confidence, evidence_id, snapshot_id, indexed_at, updated_at
FROM binaries.cve_fix_index
WHERE cve_id = @cveId
ORDER BY distro, release, source_pkg
""";
await using var conn = await _dbContext.OpenConnectionAsync(cancellationToken);
await using var cmd = new NpgsqlCommand(sql, conn);
cmd.Parameters.AddWithValue("cveId", cveId);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
var results = new List<FixIndexEntry>();
await using var reader = await cmd.ExecuteReaderAsync(cancellationToken);
while (await reader.ReadAsync(cancellationToken))
{
results.Add(MapToFixIndexEntry(reader));
}
var entities = await efContext.CveFixIndexes
.AsNoTracking()
.Where(e => e.CveId == cveId)
.OrderBy(e => e.Distro).ThenBy(e => e.Release).ThenBy(e => e.SourcePkg)
.ToListAsync(cancellationToken);
return results;
return entities.Select(ToModel).ToList();
}
/// <inheritdoc />
@@ -123,47 +90,40 @@ public sealed class FixIndexRepository : IFixIndexRepository
// First store evidence
var evidenceId = await StoreEvidenceAsync(evidence, cancellationToken);
const string sql = """
INSERT INTO binaries.cve_fix_index
(distro, release, source_pkg, cve_id, architecture, state, fixed_version, method, confidence, evidence_id, snapshot_id)
VALUES
(@distro, @release, @sourcePkg, @cveId, @architecture, @state, @fixedVersion, @method, @confidence, @evidenceId, @snapshotId)
ON CONFLICT (tenant_id, distro, release, source_pkg, cve_id, architecture)
DO UPDATE SET
state = EXCLUDED.state,
fixed_version = EXCLUDED.fixed_version,
method = CASE
WHEN binaries.cve_fix_index.confidence < EXCLUDED.confidence THEN EXCLUDED.method
ELSE binaries.cve_fix_index.method
END,
confidence = GREATEST(binaries.cve_fix_index.confidence, EXCLUDED.confidence),
evidence_id = CASE
WHEN binaries.cve_fix_index.confidence < EXCLUDED.confidence THEN EXCLUDED.evidence_id
ELSE binaries.cve_fix_index.evidence_id
END,
snapshot_id = EXCLUDED.snapshot_id,
updated_at = now()
RETURNING id, distro, release, source_pkg, cve_id, state, fixed_version,
method, confidence, evidence_id, snapshot_id, indexed_at, updated_at
""";
await using var conn = await _dbContext.OpenConnectionAsync(cancellationToken);
await using var cmd = new NpgsqlCommand(sql, conn);
cmd.Parameters.AddWithValue("distro", evidence.Distro);
cmd.Parameters.AddWithValue("release", evidence.Release);
cmd.Parameters.AddWithValue("sourcePkg", evidence.SourcePkg);
cmd.Parameters.AddWithValue("cveId", evidence.CveId);
cmd.Parameters.AddWithValue("architecture", DBNull.Value);
cmd.Parameters.AddWithValue("state", evidence.State.ToString().ToLowerInvariant());
cmd.Parameters.AddWithValue("fixedVersion", (object?)evidence.FixedVersion ?? DBNull.Value);
cmd.Parameters.AddWithValue("method", ToDbFixMethod(evidence.Method));
cmd.Parameters.AddWithValue("confidence", evidence.Confidence);
cmd.Parameters.AddWithValue("evidenceId", evidenceId);
cmd.Parameters.AddWithValue("snapshotId", (object?)evidence.SnapshotId ?? DBNull.Value);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
await using var reader = await cmd.ExecuteReaderAsync(cancellationToken);
await reader.ReadAsync(cancellationToken);
return MapToFixIndexEntry(reader);
var state = evidence.State.ToString().ToLowerInvariant();
var method = ToDbFixMethod(evidence.Method);
var results = await efContext.CveFixIndexes
.FromSqlInterpolated($"""
INSERT INTO binaries.cve_fix_index
(distro, release, source_pkg, cve_id, architecture, state, fixed_version, method, confidence, evidence_id, snapshot_id)
VALUES
({evidence.Distro}, {evidence.Release}, {evidence.SourcePkg}, {evidence.CveId}, {(string?)null}, {state}, {evidence.FixedVersion}, {method}, {evidence.Confidence}, {evidenceId}, {evidence.SnapshotId})
ON CONFLICT (tenant_id, distro, release, source_pkg, cve_id, architecture)
DO UPDATE SET
state = EXCLUDED.state,
fixed_version = EXCLUDED.fixed_version,
method = CASE
WHEN binaries.cve_fix_index.confidence < EXCLUDED.confidence THEN EXCLUDED.method
ELSE binaries.cve_fix_index.method
END,
confidence = GREATEST(binaries.cve_fix_index.confidence, EXCLUDED.confidence),
evidence_id = CASE
WHEN binaries.cve_fix_index.confidence < EXCLUDED.confidence THEN EXCLUDED.evidence_id
ELSE binaries.cve_fix_index.evidence_id
END,
snapshot_id = EXCLUDED.snapshot_id,
updated_at = now()
RETURNING id, tenant_id, distro, release, source_pkg, cve_id, architecture,
state, fixed_version, method, confidence, evidence_id, snapshot_id, indexed_at, updated_at
""")
.AsNoTracking()
.ToListAsync(cancellationToken);
return ToModel(results.First());
}
/// <inheritdoc />
@@ -187,24 +147,22 @@ public sealed class FixIndexRepository : IFixIndexRepository
{
var (evidenceType, sourceFile, excerpt, metadata) = MapEvidencePayload(evidence.Evidence);
const string sql = """
INSERT INTO binaries.fix_evidence
(evidence_type, source_file, excerpt, metadata, snapshot_id)
VALUES
(@evidenceType, @sourceFile, @excerpt, @metadata::jsonb, @snapshotId)
RETURNING id
""";
await using var conn = await _dbContext.OpenConnectionAsync(cancellationToken);
await using var cmd = new NpgsqlCommand(sql, conn);
cmd.Parameters.AddWithValue("evidenceType", evidenceType);
cmd.Parameters.AddWithValue("sourceFile", (object?)sourceFile ?? DBNull.Value);
cmd.Parameters.AddWithValue("excerpt", (object?)excerpt ?? DBNull.Value);
cmd.Parameters.AddWithValue("metadata", NpgsqlDbType.Jsonb, metadata);
cmd.Parameters.AddWithValue("snapshotId", (object?)evidence.SnapshotId ?? DBNull.Value);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
var result = await cmd.ExecuteScalarAsync(cancellationToken);
return (Guid)result!;
var results = await efContext.FixEvidences
.FromSqlInterpolated($"""
INSERT INTO binaries.fix_evidence
(evidence_type, source_file, excerpt, metadata, snapshot_id)
VALUES
({evidenceType}, {sourceFile}, {excerpt}, {metadata}::jsonb, {evidence.SnapshotId})
RETURNING id, tenant_id, evidence_type, source_file, source_sha256, excerpt,
metadata, snapshot_id, created_at
""")
.AsNoTracking()
.ToListAsync(cancellationToken);
return results.First().Id;
}
/// <inheritdoc />
@@ -212,33 +170,30 @@ public sealed class FixIndexRepository : IFixIndexRepository
Guid evidenceId,
CancellationToken cancellationToken = default)
{
const string sql = """
SELECT id, evidence_type, source_file, source_sha256, excerpt, metadata::text, snapshot_id, created_at
FROM binaries.fix_evidence
WHERE id = @id
""";
await using var conn = await _dbContext.OpenConnectionAsync(cancellationToken);
await using var cmd = new NpgsqlCommand(sql, conn);
cmd.Parameters.AddWithValue("id", evidenceId);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
await using var reader = await cmd.ExecuteReaderAsync(cancellationToken);
if (await reader.ReadAsync(cancellationToken))
var entity = await efContext.FixEvidences
.AsNoTracking()
.Where(e => e.Id == evidenceId)
.FirstOrDefaultAsync(cancellationToken);
if (entity is null)
{
return new FixEvidenceRecord
{
Id = reader.GetGuid(0),
EvidenceType = reader.GetString(1),
SourceFile = reader.IsDBNull(2) ? null : reader.GetString(2),
SourceSha256 = reader.IsDBNull(3) ? null : reader.GetString(3),
Excerpt = reader.IsDBNull(4) ? null : reader.GetString(4),
MetadataJson = reader.GetString(5),
SnapshotId = reader.IsDBNull(6) ? null : reader.GetGuid(6),
CreatedAt = reader.GetFieldValue<DateTimeOffset>(7)
};
return null;
}
return null;
return new FixEvidenceRecord
{
Id = entity.Id,
EvidenceType = entity.EvidenceType,
SourceFile = entity.SourceFile,
SourceSha256 = entity.SourceSha256,
Excerpt = entity.Excerpt,
MetadataJson = entity.Metadata,
SnapshotId = entity.SnapshotId,
CreatedAt = new DateTimeOffset(entity.CreatedAt, TimeSpan.Zero)
};
}
/// <inheritdoc />
@@ -246,41 +201,41 @@ public sealed class FixIndexRepository : IFixIndexRepository
Guid snapshotId,
CancellationToken cancellationToken = default)
{
const string sql = """
await using var conn = await _dbContext.OpenConnectionAsync(cancellationToken);
await using var efContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
// Use raw SQL for the CTE-based multi-table delete
var result = await efContext.Database.SqlQueryRaw<int>("""
WITH deleted_index AS (
DELETE FROM binaries.cve_fix_index WHERE snapshot_id = @snapshotId RETURNING 1
DELETE FROM binaries.cve_fix_index WHERE snapshot_id = @p0 RETURNING 1
),
deleted_evidence AS (
DELETE FROM binaries.fix_evidence WHERE snapshot_id = @snapshotId RETURNING 1
DELETE FROM binaries.fix_evidence WHERE snapshot_id = @p0 RETURNING 1
)
SELECT (SELECT COUNT(*) FROM deleted_index) + (SELECT COUNT(*) FROM deleted_evidence)
""";
SELECT CAST((SELECT COUNT(*) FROM deleted_index) + (SELECT COUNT(*) FROM deleted_evidence) AS integer) AS "Value"
""", snapshotId)
.ToListAsync(cancellationToken);
await using var conn = await _dbContext.OpenConnectionAsync(cancellationToken);
await using var cmd = new NpgsqlCommand(sql, conn);
cmd.Parameters.AddWithValue("snapshotId", snapshotId);
var result = await cmd.ExecuteScalarAsync(cancellationToken);
return Convert.ToInt32(result);
return result.FirstOrDefault();
}
private static FixIndexEntry MapToFixIndexEntry(NpgsqlDataReader reader)
private static FixIndexEntry ToModel(EfCore.Models.CveFixIndexEntity entity)
{
return new FixIndexEntry
{
Id = reader.GetGuid(0),
Distro = reader.GetString(1),
Release = reader.GetString(2),
SourcePkg = reader.GetString(3),
CveId = reader.GetString(4),
State = Enum.Parse<FixState>(reader.GetString(5), ignoreCase: true),
FixedVersion = reader.IsDBNull(6) ? null : reader.GetString(6),
Method = ParseFixMethod(reader.GetString(7)),
Confidence = reader.GetDecimal(8),
EvidenceId = reader.IsDBNull(9) ? null : reader.GetGuid(9),
SnapshotId = reader.IsDBNull(10) ? null : reader.GetGuid(10),
IndexedAt = reader.GetFieldValue<DateTimeOffset>(11),
UpdatedAt = reader.GetFieldValue<DateTimeOffset>(12)
Id = entity.Id,
Distro = entity.Distro,
Release = entity.Release,
SourcePkg = entity.SourcePkg,
CveId = entity.CveId,
State = Enum.Parse<FixState>(entity.State, ignoreCase: true),
FixedVersion = entity.FixedVersion,
Method = ParseFixMethod(entity.Method),
Confidence = entity.Confidence,
EvidenceId = entity.EvidenceId,
SnapshotId = entity.SnapshotId,
IndexedAt = new DateTimeOffset(entity.IndexedAt, TimeSpan.Zero),
UpdatedAt = new DateTimeOffset(entity.UpdatedAt, TimeSpan.Zero)
};
}

View File

@@ -1,13 +1,16 @@
using Dapper;
using Microsoft.EntityFrameworkCore;
using StellaOps.BinaryIndex.Persistence.Postgres;
using EfModels = StellaOps.BinaryIndex.Persistence.EfCore.Models;
namespace StellaOps.BinaryIndex.Persistence.Repositories.GroundTruth;
/// <summary>
/// Repository implementation for raw document storage (immutable, append-only).
/// EF Core repository implementation for raw document storage (immutable, append-only).
/// </summary>
public sealed class RawDocumentRepository : IRawDocumentRepository
{
private readonly BinaryIndexDbContext _dbContext;
private const int CommandTimeoutSeconds = 30;
public RawDocumentRepository(BinaryIndexDbContext dbContext)
{
@@ -18,38 +21,25 @@ public sealed class RawDocumentRepository : IRawDocumentRepository
public async Task<RawDocumentEntity?> GetByDigestAsync(string digest, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT digest AS "Digest",
source_id AS "SourceId",
document_uri AS "DocumentUri",
content_type AS "ContentType",
content_size AS "ContentSize",
etag AS "ETag",
fetched_at AS "FetchedAt",
recorded_at AS "RecordedAt",
status AS "Status",
payload_id AS "PayloadId",
metadata::text AS "MetadataJson"
FROM groundtruth.raw_documents
WHERE digest = @Digest
""";
var entity = await dbContext.RawDocuments
.AsNoTracking()
.Where(e => e.Digest == digest)
.FirstOrDefaultAsync(ct);
var command = new CommandDefinition(sql, new { Digest = digest }, cancellationToken: ct);
return await conn.QuerySingleOrDefaultAsync<RawDocumentEntity>(command);
return entity is null ? null : ToModel(entity);
}
/// <inheritdoc/>
public async Task<bool> ExistsAsync(string digest, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT EXISTS(SELECT 1 FROM groundtruth.raw_documents WHERE digest = @Digest)
""";
var command = new CommandDefinition(sql, new { Digest = digest }, cancellationToken: ct);
return await conn.QuerySingleAsync<bool>(command);
return await dbContext.RawDocuments
.AsNoTracking()
.AnyAsync(e => e.Digest == digest, ct);
}
/// <inheritdoc/>
@@ -59,28 +49,16 @@ public sealed class RawDocumentRepository : IRawDocumentRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT digest AS "Digest",
source_id AS "SourceId",
document_uri AS "DocumentUri",
content_type AS "ContentType",
content_size AS "ContentSize",
etag AS "ETag",
fetched_at AS "FetchedAt",
recorded_at AS "RecordedAt",
status AS "Status",
payload_id AS "PayloadId",
metadata::text AS "MetadataJson"
FROM groundtruth.raw_documents
WHERE source_id = @SourceId AND status = 'pending_parse'
ORDER BY fetched_at ASC
LIMIT @Limit
""";
var entities = await dbContext.RawDocuments
.AsNoTracking()
.Where(e => e.SourceId == sourceId && e.Status == "pending_parse")
.OrderBy(e => e.FetchedAt)
.Take(limit)
.ToListAsync(ct);
var command = new CommandDefinition(sql, new { SourceId = sourceId, Limit = limit }, cancellationToken: ct);
var rows = await conn.QueryAsync<RawDocumentEntity>(command);
return rows.ToList();
return entities.Select(ToModel).ToList();
}
/// <inheritdoc/>
@@ -90,65 +68,36 @@ public sealed class RawDocumentRepository : IRawDocumentRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT digest AS "Digest",
source_id AS "SourceId",
document_uri AS "DocumentUri",
content_type AS "ContentType",
content_size AS "ContentSize",
etag AS "ETag",
fetched_at AS "FetchedAt",
recorded_at AS "RecordedAt",
status AS "Status",
payload_id AS "PayloadId",
metadata::text AS "MetadataJson"
FROM groundtruth.raw_documents
WHERE source_id = @SourceId AND status = 'pending_map'
ORDER BY fetched_at ASC
LIMIT @Limit
""";
var entities = await dbContext.RawDocuments
.AsNoTracking()
.Where(e => e.SourceId == sourceId && e.Status == "pending_map")
.OrderBy(e => e.FetchedAt)
.Take(limit)
.ToListAsync(ct);
var command = new CommandDefinition(sql, new { SourceId = sourceId, Limit = limit }, cancellationToken: ct);
var rows = await conn.QueryAsync<RawDocumentEntity>(command);
return rows.ToList();
return entities.Select(ToModel).ToList();
}
/// <inheritdoc/>
public async Task<bool> InsertAsync(RawDocumentEntity document, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
var now = DateTimeOffset.UtcNow;
var affected = await dbContext.Database.ExecuteSqlInterpolatedAsync($"""
INSERT INTO groundtruth.raw_documents (
digest, source_id, document_uri, content_type, content_size,
etag, fetched_at, recorded_at, status, payload_id, metadata
) VALUES (
@Digest, @SourceId, @DocumentUri, @ContentType, @ContentSize,
@ETag, @FetchedAt, @Now, @Status, @PayloadId, @MetadataJson::jsonb
{document.Digest}, {document.SourceId}, {document.DocumentUri}, {document.ContentType}, {document.ContentSize},
{document.ETag}, {document.FetchedAt}, {now}, {document.Status}, {document.PayloadId}, {document.MetadataJson}::jsonb
)
ON CONFLICT (digest) DO NOTHING
""";
""", ct);
var command = new CommandDefinition(
sql,
new
{
document.Digest,
document.SourceId,
document.DocumentUri,
document.ContentType,
document.ContentSize,
document.ETag,
document.FetchedAt,
Now = DateTimeOffset.UtcNow,
document.Status,
document.PayloadId,
document.MetadataJson
},
cancellationToken: ct);
var affected = await conn.ExecuteAsync(command);
return affected > 0;
}
@@ -156,15 +105,13 @@ public sealed class RawDocumentRepository : IRawDocumentRepository
public async Task UpdateStatusAsync(string digest, string status, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
await dbContext.Database.ExecuteSqlInterpolatedAsync($"""
UPDATE groundtruth.raw_documents
SET status = @Status
WHERE digest = @Digest
""";
var command = new CommandDefinition(sql, new { Digest = digest, Status = status }, cancellationToken: ct);
await conn.ExecuteAsync(command);
SET status = {status}
WHERE digest = {digest}
""", ct);
}
/// <inheritdoc/>
@@ -173,16 +120,30 @@ public sealed class RawDocumentRepository : IRawDocumentRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT status AS "Status", COUNT(*) AS "Count"
FROM groundtruth.raw_documents
WHERE source_id = @SourceId
GROUP BY status
""";
var groups = await dbContext.RawDocuments
.AsNoTracking()
.Where(e => e.SourceId == sourceId)
.GroupBy(e => e.Status)
.Select(g => new { Status = g.Key, Count = (long)g.Count() })
.ToListAsync(ct);
var command = new CommandDefinition(sql, new { SourceId = sourceId }, cancellationToken: ct);
var rows = await conn.QueryAsync<(string Status, long Count)>(command);
return rows.ToDictionary(r => r.Status, r => r.Count);
return groups.ToDictionary(g => g.Status, g => g.Count);
}
private static RawDocumentEntity ToModel(EfModels.RawDocumentEntity entity) => new()
{
Digest = entity.Digest,
SourceId = entity.SourceId,
DocumentUri = entity.DocumentUri,
ContentType = entity.ContentType,
ContentSize = entity.ContentSize,
ETag = entity.Etag,
FetchedAt = new DateTimeOffset(entity.FetchedAt, TimeSpan.Zero),
RecordedAt = new DateTimeOffset(entity.RecordedAt, TimeSpan.Zero),
Status = entity.Status,
PayloadId = entity.PayloadId,
MetadataJson = entity.Metadata
};
}

View File

@@ -1,13 +1,16 @@
using Dapper;
using Microsoft.EntityFrameworkCore;
using StellaOps.BinaryIndex.Persistence.Postgres;
using EfModels = StellaOps.BinaryIndex.Persistence.EfCore.Models;
namespace StellaOps.BinaryIndex.Persistence.Repositories.GroundTruth;
/// <summary>
/// Repository implementation for security pair (pre/post CVE binary) management.
/// EF Core repository implementation for security pair (pre/post CVE binary) management.
/// </summary>
public sealed class SecurityPairRepository : ISecurityPairRepository
{
private readonly BinaryIndexDbContext _dbContext;
private const int CommandTimeoutSeconds = 30;
public SecurityPairRepository(BinaryIndexDbContext dbContext)
{
@@ -18,65 +21,29 @@ public sealed class SecurityPairRepository : ISecurityPairRepository
public async Task<SecurityPairEntity?> GetByIdAsync(Guid pairId, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT pair_id AS "PairId",
cve_id AS "CveId",
package_name AS "PackageName",
distro AS "Distro",
distro_version AS "DistroVersion",
vulnerable_version AS "VulnerableVersion",
vulnerable_debug_id AS "VulnerableDebugId",
vulnerable_observation_id AS "VulnerableObservationId",
fixed_version AS "FixedVersion",
fixed_debug_id AS "FixedDebugId",
fixed_observation_id AS "FixedObservationId",
upstream_diff_url AS "UpstreamDiffUrl",
patch_functions AS "PatchFunctions",
verification_status AS "VerificationStatus",
metadata::text AS "MetadataJson",
created_at AS "CreatedAt",
updated_at AS "UpdatedAt"
FROM groundtruth.security_pairs
WHERE pair_id = @PairId
""";
var entity = await dbContext.SecurityPairs
.AsNoTracking()
.Where(e => e.PairId == pairId)
.FirstOrDefaultAsync(ct);
var command = new CommandDefinition(sql, new { PairId = pairId }, cancellationToken: ct);
var row = await conn.QuerySingleOrDefaultAsync<SecurityPairRow>(command);
return row?.ToEntity();
return entity is null ? null : ToModel(entity);
}
/// <inheritdoc/>
public async Task<IReadOnlyList<SecurityPairEntity>> GetByCveAsync(string cveId, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT pair_id AS "PairId",
cve_id AS "CveId",
package_name AS "PackageName",
distro AS "Distro",
distro_version AS "DistroVersion",
vulnerable_version AS "VulnerableVersion",
vulnerable_debug_id AS "VulnerableDebugId",
vulnerable_observation_id AS "VulnerableObservationId",
fixed_version AS "FixedVersion",
fixed_debug_id AS "FixedDebugId",
fixed_observation_id AS "FixedObservationId",
upstream_diff_url AS "UpstreamDiffUrl",
patch_functions AS "PatchFunctions",
verification_status AS "VerificationStatus",
metadata::text AS "MetadataJson",
created_at AS "CreatedAt",
updated_at AS "UpdatedAt"
FROM groundtruth.security_pairs
WHERE cve_id = @CveId
ORDER BY package_name, distro
""";
var entities = await dbContext.SecurityPairs
.AsNoTracking()
.Where(e => e.CveId == cveId)
.OrderBy(e => e.PackageName).ThenBy(e => e.Distro)
.ToListAsync(ct);
var command = new CommandDefinition(sql, new { CveId = cveId }, cancellationToken: ct);
var rows = await conn.QueryAsync<SecurityPairRow>(command);
return rows.Select(r => r.ToEntity()).ToList();
return entities.Select(ToModel).ToList();
}
/// <inheritdoc/>
@@ -86,37 +53,22 @@ public sealed class SecurityPairRepository : ISecurityPairRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT pair_id AS "PairId",
cve_id AS "CveId",
package_name AS "PackageName",
distro AS "Distro",
distro_version AS "DistroVersion",
vulnerable_version AS "VulnerableVersion",
vulnerable_debug_id AS "VulnerableDebugId",
vulnerable_observation_id AS "VulnerableObservationId",
fixed_version AS "FixedVersion",
fixed_debug_id AS "FixedDebugId",
fixed_observation_id AS "FixedObservationId",
upstream_diff_url AS "UpstreamDiffUrl",
patch_functions AS "PatchFunctions",
verification_status AS "VerificationStatus",
metadata::text AS "MetadataJson",
created_at AS "CreatedAt",
updated_at AS "UpdatedAt"
FROM groundtruth.security_pairs
WHERE package_name = @PackageName
AND (@Distro IS NULL OR distro = @Distro)
ORDER BY cve_id, distro
""";
var query = dbContext.SecurityPairs
.AsNoTracking()
.Where(e => e.PackageName == packageName);
var command = new CommandDefinition(
sql,
new { PackageName = packageName, Distro = distro },
cancellationToken: ct);
var rows = await conn.QueryAsync<SecurityPairRow>(command);
return rows.Select(r => r.ToEntity()).ToList();
if (distro is not null)
{
query = query.Where(e => e.Distro == distro);
}
var entities = await query
.OrderBy(e => e.CveId).ThenBy(e => e.Distro)
.ToListAsync(ct);
return entities.Select(ToModel).ToList();
}
/// <inheritdoc/>
@@ -125,108 +77,62 @@ public sealed class SecurityPairRepository : ISecurityPairRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT pair_id AS "PairId",
cve_id AS "CveId",
package_name AS "PackageName",
distro AS "Distro",
distro_version AS "DistroVersion",
vulnerable_version AS "VulnerableVersion",
vulnerable_debug_id AS "VulnerableDebugId",
vulnerable_observation_id AS "VulnerableObservationId",
fixed_version AS "FixedVersion",
fixed_debug_id AS "FixedDebugId",
fixed_observation_id AS "FixedObservationId",
upstream_diff_url AS "UpstreamDiffUrl",
patch_functions AS "PatchFunctions",
verification_status AS "VerificationStatus",
metadata::text AS "MetadataJson",
created_at AS "CreatedAt",
updated_at AS "UpdatedAt"
FROM groundtruth.security_pairs
WHERE verification_status = 'pending'
ORDER BY created_at ASC
LIMIT @Limit
""";
var entities = await dbContext.SecurityPairs
.AsNoTracking()
.Where(e => e.VerificationStatus == "pending")
.OrderBy(e => e.CreatedAt)
.Take(limit)
.ToListAsync(ct);
var command = new CommandDefinition(sql, new { Limit = limit }, cancellationToken: ct);
var rows = await conn.QueryAsync<SecurityPairRow>(command);
return rows.Select(r => r.ToEntity()).ToList();
return entities.Select(ToModel).ToList();
}
/// <inheritdoc/>
public async Task<SecurityPairEntity> UpsertAsync(SecurityPairEntity pair, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
INSERT INTO groundtruth.security_pairs (
cve_id, package_name, distro, distro_version,
vulnerable_version, vulnerable_debug_id, vulnerable_observation_id,
fixed_version, fixed_debug_id, fixed_observation_id,
upstream_diff_url, patch_functions, verification_status, metadata,
created_at, updated_at
) VALUES (
@CveId, @PackageName, @Distro, @DistroVersion,
@VulnerableVersion, @VulnerableDebugId, @VulnerableObservationId,
@FixedVersion, @FixedDebugId, @FixedObservationId,
@UpstreamDiffUrl, @PatchFunctions, @VerificationStatus, @MetadataJson::jsonb,
@Now, @Now
)
ON CONFLICT (cve_id, package_name, distro, vulnerable_version, fixed_version) DO UPDATE SET
distro_version = EXCLUDED.distro_version,
vulnerable_debug_id = COALESCE(EXCLUDED.vulnerable_debug_id, groundtruth.security_pairs.vulnerable_debug_id),
vulnerable_observation_id = COALESCE(EXCLUDED.vulnerable_observation_id, groundtruth.security_pairs.vulnerable_observation_id),
fixed_debug_id = COALESCE(EXCLUDED.fixed_debug_id, groundtruth.security_pairs.fixed_debug_id),
fixed_observation_id = COALESCE(EXCLUDED.fixed_observation_id, groundtruth.security_pairs.fixed_observation_id),
upstream_diff_url = COALESCE(EXCLUDED.upstream_diff_url, groundtruth.security_pairs.upstream_diff_url),
patch_functions = COALESCE(EXCLUDED.patch_functions, groundtruth.security_pairs.patch_functions),
metadata = COALESCE(EXCLUDED.metadata, groundtruth.security_pairs.metadata),
updated_at = EXCLUDED.updated_at
RETURNING pair_id AS "PairId",
cve_id AS "CveId",
package_name AS "PackageName",
distro AS "Distro",
distro_version AS "DistroVersion",
vulnerable_version AS "VulnerableVersion",
vulnerable_debug_id AS "VulnerableDebugId",
vulnerable_observation_id AS "VulnerableObservationId",
fixed_version AS "FixedVersion",
fixed_debug_id AS "FixedDebugId",
fixed_observation_id AS "FixedObservationId",
upstream_diff_url AS "UpstreamDiffUrl",
patch_functions AS "PatchFunctions",
verification_status AS "VerificationStatus",
metadata::text AS "MetadataJson",
created_at AS "CreatedAt",
updated_at AS "UpdatedAt"
""";
var now = DateTimeOffset.UtcNow;
var patchFunctions = pair.PatchFunctions?.ToArray();
var command = new CommandDefinition(
sql,
new
{
pair.CveId,
pair.PackageName,
pair.Distro,
pair.DistroVersion,
pair.VulnerableVersion,
pair.VulnerableDebugId,
pair.VulnerableObservationId,
pair.FixedVersion,
pair.FixedDebugId,
pair.FixedObservationId,
pair.UpstreamDiffUrl,
PatchFunctions = pair.PatchFunctions?.ToArray(),
pair.VerificationStatus,
pair.MetadataJson,
Now = DateTimeOffset.UtcNow
},
cancellationToken: ct);
var results = await dbContext.SecurityPairs
.FromSqlInterpolated($"""
INSERT INTO groundtruth.security_pairs (
cve_id, package_name, distro, distro_version,
vulnerable_version, vulnerable_debug_id, vulnerable_observation_id,
fixed_version, fixed_debug_id, fixed_observation_id,
upstream_diff_url, patch_functions, verification_status, metadata,
created_at, updated_at
) VALUES (
{pair.CveId}, {pair.PackageName}, {pair.Distro}, {pair.DistroVersion},
{pair.VulnerableVersion}, {pair.VulnerableDebugId}, {pair.VulnerableObservationId},
{pair.FixedVersion}, {pair.FixedDebugId}, {pair.FixedObservationId},
{pair.UpstreamDiffUrl}, {patchFunctions}, {pair.VerificationStatus}, {pair.MetadataJson}::jsonb,
{now}, {now}
)
ON CONFLICT (cve_id, package_name, distro, vulnerable_version, fixed_version) DO UPDATE SET
distro_version = EXCLUDED.distro_version,
vulnerable_debug_id = COALESCE(EXCLUDED.vulnerable_debug_id, groundtruth.security_pairs.vulnerable_debug_id),
vulnerable_observation_id = COALESCE(EXCLUDED.vulnerable_observation_id, groundtruth.security_pairs.vulnerable_observation_id),
fixed_debug_id = COALESCE(EXCLUDED.fixed_debug_id, groundtruth.security_pairs.fixed_debug_id),
fixed_observation_id = COALESCE(EXCLUDED.fixed_observation_id, groundtruth.security_pairs.fixed_observation_id),
upstream_diff_url = COALESCE(EXCLUDED.upstream_diff_url, groundtruth.security_pairs.upstream_diff_url),
patch_functions = COALESCE(EXCLUDED.patch_functions, groundtruth.security_pairs.patch_functions),
metadata = COALESCE(EXCLUDED.metadata, groundtruth.security_pairs.metadata),
updated_at = EXCLUDED.updated_at
RETURNING pair_id, cve_id, package_name, distro, distro_version,
vulnerable_version, vulnerable_debug_id, vulnerable_observation_id,
fixed_version, fixed_debug_id, fixed_observation_id,
upstream_diff_url, patch_functions, verification_status,
metadata, created_at, updated_at
""")
.AsNoTracking()
.ToListAsync(ct);
var row = await conn.QuerySingleAsync<SecurityPairRow>(command);
return row.ToEntity();
return ToModel(results.First());
}
/// <inheritdoc/>
@@ -236,19 +142,14 @@ public sealed class SecurityPairRepository : ISecurityPairRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
var now = DateTimeOffset.UtcNow;
await dbContext.Database.ExecuteSqlInterpolatedAsync($"""
UPDATE groundtruth.security_pairs
SET verification_status = @Status, updated_at = @Now
WHERE pair_id = @PairId
""";
var command = new CommandDefinition(
sql,
new { PairId = pairId, Status = status, Now = DateTimeOffset.UtcNow },
cancellationToken: ct);
await conn.ExecuteAsync(command);
SET verification_status = {status}, updated_at = {now}
WHERE pair_id = {pairId}
""", ct);
}
/// <inheritdoc/>
@@ -259,27 +160,16 @@ public sealed class SecurityPairRepository : ISecurityPairRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
var now = DateTimeOffset.UtcNow;
await dbContext.Database.ExecuteSqlInterpolatedAsync($"""
UPDATE groundtruth.security_pairs
SET vulnerable_observation_id = COALESCE(@VulnerableObservationId, vulnerable_observation_id),
fixed_observation_id = COALESCE(@FixedObservationId, fixed_observation_id),
updated_at = @Now
WHERE pair_id = @PairId
""";
var command = new CommandDefinition(
sql,
new
{
PairId = pairId,
VulnerableObservationId = vulnerableObservationId,
FixedObservationId = fixedObservationId,
Now = DateTimeOffset.UtcNow
},
cancellationToken: ct);
await conn.ExecuteAsync(command);
SET vulnerable_observation_id = COALESCE({vulnerableObservationId}, vulnerable_observation_id),
fixed_observation_id = COALESCE({fixedObservationId}, fixed_observation_id),
updated_at = {now}
WHERE pair_id = {pairId}
""", ct);
}
/// <inheritdoc/>
@@ -288,76 +178,36 @@ public sealed class SecurityPairRepository : ISecurityPairRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT pair_id AS "PairId",
cve_id AS "CveId",
package_name AS "PackageName",
distro AS "Distro",
distro_version AS "DistroVersion",
vulnerable_version AS "VulnerableVersion",
vulnerable_debug_id AS "VulnerableDebugId",
vulnerable_observation_id AS "VulnerableObservationId",
fixed_version AS "FixedVersion",
fixed_debug_id AS "FixedDebugId",
fixed_observation_id AS "FixedObservationId",
upstream_diff_url AS "UpstreamDiffUrl",
patch_functions AS "PatchFunctions",
verification_status AS "VerificationStatus",
metadata::text AS "MetadataJson",
created_at AS "CreatedAt",
updated_at AS "UpdatedAt"
FROM groundtruth.security_pairs
WHERE vulnerable_observation_id IS NOT NULL
AND fixed_observation_id IS NOT NULL
ORDER BY updated_at DESC
LIMIT @Limit
""";
var entities = await dbContext.SecurityPairs
.AsNoTracking()
.Where(e => e.VulnerableObservationId != null && e.FixedObservationId != null)
.OrderByDescending(e => e.UpdatedAt)
.Take(limit)
.ToListAsync(ct);
var command = new CommandDefinition(sql, new { Limit = limit }, cancellationToken: ct);
var rows = await conn.QueryAsync<SecurityPairRow>(command);
return rows.Select(r => r.ToEntity()).ToList();
return entities.Select(ToModel).ToList();
}
private sealed class SecurityPairRow
private static SecurityPairEntity ToModel(EfModels.SecurityPairEntity entity) => new()
{
public Guid PairId { get; set; }
public string CveId { get; set; } = string.Empty;
public string PackageName { get; set; } = string.Empty;
public string Distro { get; set; } = string.Empty;
public string? DistroVersion { get; set; }
public string VulnerableVersion { get; set; } = string.Empty;
public string? VulnerableDebugId { get; set; }
public string? VulnerableObservationId { get; set; }
public string FixedVersion { get; set; } = string.Empty;
public string? FixedDebugId { get; set; }
public string? FixedObservationId { get; set; }
public string? UpstreamDiffUrl { get; set; }
public string[]? PatchFunctions { get; set; }
public string VerificationStatus { get; set; } = string.Empty;
public string? MetadataJson { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public DateTimeOffset UpdatedAt { get; set; }
public SecurityPairEntity ToEntity() => new()
{
PairId = PairId,
CveId = CveId,
PackageName = PackageName,
Distro = Distro,
DistroVersion = DistroVersion,
VulnerableVersion = VulnerableVersion,
VulnerableDebugId = VulnerableDebugId,
VulnerableObservationId = VulnerableObservationId,
FixedVersion = FixedVersion,
FixedDebugId = FixedDebugId,
FixedObservationId = FixedObservationId,
UpstreamDiffUrl = UpstreamDiffUrl,
PatchFunctions = PatchFunctions,
VerificationStatus = VerificationStatus,
MetadataJson = MetadataJson,
CreatedAt = CreatedAt,
UpdatedAt = UpdatedAt
};
}
PairId = entity.PairId,
CveId = entity.CveId,
PackageName = entity.PackageName,
Distro = entity.Distro,
DistroVersion = entity.DistroVersion,
VulnerableVersion = entity.VulnerableVersion,
VulnerableDebugId = entity.VulnerableDebugId,
VulnerableObservationId = entity.VulnerableObservationId,
FixedVersion = entity.FixedVersion,
FixedDebugId = entity.FixedDebugId,
FixedObservationId = entity.FixedObservationId,
UpstreamDiffUrl = entity.UpstreamDiffUrl,
PatchFunctions = entity.PatchFunctions,
VerificationStatus = entity.VerificationStatus,
MetadataJson = entity.Metadata,
CreatedAt = new DateTimeOffset(entity.CreatedAt, TimeSpan.Zero),
UpdatedAt = new DateTimeOffset(entity.UpdatedAt, TimeSpan.Zero)
};
}

View File

@@ -1,13 +1,16 @@
using Dapper;
using Microsoft.EntityFrameworkCore;
using StellaOps.BinaryIndex.Persistence.Postgres;
using EfModels = StellaOps.BinaryIndex.Persistence.EfCore.Models;
namespace StellaOps.BinaryIndex.Persistence.Repositories.GroundTruth;
/// <summary>
/// Repository implementation for source sync state and cursor management.
/// EF Core repository implementation for source sync state and cursor management.
/// </summary>
public sealed class SourceStateRepository : ISourceStateRepository
{
private readonly BinaryIndexDbContext _dbContext;
private const int CommandTimeoutSeconds = 30;
public SourceStateRepository(BinaryIndexDbContext dbContext)
{
@@ -18,104 +21,65 @@ public sealed class SourceStateRepository : ISourceStateRepository
public async Task<SourceStateEntity?> GetAsync(string sourceId, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT source_id AS "SourceId",
last_sync_at AS "LastSyncAt",
cursor_position AS "CursorPosition",
cursor_metadata::text AS "CursorMetadataJson",
sync_status AS "SyncStatus",
last_error AS "LastError",
document_count AS "DocumentCount",
observation_count AS "ObservationCount",
updated_at AS "UpdatedAt"
FROM groundtruth.source_state
WHERE source_id = @SourceId
""";
var entity = await dbContext.SourceStates
.AsNoTracking()
.Where(e => e.SourceId == sourceId)
.FirstOrDefaultAsync(ct);
var command = new CommandDefinition(sql, new { SourceId = sourceId }, cancellationToken: ct);
return await conn.QuerySingleOrDefaultAsync<SourceStateEntity>(command);
return entity is null ? null : ToModel(entity);
}
/// <inheritdoc/>
public async Task<IReadOnlyList<SourceStateEntity>> GetAllAsync(CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT source_id AS "SourceId",
last_sync_at AS "LastSyncAt",
cursor_position AS "CursorPosition",
cursor_metadata::text AS "CursorMetadataJson",
sync_status AS "SyncStatus",
last_error AS "LastError",
document_count AS "DocumentCount",
observation_count AS "ObservationCount",
updated_at AS "UpdatedAt"
FROM groundtruth.source_state
ORDER BY source_id
""";
var entities = await dbContext.SourceStates
.AsNoTracking()
.OrderBy(e => e.SourceId)
.ToListAsync(ct);
var command = new CommandDefinition(sql, cancellationToken: ct);
var rows = await conn.QueryAsync<SourceStateEntity>(command);
return rows.ToList();
return entities.Select(ToModel).ToList();
}
/// <inheritdoc/>
public async Task UpdateAsync(SourceStateEntity state, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
var now = DateTimeOffset.UtcNow;
await dbContext.Database.ExecuteSqlInterpolatedAsync($"""
UPDATE groundtruth.source_state
SET last_sync_at = @LastSyncAt,
cursor_position = @CursorPosition,
cursor_metadata = @CursorMetadataJson::jsonb,
sync_status = @SyncStatus,
last_error = @LastError,
document_count = @DocumentCount,
observation_count = @ObservationCount,
updated_at = @Now
WHERE source_id = @SourceId
""";
var command = new CommandDefinition(
sql,
new
{
state.SourceId,
state.LastSyncAt,
state.CursorPosition,
state.CursorMetadataJson,
state.SyncStatus,
state.LastError,
state.DocumentCount,
state.ObservationCount,
Now = DateTimeOffset.UtcNow
},
cancellationToken: ct);
await conn.ExecuteAsync(command);
SET last_sync_at = {state.LastSyncAt},
cursor_position = {state.CursorPosition},
cursor_metadata = {state.CursorMetadataJson}::jsonb,
sync_status = {state.SyncStatus},
last_error = {state.LastError},
document_count = {state.DocumentCount},
observation_count = {state.ObservationCount},
updated_at = {now}
WHERE source_id = {state.SourceId}
""", ct);
}
/// <inheritdoc/>
public async Task<bool> TrySetSyncingAsync(string sourceId, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
var now = DateTimeOffset.UtcNow;
// Only set to syncing if currently idle (optimistic locking)
const string sql = """
var affected = await dbContext.Database.ExecuteSqlInterpolatedAsync($"""
UPDATE groundtruth.source_state
SET sync_status = 'syncing', updated_at = @Now
WHERE source_id = @SourceId AND sync_status = 'idle'
""";
SET sync_status = 'syncing', updated_at = {now}
WHERE source_id = {sourceId} AND sync_status = 'idle'
""", ct);
var command = new CommandDefinition(
sql,
new { SourceId = sourceId, Now = DateTimeOffset.UtcNow },
cancellationToken: ct);
var affected = await conn.ExecuteAsync(command);
return affected > 0;
}
@@ -123,42 +87,45 @@ public sealed class SourceStateRepository : ISourceStateRepository
public async Task ClearSyncingAsync(string sourceId, string? error = null, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
var now = DateTimeOffset.UtcNow;
await dbContext.Database.ExecuteSqlInterpolatedAsync($"""
UPDATE groundtruth.source_state
SET sync_status = CASE WHEN @Error IS NULL THEN 'idle' ELSE 'error' END,
last_error = @Error,
last_sync_at = CASE WHEN @Error IS NULL THEN @Now ELSE last_sync_at END,
updated_at = @Now
WHERE source_id = @SourceId
""";
var command = new CommandDefinition(
sql,
new { SourceId = sourceId, Error = error, Now = DateTimeOffset.UtcNow },
cancellationToken: ct);
await conn.ExecuteAsync(command);
SET sync_status = CASE WHEN {error} IS NULL THEN 'idle' ELSE 'error' END,
last_error = {error},
last_sync_at = CASE WHEN {error} IS NULL THEN {now} ELSE last_sync_at END,
updated_at = {now}
WHERE source_id = {sourceId}
""", ct);
}
/// <inheritdoc/>
public async Task IncrementCountsAsync(string sourceId, int documents, int observations, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
var now = DateTimeOffset.UtcNow;
await dbContext.Database.ExecuteSqlInterpolatedAsync($"""
UPDATE groundtruth.source_state
SET document_count = document_count + @Documents,
observation_count = observation_count + @Observations,
updated_at = @Now
WHERE source_id = @SourceId
""";
var command = new CommandDefinition(
sql,
new { SourceId = sourceId, Documents = documents, Observations = observations, Now = DateTimeOffset.UtcNow },
cancellationToken: ct);
await conn.ExecuteAsync(command);
SET document_count = document_count + {documents},
observation_count = observation_count + {observations},
updated_at = {now}
WHERE source_id = {sourceId}
""", ct);
}
private static SourceStateEntity ToModel(EfModels.SourceStateEntity entity) => new()
{
SourceId = entity.SourceId,
LastSyncAt = entity.LastSyncAt.HasValue ? new DateTimeOffset(entity.LastSyncAt.Value, TimeSpan.Zero) : null,
CursorPosition = entity.CursorPosition,
CursorMetadataJson = entity.CursorMetadata,
SyncStatus = entity.SyncStatus,
LastError = entity.LastError,
DocumentCount = entity.DocumentCount,
ObservationCount = entity.ObservationCount,
UpdatedAt = new DateTimeOffset(entity.UpdatedAt, TimeSpan.Zero)
};
}

View File

@@ -1,14 +1,17 @@
using Dapper;
using Microsoft.EntityFrameworkCore;
using StellaOps.BinaryIndex.Persistence.Postgres;
using EfModels = StellaOps.BinaryIndex.Persistence.EfCore.Models;
namespace StellaOps.BinaryIndex.Persistence.Repositories.GroundTruth;
/// <summary>
/// Repository implementation for symbol observation persistence.
/// EF Core repository implementation for symbol observation persistence.
/// Follows immutable, append-only pattern with supersession.
/// </summary>
public sealed class SymbolObservationRepository : ISymbolObservationRepository
{
private readonly BinaryIndexDbContext _dbContext;
private const int CommandTimeoutSeconds = 30;
public SymbolObservationRepository(BinaryIndexDbContext dbContext)
{
@@ -19,105 +22,58 @@ public sealed class SymbolObservationRepository : ISymbolObservationRepository
public async Task<SymbolObservationEntity?> GetByIdAsync(string observationId, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT observation_id AS "ObservationId",
source_id AS "SourceId",
debug_id AS "DebugId",
code_id AS "CodeId",
binary_name AS "BinaryName",
binary_path AS "BinaryPath",
architecture AS "Architecture",
distro AS "Distro",
distro_version AS "DistroVersion",
package_name AS "PackageName",
package_version AS "PackageVersion",
symbol_count AS "SymbolCount",
symbols::text AS "SymbolsJson",
build_metadata::text AS "BuildMetadataJson",
provenance::text AS "ProvenanceJson",
content_hash AS "ContentHash",
supersedes_id AS "SupersedesId",
created_at AS "CreatedAt"
FROM groundtruth.symbol_observations
WHERE observation_id = @ObservationId
""";
var entity = await dbContext.SymbolObservations
.AsNoTracking()
.Where(e => e.ObservationId == observationId)
.FirstOrDefaultAsync(ct);
var command = new CommandDefinition(sql, new { ObservationId = observationId }, cancellationToken: ct);
return await conn.QuerySingleOrDefaultAsync<SymbolObservationEntity>(command);
return entity is null ? null : ToModel(entity);
}
/// <inheritdoc/>
public async Task<IReadOnlyList<SymbolObservationEntity>> GetByDebugIdAsync(string debugId, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT observation_id AS "ObservationId",
source_id AS "SourceId",
debug_id AS "DebugId",
code_id AS "CodeId",
binary_name AS "BinaryName",
binary_path AS "BinaryPath",
architecture AS "Architecture",
distro AS "Distro",
distro_version AS "DistroVersion",
package_name AS "PackageName",
package_version AS "PackageVersion",
symbol_count AS "SymbolCount",
symbols::text AS "SymbolsJson",
build_metadata::text AS "BuildMetadataJson",
provenance::text AS "ProvenanceJson",
content_hash AS "ContentHash",
supersedes_id AS "SupersedesId",
created_at AS "CreatedAt"
FROM groundtruth.symbol_observations
WHERE debug_id = @DebugId
ORDER BY created_at DESC
""";
var entities = await dbContext.SymbolObservations
.AsNoTracking()
.Where(e => e.DebugId == debugId)
.OrderByDescending(e => e.CreatedAt)
.ToListAsync(ct);
var command = new CommandDefinition(sql, new { DebugId = debugId }, cancellationToken: ct);
var rows = await conn.QueryAsync<SymbolObservationEntity>(command);
return rows.ToList();
return entities.Select(ToModel).ToList();
}
/// <inheritdoc/>
public async Task<SymbolObservationEntity?> GetLatestByDebugIdAsync(string debugId, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
// Get the latest observation that is not superseded by another
const string sql = """
SELECT o.observation_id AS "ObservationId",
o.source_id AS "SourceId",
o.debug_id AS "DebugId",
o.code_id AS "CodeId",
o.binary_name AS "BinaryName",
o.binary_path AS "BinaryPath",
o.architecture AS "Architecture",
o.distro AS "Distro",
o.distro_version AS "DistroVersion",
o.package_name AS "PackageName",
o.package_version AS "PackageVersion",
o.symbol_count AS "SymbolCount",
o.symbols::text AS "SymbolsJson",
o.build_metadata::text AS "BuildMetadataJson",
o.provenance::text AS "ProvenanceJson",
o.content_hash AS "ContentHash",
o.supersedes_id AS "SupersedesId",
o.created_at AS "CreatedAt"
FROM groundtruth.symbol_observations o
WHERE o.debug_id = @DebugId
AND NOT EXISTS (
SELECT 1 FROM groundtruth.symbol_observations s
WHERE s.supersedes_id = o.observation_id
)
ORDER BY o.created_at DESC
LIMIT 1
""";
// Get the latest observation that is not superseded by another.
// Uses raw SQL because the NOT EXISTS subquery with self-join is more natural in SQL.
var results = await dbContext.SymbolObservations
.FromSqlInterpolated($"""
SELECT o.observation_id, o.source_id, o.debug_id, o.code_id, o.binary_name, o.binary_path,
o.architecture, o.distro, o.distro_version, o.package_name, o.package_version,
o.symbol_count, o.symbols, o.build_metadata, o.provenance, o.content_hash,
o.supersedes_id, o.created_at
FROM groundtruth.symbol_observations o
WHERE o.debug_id = {debugId}
AND NOT EXISTS (
SELECT 1 FROM groundtruth.symbol_observations s
WHERE s.supersedes_id = o.observation_id
)
ORDER BY o.created_at DESC
LIMIT 1
""")
.AsNoTracking()
.ToListAsync(ct);
var command = new CommandDefinition(sql, new { DebugId = debugId }, cancellationToken: ct);
return await conn.QuerySingleOrDefaultAsync<SymbolObservationEntity>(command);
return results.Count == 0 ? null : ToModel(results[0]);
}
/// <inheritdoc/>
@@ -128,116 +84,74 @@ public sealed class SymbolObservationRepository : ISymbolObservationRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT observation_id AS "ObservationId",
source_id AS "SourceId",
debug_id AS "DebugId",
code_id AS "CodeId",
binary_name AS "BinaryName",
binary_path AS "BinaryPath",
architecture AS "Architecture",
distro AS "Distro",
distro_version AS "DistroVersion",
package_name AS "PackageName",
package_version AS "PackageVersion",
symbol_count AS "SymbolCount",
symbols::text AS "SymbolsJson",
build_metadata::text AS "BuildMetadataJson",
provenance::text AS "ProvenanceJson",
content_hash AS "ContentHash",
supersedes_id AS "SupersedesId",
created_at AS "CreatedAt"
FROM groundtruth.symbol_observations
WHERE package_name = @PackageName
AND (@PackageVersion IS NULL OR package_version = @PackageVersion)
AND (@Distro IS NULL OR distro = @Distro)
ORDER BY created_at DESC
""";
// Use raw SQL because EF Core cannot translate the (@Param IS NULL OR col = @Param) pattern
// with nullable parameters efficiently for PostgreSQL.
var results = await dbContext.SymbolObservations
.FromSqlInterpolated($"""
SELECT observation_id, source_id, debug_id, code_id, binary_name, binary_path,
architecture, distro, distro_version, package_name, package_version,
symbol_count, symbols, build_metadata, provenance, content_hash,
supersedes_id, created_at
FROM groundtruth.symbol_observations
WHERE package_name = {packageName}
AND ({packageVersion} IS NULL OR package_version = {packageVersion})
AND ({distro} IS NULL OR distro = {distro})
ORDER BY created_at DESC
""")
.AsNoTracking()
.ToListAsync(ct);
var command = new CommandDefinition(
sql,
new { PackageName = packageName, PackageVersion = packageVersion, Distro = distro },
cancellationToken: ct);
var rows = await conn.QueryAsync<SymbolObservationEntity>(command);
return rows.ToList();
return results.Select(ToModel).ToList();
}
/// <inheritdoc/>
public async Task<string?> GetExistingContentHashAsync(string observationId, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT content_hash
FROM groundtruth.symbol_observations
WHERE observation_id = @ObservationId
""";
var command = new CommandDefinition(sql, new { ObservationId = observationId }, cancellationToken: ct);
return await conn.QuerySingleOrDefaultAsync<string>(command);
return await dbContext.SymbolObservations
.AsNoTracking()
.Where(e => e.ObservationId == observationId)
.Select(e => e.ContentHash)
.FirstOrDefaultAsync(ct);
}
/// <inheritdoc/>
public async Task<bool> InsertAsync(SymbolObservationEntity observation, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
// Check if identical content already exists (idempotency)
const string checkSql = """
SELECT 1 FROM groundtruth.symbol_observations
WHERE content_hash = @ContentHash
LIMIT 1
""";
var exists = await dbContext.SymbolObservations
.AsNoTracking()
.AnyAsync(e => e.ContentHash == observation.ContentHash, ct);
var checkCommand = new CommandDefinition(checkSql, new { observation.ContentHash }, cancellationToken: ct);
var exists = await conn.QuerySingleOrDefaultAsync<int?>(checkCommand);
if (exists.HasValue)
if (exists)
{
return false; // Already exists with same content
}
const string sql = """
var now = DateTimeOffset.UtcNow;
var affected = await dbContext.Database.ExecuteSqlInterpolatedAsync($"""
INSERT INTO groundtruth.symbol_observations (
observation_id, source_id, debug_id, code_id, binary_name, binary_path,
architecture, distro, distro_version, package_name, package_version,
symbol_count, symbols, build_metadata, provenance, content_hash,
supersedes_id, created_at
) VALUES (
@ObservationId, @SourceId, @DebugId, @CodeId, @BinaryName, @BinaryPath,
@Architecture, @Distro, @DistroVersion, @PackageName, @PackageVersion,
@SymbolCount, @SymbolsJson::jsonb, @BuildMetadataJson::jsonb, @ProvenanceJson::jsonb,
@ContentHash, @SupersedesId, @Now
{observation.ObservationId}, {observation.SourceId}, {observation.DebugId}, {observation.CodeId},
{observation.BinaryName}, {observation.BinaryPath}, {observation.Architecture}, {observation.Distro},
{observation.DistroVersion}, {observation.PackageName}, {observation.PackageVersion},
{observation.SymbolCount}, {observation.SymbolsJson}::jsonb, {observation.BuildMetadataJson}::jsonb,
{observation.ProvenanceJson}::jsonb, {observation.ContentHash}, {observation.SupersedesId}, {now}
)
ON CONFLICT (observation_id) DO NOTHING
""";
""", ct);
var command = new CommandDefinition(
sql,
new
{
observation.ObservationId,
observation.SourceId,
observation.DebugId,
observation.CodeId,
observation.BinaryName,
observation.BinaryPath,
observation.Architecture,
observation.Distro,
observation.DistroVersion,
observation.PackageName,
observation.PackageVersion,
observation.SymbolCount,
observation.SymbolsJson,
observation.BuildMetadataJson,
observation.ProvenanceJson,
observation.ContentHash,
observation.SupersedesId,
Now = DateTimeOffset.UtcNow
},
cancellationToken: ct);
var affected = await conn.ExecuteAsync(command);
return affected > 0;
}
@@ -248,57 +162,62 @@ public sealed class SymbolObservationRepository : ISymbolObservationRepository
CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
// Use JSONB containment for symbol search
const string sql = """
SELECT observation_id AS "ObservationId",
source_id AS "SourceId",
debug_id AS "DebugId",
code_id AS "CodeId",
binary_name AS "BinaryName",
binary_path AS "BinaryPath",
architecture AS "Architecture",
distro AS "Distro",
distro_version AS "DistroVersion",
package_name AS "PackageName",
package_version AS "PackageVersion",
symbol_count AS "SymbolCount",
symbols::text AS "SymbolsJson",
build_metadata::text AS "BuildMetadataJson",
provenance::text AS "ProvenanceJson",
content_hash AS "ContentHash",
supersedes_id AS "SupersedesId",
created_at AS "CreatedAt"
FROM groundtruth.symbol_observations
WHERE symbols @> @SearchPattern::jsonb
ORDER BY created_at DESC
LIMIT @Limit
""";
// Search for symbol by name using JSONB array containment
// Use JSONB containment for symbol search -- requires raw SQL
var searchPattern = $"[{{\"name\":\"{symbolName}\"}}]";
var command = new CommandDefinition(
sql,
new { SearchPattern = searchPattern, Limit = limit },
cancellationToken: ct);
var rows = await conn.QueryAsync<SymbolObservationEntity>(command);
return rows.ToList();
var results = await dbContext.SymbolObservations
.FromSqlInterpolated($"""
SELECT observation_id, source_id, debug_id, code_id, binary_name, binary_path,
architecture, distro, distro_version, package_name, package_version,
symbol_count, symbols, build_metadata, provenance, content_hash,
supersedes_id, created_at
FROM groundtruth.symbol_observations
WHERE symbols @> {searchPattern}::jsonb
ORDER BY created_at DESC
LIMIT {limit}
""")
.AsNoTracking()
.ToListAsync(ct);
return results.Select(ToModel).ToList();
}
/// <inheritdoc/>
public async Task<IDictionary<string, long>> GetCountBySourceAsync(CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT source_id AS "SourceId", COUNT(*) AS "Count"
FROM groundtruth.symbol_observations
GROUP BY source_id
""";
var groups = await dbContext.SymbolObservations
.AsNoTracking()
.GroupBy(e => e.SourceId)
.Select(g => new { SourceId = g.Key, Count = (long)g.Count() })
.ToListAsync(ct);
var command = new CommandDefinition(sql, cancellationToken: ct);
var rows = await conn.QueryAsync<(string SourceId, long Count)>(command);
return rows.ToDictionary(r => r.SourceId, r => r.Count);
return groups.ToDictionary(g => g.SourceId, g => g.Count);
}
private static SymbolObservationEntity ToModel(EfModels.SymbolObservationEntity entity) => new()
{
ObservationId = entity.ObservationId,
SourceId = entity.SourceId,
DebugId = entity.DebugId,
CodeId = entity.CodeId,
BinaryName = entity.BinaryName,
BinaryPath = entity.BinaryPath,
Architecture = entity.Architecture,
Distro = entity.Distro,
DistroVersion = entity.DistroVersion,
PackageName = entity.PackageName,
PackageVersion = entity.PackageVersion,
SymbolCount = entity.SymbolCount,
SymbolsJson = entity.Symbols,
BuildMetadataJson = entity.BuildMetadata,
ProvenanceJson = entity.Provenance,
ContentHash = entity.ContentHash,
SupersedesId = entity.SupersedesId,
CreatedAt = new DateTimeOffset(entity.CreatedAt, TimeSpan.Zero)
};
}

View File

@@ -1,13 +1,16 @@
using Dapper;
using Microsoft.EntityFrameworkCore;
using StellaOps.BinaryIndex.Persistence.Postgres;
using EfModels = StellaOps.BinaryIndex.Persistence.EfCore.Models;
namespace StellaOps.BinaryIndex.Persistence.Repositories.GroundTruth;
/// <summary>
/// Repository implementation for symbol source management.
/// EF Core repository implementation for symbol source management.
/// </summary>
public sealed class SymbolSourceRepository : ISymbolSourceRepository
{
private readonly BinaryIndexDbContext _dbContext;
private const int CommandTimeoutSeconds = 30;
public SymbolSourceRepository(BinaryIndexDbContext dbContext)
{
@@ -18,168 +21,104 @@ public sealed class SymbolSourceRepository : ISymbolSourceRepository
public async Task<IReadOnlyList<SymbolSourceEntity>> GetAllAsync(CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT source_id AS "SourceId",
display_name AS "DisplayName",
source_type AS "SourceType",
base_url AS "BaseUrl",
supported_distros AS "SupportedDistros",
is_enabled AS "IsEnabled",
config_json AS "ConfigJson",
created_at AS "CreatedAt",
updated_at AS "UpdatedAt"
FROM groundtruth.symbol_sources
ORDER BY display_name
""";
var entities = await dbContext.SymbolSources
.AsNoTracking()
.OrderBy(e => e.DisplayName)
.ToListAsync(ct);
var command = new CommandDefinition(sql, cancellationToken: ct);
var rows = await conn.QueryAsync<SymbolSourceRow>(command);
return rows.Select(r => r.ToEntity()).ToList();
return entities.Select(ToModel).ToList();
}
/// <inheritdoc/>
public async Task<SymbolSourceEntity?> GetByIdAsync(string sourceId, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT source_id AS "SourceId",
display_name AS "DisplayName",
source_type AS "SourceType",
base_url AS "BaseUrl",
supported_distros AS "SupportedDistros",
is_enabled AS "IsEnabled",
config_json AS "ConfigJson",
created_at AS "CreatedAt",
updated_at AS "UpdatedAt"
FROM groundtruth.symbol_sources
WHERE source_id = @SourceId
""";
var entity = await dbContext.SymbolSources
.AsNoTracking()
.Where(e => e.SourceId == sourceId)
.FirstOrDefaultAsync(ct);
var command = new CommandDefinition(sql, new { SourceId = sourceId }, cancellationToken: ct);
var row = await conn.QuerySingleOrDefaultAsync<SymbolSourceRow>(command);
return row?.ToEntity();
return entity is null ? null : ToModel(entity);
}
/// <inheritdoc/>
public async Task<IReadOnlyList<SymbolSourceEntity>> GetEnabledAsync(CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
SELECT source_id AS "SourceId",
display_name AS "DisplayName",
source_type AS "SourceType",
base_url AS "BaseUrl",
supported_distros AS "SupportedDistros",
is_enabled AS "IsEnabled",
config_json AS "ConfigJson",
created_at AS "CreatedAt",
updated_at AS "UpdatedAt"
FROM groundtruth.symbol_sources
WHERE is_enabled = true
ORDER BY display_name
""";
var entities = await dbContext.SymbolSources
.AsNoTracking()
.Where(e => e.IsEnabled)
.OrderBy(e => e.DisplayName)
.ToListAsync(ct);
var command = new CommandDefinition(sql, cancellationToken: ct);
var rows = await conn.QueryAsync<SymbolSourceRow>(command);
return rows.Select(r => r.ToEntity()).ToList();
return entities.Select(ToModel).ToList();
}
/// <inheritdoc/>
public async Task<SymbolSourceEntity> UpsertAsync(SymbolSourceEntity source, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
INSERT INTO groundtruth.symbol_sources (
source_id, display_name, source_type, base_url, supported_distros,
is_enabled, config_json, created_at, updated_at
) VALUES (
@SourceId, @DisplayName, @SourceType, @BaseUrl, @SupportedDistros,
@IsEnabled, @ConfigJson::jsonb, @Now, @Now
)
ON CONFLICT (source_id) DO UPDATE SET
display_name = EXCLUDED.display_name,
source_type = EXCLUDED.source_type,
base_url = EXCLUDED.base_url,
supported_distros = EXCLUDED.supported_distros,
is_enabled = EXCLUDED.is_enabled,
config_json = EXCLUDED.config_json,
updated_at = EXCLUDED.updated_at
RETURNING source_id AS "SourceId",
display_name AS "DisplayName",
source_type AS "SourceType",
base_url AS "BaseUrl",
supported_distros AS "SupportedDistros",
is_enabled AS "IsEnabled",
config_json AS "ConfigJson",
created_at AS "CreatedAt",
updated_at AS "UpdatedAt"
""";
var now = DateTimeOffset.UtcNow;
var supportedDistros = source.SupportedDistros.ToArray();
var command = new CommandDefinition(
sql,
new
{
source.SourceId,
source.DisplayName,
source.SourceType,
source.BaseUrl,
SupportedDistros = source.SupportedDistros.ToArray(),
source.IsEnabled,
source.ConfigJson,
Now = DateTimeOffset.UtcNow
},
cancellationToken: ct);
var results = await dbContext.SymbolSources
.FromSqlInterpolated($"""
INSERT INTO groundtruth.symbol_sources (
source_id, display_name, source_type, base_url, supported_distros,
is_enabled, config_json, created_at, updated_at
) VALUES (
{source.SourceId}, {source.DisplayName}, {source.SourceType}, {source.BaseUrl}, {supportedDistros},
{source.IsEnabled}, {source.ConfigJson}::jsonb, {now}, {now}
)
ON CONFLICT (source_id) DO UPDATE SET
display_name = EXCLUDED.display_name,
source_type = EXCLUDED.source_type,
base_url = EXCLUDED.base_url,
supported_distros = EXCLUDED.supported_distros,
is_enabled = EXCLUDED.is_enabled,
config_json = EXCLUDED.config_json,
updated_at = EXCLUDED.updated_at
RETURNING source_id, display_name, source_type, base_url, supported_distros,
is_enabled, config_json, created_at, updated_at
""")
.AsNoTracking()
.ToListAsync(ct);
var row = await conn.QuerySingleAsync<SymbolSourceRow>(command);
return row.ToEntity();
return ToModel(results.First());
}
/// <inheritdoc/>
public async Task SetEnabledAsync(string sourceId, bool enabled, CancellationToken ct = default)
{
await using var conn = await _dbContext.OpenConnectionAsync(ct);
await using var dbContext = BinaryIndexPersistenceDbContextFactory.Create(conn, CommandTimeoutSeconds);
const string sql = """
var now = DateTimeOffset.UtcNow;
await dbContext.Database.ExecuteSqlInterpolatedAsync($"""
UPDATE groundtruth.symbol_sources
SET is_enabled = @Enabled, updated_at = @Now
WHERE source_id = @SourceId
""";
var command = new CommandDefinition(
sql,
new { SourceId = sourceId, Enabled = enabled, Now = DateTimeOffset.UtcNow },
cancellationToken: ct);
await conn.ExecuteAsync(command);
SET is_enabled = {enabled}, updated_at = {now}
WHERE source_id = {sourceId}
""", ct);
}
private sealed class SymbolSourceRow
private static SymbolSourceEntity ToModel(EfModels.SymbolSourceEntity entity) => new()
{
public string SourceId { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public string SourceType { get; set; } = string.Empty;
public string BaseUrl { get; set; } = string.Empty;
public string[] SupportedDistros { get; set; } = [];
public bool IsEnabled { get; set; }
public string? ConfigJson { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public DateTimeOffset UpdatedAt { get; set; }
public SymbolSourceEntity ToEntity() => new()
{
SourceId = SourceId,
DisplayName = DisplayName,
SourceType = SourceType,
BaseUrl = BaseUrl,
SupportedDistros = SupportedDistros,
IsEnabled = IsEnabled,
ConfigJson = ConfigJson,
CreatedAt = CreatedAt,
UpdatedAt = UpdatedAt
};
}
SourceId = entity.SourceId,
DisplayName = entity.DisplayName,
SourceType = entity.SourceType,
BaseUrl = entity.BaseUrl,
SupportedDistros = entity.SupportedDistros,
IsEnabled = entity.IsEnabled,
ConfigJson = entity.ConfigJson,
CreatedAt = new DateTimeOffset(entity.CreatedAt, TimeSpan.Zero),
UpdatedAt = new DateTimeOffset(entity.UpdatedAt, TimeSpan.Zero)
};
}

View File

@@ -9,7 +9,19 @@
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="Migrations\*.sql" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup>
<!-- Prevent automatic compiled-model binding so non-default schemas can build runtime models. -->
<Compile Remove="EfCore\CompiledModels\BinaryIndexPersistenceDbContextAssemblyAttributes.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" PrivateAssets="all" />
<PackageReference Include="Npgsql" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
<PackageReference Include="Dapper" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
</ItemGroup>
@@ -21,10 +33,7 @@
<ProjectReference Include="..\StellaOps.BinaryIndex.FixIndex\StellaOps.BinaryIndex.FixIndex.csproj" />
<ProjectReference Include="..\StellaOps.BinaryIndex.Fingerprints\StellaOps.BinaryIndex.Fingerprints.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Infrastructure.Postgres\StellaOps.Infrastructure.Postgres.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Infrastructure.EfCore\StellaOps.Infrastructure.EfCore.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Determinism.Abstractions\StellaOps.Determinism.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Migrations\*.sql" />
</ItemGroup>
</Project>

View File

@@ -10,3 +10,8 @@ Source of truth: `docs-archived/implplan/2025-12-29-csproj-audit/SPRINT_20251229
| AUDIT-0125-T | DONE | Test coverage audit for StellaOps.BinaryIndex.Persistence; revalidated 2026-01-06. |
| AUDIT-0125-A | TODO | Revalidated 2026-01-06; open findings pending apply. |
| REMED-06 | DONE | SOLID review notes captured for SPRINT_20260130_002. |
| BINARY-EF-01 | DONE | SPRINT_20260222_090: Migration registry wiring verified. BinaryIndexMigrationModulePlugin added to Platform. |
| BINARY-EF-02 | DONE | SPRINT_20260222_090: EF Core model baseline scaffolded (15 entities, binaries+groundtruth schemas). |
| BINARY-EF-03 | DONE | SPRINT_20260222_090: 10 repositories converted from Dapper to EF Core. FunctionCorpusRepository deferred. |
| BINARY-EF-04 | DONE | SPRINT_20260222_090: Compiled model (18 files) generated. UseModel() wired in runtime factory. |
| BINARY-EF-05 | DONE | SPRINT_20260222_090: Sequential builds/tests validated. Module docs updated. |