feat(security): audit batch C — data posture, retention, DP keys (#22)
CI / backend (push) Successful in 52s
CI / frontend (push) Successful in 11s
Deploy Staging / deploy (push) Successful in 24s
Security / secrets (push) Successful in 4s
Security / dependencies (push) Successful in 52s
CI / backend (pull_request) Successful in 49s
CI / frontend (pull_request) Successful in 10s
Security / secrets (pull_request) Successful in 3s
Security / dependencies (pull_request) Successful in 55s
CI / backend (push) Successful in 52s
CI / frontend (push) Successful in 11s
Deploy Staging / deploy (push) Successful in 24s
Security / secrets (push) Successful in 4s
Security / dependencies (push) Successful in 52s
CI / backend (pull_request) Successful in 49s
CI / frontend (pull_request) Successful in 10s
Security / secrets (pull_request) Successful in 3s
Security / dependencies (pull_request) Successful in 55s
This commit was merged in pull request #22.
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
using FluentAssertions;
|
||||
using InboxIntel.Application.Abstractions;
|
||||
using InboxIntel.Domain.Entities;
|
||||
using InboxIntel.Infrastructure.Configuration;
|
||||
using InboxIntel.Infrastructure.Persistence;
|
||||
using InboxIntel.Infrastructure.Retention;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Xunit;
|
||||
|
||||
namespace InboxIntel.IntegrationTests;
|
||||
|
||||
/// <summary>
|
||||
/// AUDIT H-3 (retention): the purge removes only what the configuration targets and is a
|
||||
/// no-op while disabled — locking the "no behaviour change until opted in" guarantee.
|
||||
/// </summary>
|
||||
public class RetentionServiceTests
|
||||
{
|
||||
private sealed class FakeCurrentUser : ICurrentUser
|
||||
{
|
||||
public Guid UserId => Guid.Empty; // worker scope
|
||||
public bool IsAuthenticated => false;
|
||||
}
|
||||
|
||||
private static AppDbContext NewDb(string name) =>
|
||||
new(new DbContextOptionsBuilder<AppDbContext>().UseInMemoryDatabase(name).Options, new FakeCurrentUser());
|
||||
|
||||
private static async Task SeedAsync(AppDbContext db)
|
||||
{
|
||||
var user = Guid.NewGuid();
|
||||
db.Emails.AddRange(
|
||||
new Email { UserId = user, GmailMessageId = "old-trashed", IsTrashed = true, SentAtUtc = DateTimeOffset.UtcNow.AddDays(-100) },
|
||||
new Email { UserId = user, GmailMessageId = "new-trashed", IsTrashed = true, SentAtUtc = DateTimeOffset.UtcNow.AddDays(-5) },
|
||||
new Email { UserId = user, GmailMessageId = "old-kept", IsTrashed = false, SentAtUtc = DateTimeOffset.UtcNow.AddDays(-100) });
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private static RetentionService Sut(AppDbContext db, int trashedDays = 0, int allDays = 0) =>
|
||||
new(db, Options.Create(new DataRetentionOptions
|
||||
{
|
||||
PurgeTrashedAfterDays = trashedDays,
|
||||
PurgeAllAfterDays = allDays
|
||||
}), NullLogger<RetentionService>.Instance);
|
||||
|
||||
[Fact]
|
||||
public async Task Disabled_retention_purges_nothing()
|
||||
{
|
||||
using var db = NewDb(nameof(Disabled_retention_purges_nothing));
|
||||
await SeedAsync(db);
|
||||
(await Sut(db).PurgeAsync()).Should().Be(0);
|
||||
(await db.Emails.CountAsync()).Should().Be(3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Trashed_purge_removes_only_old_trashed_emails()
|
||||
{
|
||||
using var db = NewDb(nameof(Trashed_purge_removes_only_old_trashed_emails));
|
||||
await SeedAsync(db);
|
||||
(await Sut(db, trashedDays: 30).PurgeAsync()).Should().Be(1);
|
||||
var remaining = await db.Emails.Select(e => e.GmailMessageId).ToListAsync();
|
||||
remaining.Should().BeEquivalentTo(new[] { "new-trashed", "old-kept" });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Age_purge_removes_everything_past_the_cutoff()
|
||||
{
|
||||
using var db = NewDb(nameof(Age_purge_removes_everything_past_the_cutoff));
|
||||
await SeedAsync(db);
|
||||
(await Sut(db, allDays: 30).PurgeAsync()).Should().Be(2); // both 100-day-old emails
|
||||
(await db.Emails.SingleAsync()).GmailMessageId.Should().Be("new-trashed");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user