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:
@@ -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>
|
||||
|
||||
@@ -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")),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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). |
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user