- Introduced `sink-detect.js` with various security sink detection patterns categorized by type (e.g., command injection, SQL injection, file operations). - Implemented functions to build a lookup map for fast sink detection and to match sink calls against known patterns. - Added `package-lock.json` for dependency management.
249 lines
9.2 KiB
C#
249 lines
9.2 KiB
C#
// -----------------------------------------------------------------------------
|
|
// PostgresOnlyStartupTests.cs
|
|
// Sprint: SPRINT_5100_0001_0001_mongodb_cli_cleanup_consolidation
|
|
// Task: T1.13 - PostgreSQL-only Platform Startup Test
|
|
// Description: Validates platform can start with PostgreSQL-only infrastructure.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
using System.Reflection;
|
|
using StellaOps.Infrastructure.Postgres.Testing;
|
|
using Testcontainers.PostgreSql;
|
|
|
|
namespace StellaOps.Integration.Platform;
|
|
|
|
/// <summary>
|
|
/// Integration tests validating PostgreSQL-only platform startup.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// T1.13-AC1: Platform starts successfully with PostgreSQL only
|
|
/// T1.13-AC2: All services connect to PostgreSQL correctly
|
|
/// T1.13-AC3: Schema migrations run successfully
|
|
/// T1.13-AC4: No MongoDB connection attempts in logs
|
|
/// </remarks>
|
|
[Trait("Category", "Integration")]
|
|
[Trait("Category", "Platform")]
|
|
[Trait("Category", "PostgresOnly")]
|
|
public class PostgresOnlyStartupTests : IAsyncLifetime
|
|
{
|
|
private PostgreSqlContainer? _container;
|
|
private string? _connectionString;
|
|
|
|
public async Task InitializeAsync()
|
|
{
|
|
_container = new PostgreSqlBuilder()
|
|
.WithImage("postgres:16-alpine")
|
|
.Build();
|
|
|
|
await _container.StartAsync();
|
|
_connectionString = _container.GetConnectionString();
|
|
}
|
|
|
|
public async Task DisposeAsync()
|
|
{
|
|
if (_container != null)
|
|
{
|
|
await _container.DisposeAsync();
|
|
}
|
|
}
|
|
|
|
#region T1.13-AC1: Platform starts successfully with PostgreSQL only
|
|
|
|
[Fact(DisplayName = "T1.13-AC1.1: PostgreSQL container starts and accepts connections")]
|
|
public async Task PostgresContainer_StartsAndAcceptsConnections()
|
|
{
|
|
// Arrange & Act - already done in InitializeAsync
|
|
|
|
// Assert
|
|
_connectionString.Should().NotBeNullOrEmpty();
|
|
_container!.State.Should().Be(DotNet.Testcontainers.Containers.TestcontainersStates.Running);
|
|
|
|
// Verify connection works
|
|
using var connection = new Npgsql.NpgsqlConnection(_connectionString);
|
|
await connection.OpenAsync();
|
|
connection.State.Should().Be(System.Data.ConnectionState.Open);
|
|
}
|
|
|
|
[Fact(DisplayName = "T1.13-AC1.2: PostgreSQL connection string contains no MongoDB references")]
|
|
public void ConnectionString_ContainsNoMongoDbReferences()
|
|
{
|
|
// Assert
|
|
_connectionString.Should().NotContainAny("mongo", "mongodb", "27017");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region T1.13-AC2: Services connect to PostgreSQL correctly
|
|
|
|
[Fact(DisplayName = "T1.13-AC2.1: Can create and verify database schema")]
|
|
public async Task Database_CanCreateAndVerifySchema()
|
|
{
|
|
// Arrange
|
|
using var connection = new Npgsql.NpgsqlConnection(_connectionString);
|
|
await connection.OpenAsync();
|
|
|
|
// Act - Create a test schema
|
|
using var createCmd = connection.CreateCommand();
|
|
createCmd.CommandText = "CREATE SCHEMA IF NOT EXISTS test_platform";
|
|
await createCmd.ExecuteNonQueryAsync();
|
|
|
|
// Assert - Verify schema exists
|
|
using var verifyCmd = connection.CreateCommand();
|
|
verifyCmd.CommandText = @"
|
|
SELECT schema_name
|
|
FROM information_schema.schemata
|
|
WHERE schema_name = 'test_platform'";
|
|
var result = await verifyCmd.ExecuteScalarAsync();
|
|
result.Should().Be("test_platform");
|
|
}
|
|
|
|
[Fact(DisplayName = "T1.13-AC2.2: Can perform basic CRUD operations")]
|
|
public async Task Database_CanPerformCrudOperations()
|
|
{
|
|
// Arrange
|
|
using var connection = new Npgsql.NpgsqlConnection(_connectionString);
|
|
await connection.OpenAsync();
|
|
|
|
// Create test table
|
|
using var createCmd = connection.CreateCommand();
|
|
createCmd.CommandText = @"
|
|
CREATE TABLE IF NOT EXISTS test_crud (
|
|
id SERIAL PRIMARY KEY,
|
|
name VARCHAR(100) NOT NULL,
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
)";
|
|
await createCmd.ExecuteNonQueryAsync();
|
|
|
|
// Act - Insert
|
|
using var insertCmd = connection.CreateCommand();
|
|
insertCmd.CommandText = "INSERT INTO test_crud (name) VALUES ('test-record') RETURNING id";
|
|
var insertedId = await insertCmd.ExecuteScalarAsync();
|
|
insertedId.Should().NotBeNull();
|
|
|
|
// Act - Select
|
|
using var selectCmd = connection.CreateCommand();
|
|
selectCmd.CommandText = "SELECT name FROM test_crud WHERE id = @id";
|
|
selectCmd.Parameters.AddWithValue("id", insertedId!);
|
|
var name = await selectCmd.ExecuteScalarAsync();
|
|
name.Should().Be("test-record");
|
|
|
|
// Act - Update
|
|
using var updateCmd = connection.CreateCommand();
|
|
updateCmd.CommandText = "UPDATE test_crud SET name = 'updated-record' WHERE id = @id";
|
|
updateCmd.Parameters.AddWithValue("id", insertedId!);
|
|
var rowsAffected = await updateCmd.ExecuteNonQueryAsync();
|
|
rowsAffected.Should().Be(1);
|
|
|
|
// Act - Delete
|
|
using var deleteCmd = connection.CreateCommand();
|
|
deleteCmd.CommandText = "DELETE FROM test_crud WHERE id = @id";
|
|
deleteCmd.Parameters.AddWithValue("id", insertedId!);
|
|
rowsAffected = await deleteCmd.ExecuteNonQueryAsync();
|
|
rowsAffected.Should().Be(1);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region T1.13-AC3: Schema migrations run successfully
|
|
|
|
[Fact(DisplayName = "T1.13-AC3.1: Can run DDL migrations")]
|
|
public async Task Database_CanRunDdlMigrations()
|
|
{
|
|
// Arrange
|
|
using var connection = new Npgsql.NpgsqlConnection(_connectionString);
|
|
await connection.OpenAsync();
|
|
|
|
// Act - Run a migration-like DDL script
|
|
var migrationScript = @"
|
|
-- V1: Create migrations tracking table
|
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
version VARCHAR(50) PRIMARY KEY,
|
|
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
checksum VARCHAR(64) NOT NULL
|
|
);
|
|
|
|
-- V2: Create sample domain table
|
|
CREATE TABLE IF NOT EXISTS scan_results (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
image_ref TEXT NOT NULL,
|
|
findings_count INT NOT NULL DEFAULT 0,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
-- Record migration
|
|
INSERT INTO schema_migrations (version, checksum)
|
|
VALUES ('V2_create_scan_results', 'abc123')
|
|
ON CONFLICT (version) DO NOTHING;
|
|
";
|
|
|
|
using var migrateCmd = connection.CreateCommand();
|
|
migrateCmd.CommandText = migrationScript;
|
|
await migrateCmd.ExecuteNonQueryAsync();
|
|
|
|
// Assert - Verify migration recorded
|
|
using var verifyCmd = connection.CreateCommand();
|
|
verifyCmd.CommandText = "SELECT COUNT(*) FROM schema_migrations WHERE version = 'V2_create_scan_results'";
|
|
var count = await verifyCmd.ExecuteScalarAsync();
|
|
Convert.ToInt32(count).Should().Be(1);
|
|
}
|
|
|
|
[Fact(DisplayName = "T1.13-AC3.2: PostgreSQL extensions can be created")]
|
|
public async Task Database_CanCreateExtensions()
|
|
{
|
|
// Arrange
|
|
using var connection = new Npgsql.NpgsqlConnection(_connectionString);
|
|
await connection.OpenAsync();
|
|
|
|
// Act - Create common extensions used by StellaOps
|
|
using var extCmd = connection.CreateCommand();
|
|
extCmd.CommandText = "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"";
|
|
await extCmd.ExecuteNonQueryAsync();
|
|
|
|
// Assert - Verify extension exists
|
|
using var verifyCmd = connection.CreateCommand();
|
|
verifyCmd.CommandText = "SELECT COUNT(*) FROM pg_extension WHERE extname = 'uuid-ossp'";
|
|
var count = await verifyCmd.ExecuteScalarAsync();
|
|
Convert.ToInt32(count).Should().Be(1);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region T1.13-AC4: No MongoDB connection attempts
|
|
|
|
[Fact(DisplayName = "T1.13-AC4.1: Environment variables contain no MongoDB references")]
|
|
public void EnvironmentVariables_ContainNoMongoDbReferences()
|
|
{
|
|
// Arrange - Get all environment variables
|
|
var envVars = Environment.GetEnvironmentVariables();
|
|
|
|
// Act & Assert
|
|
foreach (string key in envVars.Keys)
|
|
{
|
|
var value = envVars[key]?.ToString() ?? "";
|
|
|
|
// Skip if this is our test connection string
|
|
if (key.Contains("POSTGRES", StringComparison.OrdinalIgnoreCase))
|
|
continue;
|
|
|
|
key.Should().NotContainEquivalentOf("mongo",
|
|
$"Environment variable key '{key}' should not reference MongoDB");
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "T1.13-AC4.2: PostgreSQL-only configuration is valid")]
|
|
public void Configuration_IsPostgresOnly()
|
|
{
|
|
// This test documents the expected configuration pattern
|
|
var expectedConfig = new Dictionary<string, string>
|
|
{
|
|
["STELLAOPS_STORAGE_DRIVER"] = "postgres",
|
|
["STELLAOPS_CACHE_DRIVER"] = "valkey", // or "redis" for compatibility
|
|
};
|
|
|
|
// Assert - Document the expected pattern
|
|
expectedConfig["STELLAOPS_STORAGE_DRIVER"].Should().NotBe("mongodb");
|
|
expectedConfig["STELLAOPS_STORAGE_DRIVER"].Should().Be("postgres");
|
|
}
|
|
|
|
#endregion
|
|
}
|