refactor: DB schema fixes + container renames + compose include + audit sprint

- FindingsLedger: change schema from public to findings (V3-01)
- Add 9 migration module plugins: RiskEngine, Replay, ExportCenter, Integrations, Signer, IssuerDirectory, Workflow, PacksRegistry, OpsMemory (V4-01 to V4-09)
- Remove 16 redundant inline CREATE SCHEMA patterns (V4-10)
- Rename export→export-web, excititor→excititor-web for consistency
- Compose stella-ops.yml: thin wrapper using include: directive
- Fix dead /api/v1/jobengine/* gateway routes → release-orchestrator/packsregistry
- Scheduler plugin architecture: ISchedulerJobPlugin + ScanJobPlugin + DoctorJobPlugin
- Create unified audit sink sprint plan
- VulnExplorer integration tests + gap analysis

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
master
2026-04-08 16:10:36 +03:00
parent 6592cdcc9b
commit 65106afe4c
100 changed files with 5788 additions and 2852 deletions

View File

@@ -0,0 +1,15 @@
-- 001_initial_schema.sql
-- Replay: schema and feed_snapshot_index table.
CREATE SCHEMA IF NOT EXISTS replay;
CREATE TABLE IF NOT EXISTS replay.feed_snapshot_index (
provider_id TEXT NOT NULL,
digest TEXT NOT NULL,
captured_at TIMESTAMPTZ NOT NULL,
epoch_timestamp TIMESTAMPTZ NOT NULL,
PRIMARY KEY (provider_id, captured_at, digest)
);
CREATE INDEX IF NOT EXISTS idx_replay_snapshot_index_lookup
ON replay.feed_snapshot_index (provider_id, captured_at DESC, digest ASC);

View File

@@ -8,8 +8,6 @@ namespace StellaOps.Replay.WebService;
public sealed class PostgresFeedSnapshotIndexStore : IFeedSnapshotIndexStore, IAsyncDisposable
{
private readonly NpgsqlDataSource _dataSource;
private readonly object _initGate = new();
private bool _tableInitialized;
public PostgresFeedSnapshotIndexStore(string connectionString)
{
@@ -26,7 +24,6 @@ public sealed class PostgresFeedSnapshotIndexStore : IFeedSnapshotIndexStore, IA
public async Task IndexSnapshotAsync(FeedSnapshotIndexEntry entry, CancellationToken ct = default)
{
ArgumentNullException.ThrowIfNull(entry);
await EnsureTableAsync(ct).ConfigureAwait(false);
const string sql = """
INSERT INTO replay.feed_snapshot_index (
@@ -58,7 +55,6 @@ public sealed class PostgresFeedSnapshotIndexStore : IFeedSnapshotIndexStore, IA
CancellationToken ct = default)
{
ArgumentException.ThrowIfNullOrWhiteSpace(providerId);
await EnsureTableAsync(ct).ConfigureAwait(false);
const string sql = """
SELECT provider_id, digest, captured_at, epoch_timestamp
@@ -97,7 +93,6 @@ public sealed class PostgresFeedSnapshotIndexStore : IFeedSnapshotIndexStore, IA
CancellationToken ct = default)
{
ArgumentException.ThrowIfNullOrWhiteSpace(providerId);
await EnsureTableAsync(ct).ConfigureAwait(false);
const string sql = """
SELECT provider_id, digest, captured_at, epoch_timestamp
@@ -139,38 +134,6 @@ public sealed class PostgresFeedSnapshotIndexStore : IFeedSnapshotIndexStore, IA
return _dataSource.DisposeAsync();
}
private async Task EnsureTableAsync(CancellationToken ct)
{
lock (_initGate)
{
if (_tableInitialized)
{
return;
}
}
const string ddl = """
CREATE SCHEMA IF NOT EXISTS replay;
CREATE TABLE IF NOT EXISTS replay.feed_snapshot_index (
provider_id TEXT NOT NULL,
digest TEXT NOT NULL,
captured_at TIMESTAMPTZ NOT NULL,
epoch_timestamp TIMESTAMPTZ NOT NULL,
PRIMARY KEY (provider_id, captured_at, digest)
);
CREATE INDEX IF NOT EXISTS idx_replay_snapshot_index_lookup
ON replay.feed_snapshot_index (provider_id, captured_at DESC, digest ASC);
""";
await using var connection = await _dataSource.OpenConnectionAsync(ct).ConfigureAwait(false);
await using var command = new NpgsqlCommand(ddl, connection);
await command.ExecuteNonQueryAsync(ct).ConfigureAwait(false);
lock (_initGate)
{
_tableInitialized = true;
}
}
}
public sealed class SeedFsFeedSnapshotBlobStore : IFeedSnapshotBlobStore

View File

@@ -30,6 +30,11 @@
<EmbeddedResource Include="Translations\*.json" />
</ItemGroup>
<ItemGroup>
<!-- Embed SQL migrations as resources -->
<EmbeddedResource Include="Migrations\**\*.sql" />
</ItemGroup>
<PropertyGroup Label="StellaOpsReleaseVersion">
<Version>1.0.0-alpha1</Version>
<InformationalVersion>1.0.0-alpha1</InformationalVersion>