Inventory and discovery¶
Where PII is, across tables: in-memory data frames, Arrow, DuckDB, Spark and BigQuery all produce the same inventory.
pii_inventory ¶
pii_inventory(data: Any, source: str, table: str, sample: int = 10000, min_rate: float = 0.0, detectors: Sequence[str] | None = None, seed: int = 42) -> Inventory
Scan a table and record where PII is, for an inventory.
Uses the same rules as :func:scan_pii, but records every column -
including those where nothing was found - with the source and table
names, the sample size and method, and when and by what it was scanned.
No values are recorded, not even masked ones. Combine the inventories of
several tables with + and save them with :meth:Inventory.write.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
Any
|
Any table :func: |
required |
source
|
str
|
Name of the data source, chosen by you (e.g. |
required |
table
|
str
|
Name of the table within the source (e.g. |
required |
sample
|
int
|
As for :func: |
10000
|
min_rate
|
float
|
As for :func: |
0.0
|
detectors
|
Sequence[str] | None
|
As for :func: |
None
|
seed
|
int
|
As for :func: |
42
|
Inventory ¶
Inventory(rows: Iterable[InventoryRow] = ())
Bases: list[InventoryRow]
Rows of an inventory; combine inventories with + and save them with
:meth:write. Prints as a summary per table.
InventoryRow
dataclass
¶
InventoryRow(source: str, table: str, column: str, type: str | None, data_class: str | None, n_rows: int | None, n_sampled: int, n_matched: int, n_full: int, rate: float, mean_confidence: float | None, sample_method: str, scanned_at: str, credgate: str, v: int = FORMAT_VERSION)
One column of one table, and one PII type found in it (type is
None for a column scanned without finding any).
read_inventory ¶
read_inventory(path: str | PathLike[str]) -> Inventory
Read an inventory CSV file written by :meth:Inventory.write (in R or
Python).
Databases¶
PII inventories of whole databases (the spec's "Databases" rules).
Every table in the chosen schemas is sampled by the database where it can
(Postgres and Db2 TABLESAMPLE SYSTEM, DuckDB a reservoir sample), and only
the sample is read. With an inventory file, the scan can resume after an
interruption, and later runs rescan only the tables that changed.
import sqlalchemy
from credgate.database import inventory_database
engine = sqlalchemy.create_engine("postgresql+psycopg://reader@db/crm")
inv = inventory_database(engine, source="postgres:crm", path="inventory.csv")
credgate makes no network calls of its own: it uses the engine you pass.
DatabaseInventory ¶
DatabaseInventory(rows: Any = (), failed: dict[str, str] | None = None, skipped: Sequence[str] = ())
Bases: Inventory
An :class:~credgate.Inventory of a database, with the tables that
could not be read (failed: schema.table -> error message) and
those kept from an earlier run (skipped).
inventory_database ¶
inventory_database(connection: Any, source: str, path: str | PathLike[str] | None = None, schemas: Sequence[str] | None = None, include: Sequence[str] | None = None, exclude: Sequence[str] | None = None, views: bool = False, sample: int = 10000, min_rate: float = 0.0, detectors: Sequence[str] | None = None, max_age: float = 30, on_error: str = 'warn') -> DatabaseInventory
Record where PII is in every table of a database.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
connection
|
Any
|
A SQLAlchemy |
required |
source
|
str
|
Name of the data source for the inventory, e.g. |
required |
path
|
str | PathLike[str] | None
|
Optional inventory file (CSV). Existing rows are read first;
tables scanned within |
None
|
schemas
|
Sequence[str] | None
|
Schemas to scan; default all except the database's own. |
None
|
include
|
Sequence[str] | None
|
Shell-style patterns for |
None
|
exclude
|
Sequence[str] | None
|
Patterns for |
None
|
views
|
bool
|
Also scan views (reading a view runs its query). |
False
|
sample
|
int
|
Maximum number of rows read per table. |
10000
|
min_rate
|
float
|
As for :func: |
0.0
|
detectors
|
Sequence[str] | None
|
As for :func: |
None
|
max_age
|
float
|
Days after which a table is scanned again even if unchanged. |
30
|
on_error
|
str
|
|
'warn'
|
sample_query ¶
sample_query(family: str, schema: str, table: str, n: int, columns: Sequence[tuple[str, str]], sample: int = 10000) -> tuple[str | None, list[str], str, int | None]
The query that samples a table, the columns it reads, the sample
method, and how many rows to read (None: all the query returns), as
the spec's "Databases" rules say. columns are (name, type).
BigQuery¶
PII scans and inventories of BigQuery tables (the spec's "BigQuery tables" rules).
BigQuery samples the table and only the sample is downloaded; a dry run
checks the cost of every query first. credgate makes no network calls of
its own: it uses the google.cloud.bigquery.Client you pass, with its
credentials and project.
from google.cloud import bigquery
from credgate import bigquery as cgbq
client = bigquery.Client(project="my-project")
cgbq.scan_pii(client, "my-project.crm.customers")
inv = cgbq.inventory_dataset(client, "my-project.crm")
CostLimitError ¶
Bases: RuntimeError
A query would process more bytes than max_bytes allows; nothing ran.
scan_pii ¶
scan_pii(client: Any, table: Any, sample: int = 10000, min_rate: float = 0.0, detectors: Sequence[str] | None = None, sampling: str = 'tablesample', max_bytes: int = MAX_BYTES) -> ScanReport
Scan the columns of a BigQuery table for PII (see :func:credgate.scan_pii).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
Any
|
A |
required |
table
|
Any
|
|
required |
sample
|
int
|
Maximum number of rows sampled. |
10000
|
min_rate
|
float
|
As for :func: |
0.0
|
detectors
|
Sequence[str] | None
|
As for :func: |
None
|
sampling
|
str
|
|
'tablesample'
|
max_bytes
|
int
|
Refuse any query estimated to process more bytes than this (default 1 GB). Also sent to BigQuery as the billing limit, except with TABLESAMPLE, where BigQuery would check it against the whole table. |
MAX_BYTES
|
pii_inventory ¶
pii_inventory(client: Any, table: Any, source: str | None = None, sample: int = 10000, min_rate: float = 0.0, detectors: Sequence[str] | None = None, sampling: str = 'tablesample', max_bytes: int = MAX_BYTES) -> Inventory
Record where PII is in a BigQuery table (see :func:credgate.pii_inventory).
The source defaults to "bigquery:<project>" and the table name to
"dataset.table". Other arguments as for :func:scan_pii.
inventory_dataset ¶
inventory_dataset(client: Any, dataset: Any, source: str | None = None, sample: int = 10000, min_rate: float = 0.0, detectors: Sequence[str] | None = None, sampling: str = 'tablesample', max_bytes: int = MAX_BYTES) -> Inventory
The inventory of every table and view in a dataset ("project.dataset").
Stops at the first table whose query would exceed max_bytes. Other
arguments as for :func:pii_inventory.
sample_query ¶
sample_query(table: str, kind: str, n: int, fields: Sequence[tuple[str, str, str]], sample: int = 10000, sampling: str = 'tablesample') -> tuple[str | None, list[str], str]
The query that samples a table, the columns it reads and the sample
method (spec: "BigQuery tables"). fields are (name, type, mode).