feat: complete catalog sensitivity enhancements
This commit is contained in:
@@ -69,6 +69,32 @@ function source(scan: SensitivityTableScan): SensitivityValueSource {
|
||||
}) };
|
||||
}
|
||||
|
||||
test("reports source-scan activity before a long table scan completes", async () => {
|
||||
let releaseScan!: () => void;
|
||||
const scanGate = new Promise<void>((resolve) => {
|
||||
releaseScan = resolve;
|
||||
});
|
||||
const scanTable = vi.fn(async () => {
|
||||
await scanGate;
|
||||
return { kind: "complete" as const, observedValues: 0 };
|
||||
});
|
||||
const activity = vi.fn();
|
||||
const analysis = new SensitivityClassifier({ scanTable }).assess(
|
||||
[{ database, table, columns: [column()] }],
|
||||
new AbortController().signal,
|
||||
undefined,
|
||||
activity,
|
||||
);
|
||||
|
||||
await vi.waitFor(() => expect(scanTable).toHaveBeenCalledOnce());
|
||||
releaseScan();
|
||||
await analysis;
|
||||
|
||||
expect(activity).toHaveBeenCalledWith(
|
||||
"Scanning source data: pass 1 of 3, table batch 1 of 1.",
|
||||
);
|
||||
});
|
||||
|
||||
test("one email hidden in a generically named column makes the whole column sensitive", async () => {
|
||||
const target = column();
|
||||
const values = source({
|
||||
@@ -351,6 +377,98 @@ test("strong Italian PII metadata is sensitive even when the source column is em
|
||||
expect(values.scanTable).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("excludes bigint primary keys from content analysis as non-informative identifiers", async () => {
|
||||
const target = column({
|
||||
name: "id",
|
||||
dataType: "bigint",
|
||||
primaryKeyPosition: 1,
|
||||
isPrimaryKey: true,
|
||||
});
|
||||
const values = source({
|
||||
batches: [[{
|
||||
columnId: target.id,
|
||||
value: "3471234567",
|
||||
characterLength: 10,
|
||||
}]],
|
||||
coverage: { kind: "complete", observedValues: 1 },
|
||||
});
|
||||
|
||||
const [assessment] = await new SensitivityClassifier(values).assessTable(
|
||||
{ database, table, columns: [target] },
|
||||
new AbortController().signal,
|
||||
);
|
||||
|
||||
expect(assessment).toMatchObject({
|
||||
assessment: "non_sensitive",
|
||||
proposedSensitive: false,
|
||||
evidence: [{
|
||||
kind: "type",
|
||||
ruleId: "type.bigint_primary_key_non_informative",
|
||||
label: "non-informative bigint primary key",
|
||||
}],
|
||||
coverage: "metadata",
|
||||
});
|
||||
expect(values.scanTable).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("infers an undeclared bigint column named pk as a non-informative primary-key identifier", async () => {
|
||||
const target = column({
|
||||
name: "pk",
|
||||
dataType: "bigint",
|
||||
primaryKeyPosition: null,
|
||||
isPrimaryKey: false,
|
||||
});
|
||||
const values = source({
|
||||
batches: [[{
|
||||
columnId: target.id,
|
||||
value: "3471234567",
|
||||
characterLength: 10,
|
||||
}]],
|
||||
coverage: { kind: "complete", observedValues: 1 },
|
||||
});
|
||||
|
||||
const [assessment] = await new SensitivityClassifier(values).assessTable(
|
||||
{ database, table, columns: [target] },
|
||||
new AbortController().signal,
|
||||
);
|
||||
|
||||
expect(assessment).toMatchObject({
|
||||
assessment: "non_sensitive",
|
||||
proposedSensitive: false,
|
||||
evidence: [{
|
||||
kind: "metadata",
|
||||
ruleId: "metadata.bigint_pk_identifier_non_informative",
|
||||
label: "non-informative conventional bigint primary-key identifier",
|
||||
}],
|
||||
coverage: "metadata",
|
||||
});
|
||||
expect(values.scanTable).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("still inspects phone-like values in bigint columns that are not primary keys", async () => {
|
||||
const target = column({ name: "id", dataType: "bigint" });
|
||||
const values = source({
|
||||
batches: [[{
|
||||
columnId: target.id,
|
||||
value: "3471234567",
|
||||
characterLength: 10,
|
||||
}]],
|
||||
coverage: { kind: "complete", observedValues: 1 },
|
||||
});
|
||||
|
||||
const [assessment] = await new SensitivityClassifier(values).assessTable(
|
||||
{ database, table, columns: [target] },
|
||||
new AbortController().signal,
|
||||
);
|
||||
|
||||
expect(assessment).toMatchObject({
|
||||
assessment: "sensitive",
|
||||
proposedSensitive: true,
|
||||
evidence: [{ kind: "content", ruleId: "pii.phone_number" }],
|
||||
});
|
||||
expect(values.scanTable).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
test.each([
|
||||
["RSSMRA85T10A562S", "pii.italian_fiscal_code"],
|
||||
["IT60 X054 2811 1010 0000 0123 456", "financial.iban"],
|
||||
|
||||
Reference in New Issue
Block a user