feat: complete catalog sensitivity enhancements
This commit is contained in:
@@ -73,7 +73,7 @@ const running: SensitivityAnalysisRun = {
|
||||
scope: "all",
|
||||
engine: "local",
|
||||
modelId: null,
|
||||
policyVersion: "sensitivity-v2",
|
||||
policyVersion: "sensitivity-v4",
|
||||
status: "running",
|
||||
total: 0,
|
||||
suggestedSensitive: 0,
|
||||
@@ -132,27 +132,36 @@ test("classifies all selected tables in one breadth-first run and reports covera
|
||||
tableId === firstTable.id ? [firstColumn] : [secondColumn]
|
||||
)),
|
||||
} as unknown as CatalogRepository;
|
||||
const assess = vi.fn(async () => [
|
||||
{
|
||||
columnId: firstColumn.id,
|
||||
assessment: "non_sensitive" as const,
|
||||
proposedSensitive: false,
|
||||
evidence: [{ kind: "coverage" as const, ruleId: "coverage.sampled_1000" }],
|
||||
observedValues: 1_000,
|
||||
coverage: "sampled" as const,
|
||||
},
|
||||
{
|
||||
columnId: secondColumn.id,
|
||||
assessment: "sensitive" as const,
|
||||
proposedSensitive: true,
|
||||
evidence: [{ kind: "content" as const, ruleId: "pii.email" }],
|
||||
observedValues: 12,
|
||||
coverage: "sampled" as const,
|
||||
},
|
||||
]);
|
||||
const assess = vi.fn(async (
|
||||
_targets,
|
||||
_signal,
|
||||
_nerBudget,
|
||||
onActivity?: (message: string) => void | Promise<void>,
|
||||
) => {
|
||||
await onActivity?.("Scanning source data: pass 1 of 3, table batch 1 of 1.");
|
||||
return [
|
||||
{
|
||||
columnId: firstColumn.id,
|
||||
assessment: "non_sensitive" as const,
|
||||
proposedSensitive: false,
|
||||
evidence: [{ kind: "coverage" as const, ruleId: "coverage.sampled_1000" }],
|
||||
observedValues: 1_000,
|
||||
coverage: "sampled" as const,
|
||||
},
|
||||
{
|
||||
columnId: secondColumn.id,
|
||||
assessment: "sensitive" as const,
|
||||
proposedSensitive: true,
|
||||
evidence: [{ kind: "content" as const, ruleId: "pii.email" }],
|
||||
observedValues: 12,
|
||||
coverage: "sampled" as const,
|
||||
},
|
||||
];
|
||||
});
|
||||
const classifier = { assess } as unknown as SensitivityClassifier;
|
||||
const onPrepared = vi.fn();
|
||||
const onProgress = vi.fn();
|
||||
const onActivity = vi.fn();
|
||||
|
||||
const suggestions = await new SensitivityAnalysisService(repository, classifier).analyze(
|
||||
database.id,
|
||||
@@ -161,6 +170,7 @@ test("classifies all selected tables in one breadth-first run and reports covera
|
||||
new AbortController().signal,
|
||||
onPrepared,
|
||||
onProgress,
|
||||
onActivity,
|
||||
);
|
||||
|
||||
expect(assess).toHaveBeenCalledOnce();
|
||||
@@ -169,6 +179,9 @@ test("classifies all selected tables in one breadth-first run and reports covera
|
||||
{ database, table: secondTable, columns: [secondColumn] },
|
||||
]);
|
||||
expect(onPrepared).toHaveBeenCalledWith(2);
|
||||
expect(onActivity).toHaveBeenCalledWith(
|
||||
"Scanning source data: pass 1 of 3, table batch 1 of 1.",
|
||||
);
|
||||
expect(onProgress.mock.calls.map(([processed]) => processed)).toEqual([1, 2]);
|
||||
expect(suggestions).toEqual([
|
||||
expect.objectContaining({ columnId: firstColumn.id, sensitive: false, coverage: "sampled" }),
|
||||
@@ -176,6 +189,52 @@ test("classifies all selected tables in one breadth-first run and reports covera
|
||||
]);
|
||||
});
|
||||
|
||||
test("persists classifier activity in the running analysis event log", async () => {
|
||||
let persisted = running;
|
||||
const appendEvent = vi.fn(async () => undefined);
|
||||
const repository = {
|
||||
get: vi.fn(async () => database),
|
||||
createSensitivityAnalysisRun: vi.fn(async () => running),
|
||||
getSensitivityAnalysisRun: vi.fn(async () => persisted),
|
||||
updateSensitivityAnalysisRun: vi.fn(async (
|
||||
_runId: string,
|
||||
changes: Partial<SensitivityAnalysisRun>,
|
||||
) => {
|
||||
persisted = { ...persisted, ...changes };
|
||||
return persisted;
|
||||
}),
|
||||
appendSensitivityAnalysisEvent: appendEvent,
|
||||
} as unknown as CatalogRepository;
|
||||
const analysis = {
|
||||
analyze: vi.fn(async (
|
||||
_databaseId,
|
||||
_scope,
|
||||
_targetIds,
|
||||
_signal,
|
||||
onPrepared,
|
||||
_onProgress,
|
||||
onActivity,
|
||||
) => {
|
||||
await onPrepared?.(0);
|
||||
await onActivity?.("Scanning source data: pass 1 of 3, table batch 1 of 1.");
|
||||
return [];
|
||||
}),
|
||||
} as unknown as SensitivityAnalysisService;
|
||||
|
||||
await new SensitivityAnalysisRunner(repository, analysis).run(
|
||||
database.id,
|
||||
"all",
|
||||
[],
|
||||
new AbortController().signal,
|
||||
);
|
||||
|
||||
expect(appendEvent).toHaveBeenCalledWith(
|
||||
running.id,
|
||||
"info",
|
||||
"Scanning source data: pass 1 of 3, table batch 1 of 1.",
|
||||
);
|
||||
});
|
||||
|
||||
test("marks a created run interrupted if the request deadline expires during persistence", async () => {
|
||||
const controller = new AbortController();
|
||||
const update = vi.fn(async (_runId: string, changes: Partial<SensitivityAnalysisRun>) => ({
|
||||
|
||||
Reference in New Issue
Block a user