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

@@ -80,12 +80,13 @@ public interface ISbomSourceRunRepository
/// <summary>
/// Get a run by ID.
/// </summary>
Task<SbomSourceRun?> GetByIdAsync(Guid runId, CancellationToken ct = default);
Task<SbomSourceRun?> GetByIdAsync(string tenantId, Guid runId, CancellationToken ct = default);
/// <summary>
/// List runs for a source.
/// </summary>
Task<PagedResponse<SbomSourceRun>> ListForSourceAsync(
string tenantId,
Guid sourceId,
ListSourceRunsRequest request,
CancellationToken ct = default);
@@ -111,7 +112,7 @@ public interface ISbomSourceRunRepository
/// <summary>
/// Get aggregate statistics for a source.
/// </summary>
Task<SourceRunStats> GetStatsAsync(Guid sourceId, CancellationToken ct = default);
Task<SourceRunStats> GetStatsAsync(string tenantId, Guid sourceId, CancellationToken ct = default);
}
/// <summary>

View File

@@ -28,32 +28,37 @@ public sealed class SbomSourceRunRepository : RepositoryBase<ScannerSourcesDataS
_timeProvider = timeProvider ?? TimeProvider.System;
}
public async Task<SbomSourceRun?> GetByIdAsync(Guid runId, CancellationToken ct = default)
public async Task<SbomSourceRun?> GetByIdAsync(string tenantId, Guid runId, CancellationToken ct = default)
{
const string sql = $"""
SELECT * FROM {FullTable}
WHERE run_id = @runId
WHERE tenant_id = @tenantId AND run_id = @runId
""";
// Use system tenant for run queries (runs have their own tenant_id)
return await QuerySingleOrDefaultAsync(
"__system__",
tenantId,
sql,
cmd => AddParameter(cmd, "runId", runId),
cmd =>
{
AddParameter(cmd, "tenantId", tenantId);
AddParameter(cmd, "runId", runId);
},
MapRun,
ct);
}
public async Task<PagedResponse<SbomSourceRun>> ListForSourceAsync(
string tenantId,
Guid sourceId,
ListSourceRunsRequest request,
CancellationToken ct = default)
{
var sb = new StringBuilder($"SELECT * FROM {FullTable} WHERE source_id = @sourceId");
var countSb = new StringBuilder($"SELECT COUNT(*) FROM {FullTable} WHERE source_id = @sourceId");
var sb = new StringBuilder($"SELECT * FROM {FullTable} WHERE tenant_id = @tenantId AND source_id = @sourceId");
var countSb = new StringBuilder($"SELECT COUNT(*) FROM {FullTable} WHERE tenant_id = @tenantId AND source_id = @sourceId");
void AddFilters(NpgsqlCommand cmd)
{
AddParameter(cmd, "tenantId", tenantId);
AddParameter(cmd, "sourceId", sourceId);
if (request.Trigger.HasValue)
@@ -95,14 +100,14 @@ public sealed class SbomSourceRunRepository : RepositoryBase<ScannerSourcesDataS
}
var items = await QueryAsync(
"__system__",
tenantId,
sb.ToString(),
AddFilters,
MapRun,
ct);
var totalCount = await ExecuteScalarAsync<long>(
"__system__",
tenantId,
countSb.ToString(),
AddFilters,
ct);
@@ -197,7 +202,7 @@ public sealed class SbomSourceRunRepository : RepositoryBase<ScannerSourcesDataS
ct);
}
public async Task<SourceRunStats> GetStatsAsync(Guid sourceId, CancellationToken ct = default)
public async Task<SourceRunStats> GetStatsAsync(string tenantId, Guid sourceId, CancellationToken ct = default)
{
const string sql = $"""
SELECT
@@ -209,14 +214,19 @@ public sealed class SbomSourceRunRepository : RepositoryBase<ScannerSourcesDataS
MAX(completed_at) FILTER (WHERE status = 'Succeeded') as last_success_at,
MAX(completed_at) FILTER (WHERE status = 'Failed') as last_failure_at
FROM {FullTable}
WHERE source_id = @sourceId
WHERE tenant_id = @tenantId
AND source_id = @sourceId
AND completed_at IS NOT NULL
""";
var result = await QuerySingleOrDefaultAsync(
"__system__",
tenantId,
sql,
cmd => AddParameter(cmd, "sourceId", sourceId),
cmd =>
{
AddParameter(cmd, "tenantId", tenantId);
AddParameter(cmd, "sourceId", sourceId);
},
reader => new SourceRunStats
{
TotalRuns = reader.GetInt32(reader.GetOrdinal("total_runs")),

View File

@@ -379,7 +379,7 @@ public sealed class SbomSourceService : ISbomSourceService
var source = await _sourceRepository.GetByIdAsync(tenantId, sourceId, ct)
?? throw new KeyNotFoundException($"Source {sourceId} not found");
var result = await _runRepository.ListForSourceAsync(sourceId, request, ct);
var result = await _runRepository.ListForSourceAsync(tenantId, sourceId, request, ct);
return new PagedResponse<SourceRunResponse>
{
@@ -399,7 +399,7 @@ public sealed class SbomSourceService : ISbomSourceService
_ = await _sourceRepository.GetByIdAsync(tenantId, sourceId, ct)
?? throw new KeyNotFoundException($"Source {sourceId} not found");
var run = await _runRepository.GetByIdAsync(runId, ct);
var run = await _runRepository.GetByIdAsync(tenantId, runId, ct);
if (run == null || run.SourceId != sourceId)
{
return null;

View File

@@ -9,3 +9,4 @@ Source of truth: `docs-archived/implplan/2025-12-29-csproj-audit/SPRINT_20251229
| AUDIT-0684-T | DONE | Revalidated 2026-01-12. |
| AUDIT-0684-A | DONE | Applied 2026-01-14. |
| REMED-06 | DONE | SOLID review notes captured for SPRINT_20260130_002. |
| SPRINT-20260222-057-SCAN-TEN-13 | DONE | `SPRINT_20260222_057_Scanner_tenant_isolation_for_scans_triage_webhooks.md`: tenant-parameterized `ISbomSourceRunRepository` (`GetByIdAsync`, `ListForSourceAsync`, `GetStatsAsync`) and SQL predicates for `scanner.sbom_source_runs` (2026-02-23). |

View File

@@ -248,7 +248,13 @@ public sealed class SourceTriggerDispatcher : ISourceTriggerDispatcher
Guid originalRunId,
CancellationToken ct = default)
{
var originalRun = await _runRepository.GetByIdAsync(originalRunId, ct);
var source = await _sourceRepository.GetByIdAnyTenantAsync(sourceId, ct);
if (source == null)
{
throw new KeyNotFoundException($"Source {sourceId} not found");
}
var originalRun = await _runRepository.GetByIdAsync(source.TenantId, originalRunId, ct);
if (originalRun == null)
{
throw new KeyNotFoundException($"Run {originalRunId} not found");