feature: PHI Column Encryption + Access Logging
This commit is contained in:
@@ -11,6 +11,7 @@ public static class DbResetHelper
|
||||
try
|
||||
{
|
||||
await db.Database.ExecuteSqlRawAsync(@"
|
||||
DELETE FROM phi_access_logs;
|
||||
DELETE FROM medication_administrations;
|
||||
DELETE FROM sepsis_bundle_elements;
|
||||
DELETE FROM sepsis_bundles;
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using FluentAssertions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
[Collection("Integration")]
|
||||
public class PhiEncryptionTests
|
||||
{
|
||||
private readonly ApiFixture _fixture;
|
||||
|
||||
public PhiEncryptionTests(ApiFixture fixture) => _fixture = fixture;
|
||||
|
||||
[Fact]
|
||||
public async Task PatientPhi_StoredEncrypted_ReturnsDecryptedViaApi()
|
||||
{
|
||||
var client = _fixture.CreateClient();
|
||||
client.ClearAuth();
|
||||
client.AsAdmin();
|
||||
|
||||
var registerResp = await client.PostAsJsonAsync("/api/v1/patients", new
|
||||
{
|
||||
firstName = "Encrypted",
|
||||
lastName = "Patient",
|
||||
dateOfBirth = "1990-05-20",
|
||||
gender = "female"
|
||||
});
|
||||
registerResp.EnsureSuccessStatusCode();
|
||||
var body = await registerResp.Content.ReadFromJsonAsync<JsonElement>();
|
||||
var patientId = body.GetProperty("data").GetProperty("id").GetGuid();
|
||||
|
||||
// Raw DB check — first_name should NOT equal plaintext
|
||||
using var scope = _fixture.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
var raw = await db.Database
|
||||
.SqlQueryRaw<string>($"SELECT first_name AS \"Value\" FROM patients WHERE id = '{patientId}'")
|
||||
.FirstAsync();
|
||||
raw.Should().NotBe("Encrypted");
|
||||
|
||||
// API returns decrypted
|
||||
var getResp = await client.GetAsync($"/api/v1/patients/{patientId}");
|
||||
getResp.EnsureSuccessStatusCode();
|
||||
var patient = await getResp.Content.ReadFromJsonAsync<JsonElement>();
|
||||
patient.GetProperty("data").GetProperty("firstName").GetString()
|
||||
.Should().Be("Encrypted");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PatientView_WritesPhiAccessLog()
|
||||
{
|
||||
var client = _fixture.CreateClient();
|
||||
client.ClearAuth();
|
||||
var nurseId = Guid.Parse("11111111-1111-1111-1111-111111111111");
|
||||
client.AsNurse(nurseId);
|
||||
|
||||
await client.PostAsJsonAsync("/api/v1/patients", new
|
||||
{
|
||||
firstName = "PhiLog",
|
||||
lastName = "TestPatient",
|
||||
dateOfBirth = "1975-03-15",
|
||||
gender = "male"
|
||||
});
|
||||
|
||||
var listResp = await client.GetAsync("/api/v1/patients?pageSize=1");
|
||||
listResp.EnsureSuccessStatusCode();
|
||||
var list = await listResp.Content.ReadFromJsonAsync<JsonElement>();
|
||||
var patientId = list.GetProperty("data").GetProperty("items")[0].GetProperty("id").GetGuid();
|
||||
|
||||
await client.GetAsync($"/api/v1/patients/{patientId}");
|
||||
|
||||
client.ClearAuth();
|
||||
client.AsAdmin();
|
||||
var logsResp = await client.GetAsync($"/api/v1/phi-access-logs?patientId={patientId}");
|
||||
logsResp.EnsureSuccessStatusCode();
|
||||
var logs = await logsResp.Content.ReadFromJsonAsync<JsonElement>();
|
||||
logs.GetProperty("data").GetProperty("totalCount").GetInt32()
|
||||
.Should().BeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NameSearch_FindsEncryptedPatient()
|
||||
{
|
||||
var client = _fixture.CreateClient();
|
||||
client.ClearAuth();
|
||||
client.AsAdmin();
|
||||
|
||||
await client.PostAsJsonAsync("/api/v1/patients", new
|
||||
{
|
||||
firstName = "Searchable",
|
||||
lastName = "UniqueName",
|
||||
dateOfBirth = "1985-01-01",
|
||||
gender = "male"
|
||||
});
|
||||
|
||||
var resp = await client.GetAsync("/api/v1/patients?q=Searchable+UniqueName");
|
||||
resp.EnsureSuccessStatusCode();
|
||||
var body = await resp.Content.ReadFromJsonAsync<JsonElement>();
|
||||
body.GetProperty("data").GetProperty("totalCount").GetInt32()
|
||||
.Should().BeGreaterThan(0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user