sql-safe-mcp 1.5.1__tar.gz → 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/CHANGELOG.md +71 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/PKG-INFO +12 -7
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/README.md +9 -4
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/pyproject.toml +4 -4
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/server.json +2 -2
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/sql-safe-mcp.example-multi.yaml +6 -2
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/sql-safe-mcp.example-shared.yaml +18 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/__init__.py +1 -1
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/__main__.py +21 -1
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/config.py +215 -31
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/diagnostics.py +18 -2
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/mcp_server.py +8 -1
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/models.py +3 -1
- sql_safe_mcp-2.0.0/src/sql_safe_mcp/pii_audit.py +200 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/security/executor.py +15 -2
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/security/lineage.py +21 -13
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/security/parser.py +49 -1
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/security/pipeline.py +1 -0
- sql_safe_mcp-2.0.0/src/sql_safe_mcp/security/policy.py +147 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/security/reasons.py +3 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/security/schema.py +51 -5
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/security/tokens.py +102 -54
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/security/validated_query.py +43 -3
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/service.py +67 -3
- sql_safe_mcp-1.5.1/src/sql_safe_mcp/security/policy.py +0 -104
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/.gitignore +0 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/LICENSE +0 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/sql-safe-mcp.example-simple.yaml +0 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/db/__init__.py +0 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/db/extras.py +0 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/db/mysql.py +0 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/db/reflection.py +0 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/db/registry.py +0 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/db/sqlserver.py +0 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/errors.py +0 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/security/__init__.py +0 -0
- {sql_safe_mcp-1.5.1 → sql_safe_mcp-2.0.0}/src/sql_safe_mcp/security/dialect.py +0 -0
|
@@ -7,6 +7,77 @@ categories `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, and `Security`.
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.0.0] - 2026-11-07
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `sql-safe-mcp --verify-pii-rules [--strict]` connects to each `all_pii_safe` alias, reports how
|
|
15
|
+
many tables and columns every PII rule matches, and warns about rules that match nothing
|
|
16
|
+
(exit 2 with `--strict`) and about unprotected columns whose names look personal.
|
|
17
|
+
- `logging.audit: true` writes one `sql_safe_mcp.audit` line per `execute_sql` call with the server,
|
|
18
|
+
database, tables and columns read, protected column count, row count, truncation, and elapsed
|
|
19
|
+
time (or the error `code`). It never contains SQL, bind values, rows, or tokens. Off by default;
|
|
20
|
+
the tool response is unchanged.
|
|
21
|
+
- `--verify-pii-rules` also checks `pii.exposed_columns` and `pii.deny` entries (unmatched ones
|
|
22
|
+
warn and fail `--strict`) and, in `deny-by-default`, advises only on exposed columns.
|
|
23
|
+
- `pii.mode: deny-by-default` protects every column not listed in `pii.exposed_columns`, and
|
|
24
|
+
`pii.deny` rejects any reference to a column with `QUERY_REJECTED` ("a denied column cannot be
|
|
25
|
+
referenced"). Existing configurations are unchanged. See `docs/configuration.md`.
|
|
26
|
+
- `runtime.token_ttl_seconds` (off by default) rejects tokens older than the limit with
|
|
27
|
+
`INVALID_PII_TOKEN`. Enabling it also rejects tokens issued before it was set. The token format
|
|
28
|
+
stays `pii:v1:`.
|
|
29
|
+
- `runtime.min_count_cell` (off by default) makes `execute_sql` return a `COUNT(*)` value from 1
|
|
30
|
+
to the threshold minus one as `null`, with the new column encoding `suppressed`. `0` is not
|
|
31
|
+
suppressed.
|
|
32
|
+
- `pii_key_file` reads an alias key from a file instead of `pii_key_env`; a relative path is
|
|
33
|
+
resolved against the configuration file's directory. On POSIX the file must be owned by the
|
|
34
|
+
server user or root, with no access for others and no group write.
|
|
35
|
+
|
|
36
|
+
### Security
|
|
37
|
+
|
|
38
|
+
- With `logging.level: DEBUG`, the MCP SDK no longer writes a malformed protocol message to
|
|
39
|
+
stderr; its logger is held at `INFO` or above, because that message could carry SQL, tokens,
|
|
40
|
+
or rows.
|
|
41
|
+
- `all_pii_safe` aliases now require verified TLS in `connection_url`: SQL Server needs
|
|
42
|
+
`Encrypt=yes` and rejects `TrustServerCertificate=yes` and `odbc_connect`; MySQL and MariaDB
|
|
43
|
+
need `ssl_ca` or `ssl_capath` and reject options that turn certificate checks off. A
|
|
44
|
+
configuration without them fails at startup with `CONFIG_ERROR`. `require_tls: false` on the
|
|
45
|
+
alias turns the check off and logs a warning at every start.
|
|
46
|
+
- After loading the configuration, the server removes `pii_key_env` variables from its environment,
|
|
47
|
+
so child processes such as ODBC drivers no longer inherit PII keys.
|
|
48
|
+
- `pii.rules` entries accept an optional `domain`. A token returned for a column of one domain is
|
|
49
|
+
rejected with `INVALID_PII_TOKEN` when compared with a column of another domain, so protected
|
|
50
|
+
values cannot be replayed across unrelated columns. Without `domain` the domain is the server
|
|
51
|
+
alias. Rules of different domains matching one column reject queries touching it with
|
|
52
|
+
`QUERY_REJECTED`.
|
|
53
|
+
- PII tokens now pad their payload to a multiple of 32 bytes, so token length reveals only a
|
|
54
|
+
32-byte bucket of the plaintext length.
|
|
55
|
+
- Tokens issued before padding and domains are rejected with `INVALID_PII_TOKEN`; agents must
|
|
56
|
+
request new tokens.
|
|
57
|
+
- `execute_sql` now allows each SQL construct only in the positions the supported subset uses.
|
|
58
|
+
A bare column or literal used as a condition (`WHERE a`, `ON 1`, `WHERE a AND b = 1`) and any
|
|
59
|
+
other node in an unlisted position is rejected with `QUERY_REJECTED` before the database runs
|
|
60
|
+
the query.
|
|
61
|
+
- `execute_sql` now checks a PII token against the type of the protected column it is compared
|
|
62
|
+
with. A string token compared with an integer or decimal column, or any token compared with a
|
|
63
|
+
column of an unrecognised type, is rejected with `QUERY_REJECTED` before the database runs the
|
|
64
|
+
query. Before, SQL Server could echo the decrypted value in a conversion error (for example
|
|
65
|
+
error 245).
|
|
66
|
+
- Driver error messages in logs no longer carry values. Quoted literals (`'…'`, `N'…'`, `"…"`)
|
|
67
|
+
become `'***'` and digit runs of six or more become `***`, since SQL Server and MySQL echo the
|
|
68
|
+
offending value in conversion and duplicate-key errors. A failed `execute_sql` logs only the
|
|
69
|
+
driver error class and its SQLSTATE or numeric code, with no message text.
|
|
70
|
+
|
|
71
|
+
## [1.5.2] - 2026-10-05
|
|
72
|
+
|
|
73
|
+
### Security
|
|
74
|
+
|
|
75
|
+
- `execute_sql` now rejects a projection whose alias names anything other than a direct column,
|
|
76
|
+
a literal, or `COUNT(*)`, such as `SELECT (Email) AS e FROM Users`. Before, the expression was
|
|
77
|
+
classified as a literal, so a protected column wrapped in parentheses was returned in clear,
|
|
78
|
+
and on MySQL/MariaDB a projected comparison such as `(Email > 'm') AS x` acted as an oracle on
|
|
79
|
+
the protected value. The lineage stage also fails closed on any untraceable projection.
|
|
80
|
+
|
|
10
81
|
## [1.5.1] - 2026-09-23
|
|
11
82
|
|
|
12
83
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sql-safe-mcp
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: Minimal, read-only, PII-safe MCP server for SQL databases.
|
|
5
5
|
License: MIT License
|
|
6
6
|
|
|
@@ -26,10 +26,10 @@ License: MIT License
|
|
|
26
26
|
License-File: LICENSE
|
|
27
27
|
Requires-Python: <3.15,>=3.12
|
|
28
28
|
Requires-Dist: anyio<5,>=4.8
|
|
29
|
-
Requires-Dist: cryptography<
|
|
29
|
+
Requires-Dist: cryptography<51,>=48.0.1
|
|
30
30
|
Requires-Dist: mcp<3,>=2
|
|
31
31
|
Requires-Dist: pydantic<3,>=2.10
|
|
32
|
-
Requires-Dist: pymysql
|
|
32
|
+
Requires-Dist: pymysql<2,>=1.2.3
|
|
33
33
|
Requires-Dist: pyodbc<6,>=5.2
|
|
34
34
|
Requires-Dist: pyyaml<7,>=6
|
|
35
35
|
Requires-Dist: sqlalchemy<3,>=2.0
|
|
@@ -133,7 +133,7 @@ or
|
|
|
133
133
|
pip install sql-safe-mcp
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
-
Pin a version when you want a fixed surface: `uvx sql-safe-mcp==
|
|
136
|
+
Pin a version when you want a fixed surface: `uvx sql-safe-mcp==2.0.0`.
|
|
137
137
|
|
|
138
138
|
Requires Python 3.12–3.14, [uv](https://docs.astral.sh/uv/) (or `pip`), and
|
|
139
139
|
[Microsoft ODBC Driver 18 for SQL Server](https://learn.microsoft.com/sql/connect/odbc/download-odbc-driver-for-sql-server)
|
|
@@ -265,9 +265,12 @@ only to stderr.
|
|
|
265
265
|
```
|
|
266
266
|
|
|
267
267
|
can return a row such as `[42, "pii:v1:..."]`: the agent can follow the customer without reading
|
|
268
|
-
the email address. A token is accepted only in `=` and `IN` predicates on the same
|
|
269
|
-
|
|
270
|
-
|
|
268
|
+
the email address. A token is accepted only in `=` and `IN` predicates on the same server alias.
|
|
269
|
+
If `FirstName` is protected, `SELECT FirstName FROM Users WHERE FirstName = 'Alice'` is rejected
|
|
270
|
+
before it reaches the database. Filter protected columns only with authentic `pii:v1:...` tokens
|
|
271
|
+
returned by `execute_sql` for the same alias; a matching prefix alone is not enough. Each token is
|
|
272
|
+
authenticated and alias-bound, then validated and converted to a bound database value.
|
|
273
|
+
Protection covers the columns you list, so list every column that holds personal data.
|
|
271
274
|
|
|
272
275
|
## Documentation
|
|
273
276
|
|
|
@@ -275,6 +278,8 @@ data.
|
|
|
275
278
|
limits, and logging.
|
|
276
279
|
- [Tool reference](docs/tools.md) - arguments, responses, errors, and the accepted SQL subset.
|
|
277
280
|
- [Security model](docs/security-model.md) - trust boundaries, guarantees, limitations, and verification.
|
|
281
|
+
- [Health data of minors](docs/health-data.md) - requirements, mechanisms, and an operator
|
|
282
|
+
checklist for medical deployments.
|
|
278
283
|
- [Checks](docs/checks.md) - local, integration, and security verification commands.
|
|
279
284
|
|
|
280
285
|
## Security
|
|
@@ -95,7 +95,7 @@ or
|
|
|
95
95
|
pip install sql-safe-mcp
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
Pin a version when you want a fixed surface: `uvx sql-safe-mcp==
|
|
98
|
+
Pin a version when you want a fixed surface: `uvx sql-safe-mcp==2.0.0`.
|
|
99
99
|
|
|
100
100
|
Requires Python 3.12–3.14, [uv](https://docs.astral.sh/uv/) (or `pip`), and
|
|
101
101
|
[Microsoft ODBC Driver 18 for SQL Server](https://learn.microsoft.com/sql/connect/odbc/download-odbc-driver-for-sql-server)
|
|
@@ -227,9 +227,12 @@ only to stderr.
|
|
|
227
227
|
```
|
|
228
228
|
|
|
229
229
|
can return a row such as `[42, "pii:v1:..."]`: the agent can follow the customer without reading
|
|
230
|
-
the email address. A token is accepted only in `=` and `IN` predicates on the same
|
|
231
|
-
|
|
232
|
-
|
|
230
|
+
the email address. A token is accepted only in `=` and `IN` predicates on the same server alias.
|
|
231
|
+
If `FirstName` is protected, `SELECT FirstName FROM Users WHERE FirstName = 'Alice'` is rejected
|
|
232
|
+
before it reaches the database. Filter protected columns only with authentic `pii:v1:...` tokens
|
|
233
|
+
returned by `execute_sql` for the same alias; a matching prefix alone is not enough. Each token is
|
|
234
|
+
authenticated and alias-bound, then validated and converted to a bound database value.
|
|
235
|
+
Protection covers the columns you list, so list every column that holds personal data.
|
|
233
236
|
|
|
234
237
|
## Documentation
|
|
235
238
|
|
|
@@ -237,6 +240,8 @@ data.
|
|
|
237
240
|
limits, and logging.
|
|
238
241
|
- [Tool reference](docs/tools.md) - arguments, responses, errors, and the accepted SQL subset.
|
|
239
242
|
- [Security model](docs/security-model.md) - trust boundaries, guarantees, limitations, and verification.
|
|
243
|
+
- [Health data of minors](docs/health-data.md) - requirements, mechanisms, and an operator
|
|
244
|
+
checklist for medical deployments.
|
|
240
245
|
- [Checks](docs/checks.md) - local, integration, and security verification commands.
|
|
241
246
|
|
|
242
247
|
## Security
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sql-safe-mcp"
|
|
3
|
-
version = "
|
|
3
|
+
version = "2.0.0"
|
|
4
4
|
description = "Minimal, read-only, PII-safe MCP server for SQL databases."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12,<3.15"
|
|
7
7
|
license = { file = "LICENSE" }
|
|
8
8
|
dependencies = [
|
|
9
9
|
"anyio>=4.8,<5",
|
|
10
|
-
"cryptography>=
|
|
10
|
+
"cryptography>=48.0.1,<51",
|
|
11
11
|
"mcp>=2,<3",
|
|
12
12
|
"pydantic>=2.10,<3",
|
|
13
|
-
"pymysql>=1.2.3",
|
|
13
|
+
"pymysql>=1.2.3,<2",
|
|
14
14
|
"pyodbc>=5.2,<6",
|
|
15
15
|
"pyyaml>=6,<7",
|
|
16
16
|
"sqlalchemy>=2.0,<3",
|
|
@@ -63,7 +63,7 @@ markers = [
|
|
|
63
63
|
[tool.mutmut]
|
|
64
64
|
source_paths = ["src/sql_safe_mcp"]
|
|
65
65
|
also_copy = ["server.json", "README.md", "tools", "scripts", "compose.sqlserver.yml", "compose.mysql.yml"]
|
|
66
|
-
only_mutate = ["*security/*.py", "*config.py"]
|
|
66
|
+
only_mutate = ["*security/*.py", "*config.py", "*diagnostics.py", "*service.py"]
|
|
67
67
|
mutate_only_covered_lines = true
|
|
68
68
|
pytest_add_cli_args = ["-q", "-m", "not integration and not deep", "-p", "no:cacheprovider"]
|
|
69
69
|
pytest_add_cli_args_test_selection = ["tests/unit", "tests/security", "tests/contract"]
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"url": "https://github.com/proprock/sql-safe-mcp",
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
|
-
"version": "
|
|
10
|
+
"version": "2.0.0",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "pypi",
|
|
14
14
|
"identifier": "sql-safe-mcp",
|
|
15
|
-
"version": "
|
|
15
|
+
"version": "2.0.0",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
}
|
|
@@ -19,11 +19,14 @@ servers:
|
|
|
19
19
|
billing:
|
|
20
20
|
# `sqlserver` uses an mssql+pyodbc URL; the URL dialect must match this engine.
|
|
21
21
|
engine: sqlserver
|
|
22
|
-
# all_pii_safe requires
|
|
22
|
+
# all_pii_safe requires a key (`pii_key_env` or `pii_key_file`) and at least one effective PII rule.
|
|
23
23
|
access_level: all_pii_safe
|
|
24
|
+
# all_pii_safe requires verified TLS: the URL must set Encrypt=yes and must not set
|
|
25
|
+
# TrustServerCertificate=yes. `require_tls: false` turns the check off for a dev server.
|
|
24
26
|
connection_url: "${BILLING_SQL_URL}"
|
|
25
27
|
# Environment-variable name for one base64-encoded 32-byte key. Names must match
|
|
26
|
-
# ^[A-Z_][A-Z0-9_]*$; each all_pii_safe alias needs a different key.
|
|
28
|
+
# ^[A-Z_][A-Z0-9_]*$; each all_pii_safe alias needs a different key. Instead of
|
|
29
|
+
# pii_key_env you may set `pii_key_file: secrets/billing.key` (relative to this file).
|
|
27
30
|
pii_key_env: BILLING_PII_KEY
|
|
28
31
|
pii:
|
|
29
32
|
# Only local rules are used in this file; `include` is intentionally absent.
|
|
@@ -42,6 +45,7 @@ servers:
|
|
|
42
45
|
# mysql and mariadb both use mysql+pymysql URLs. Select the engine matching the server.
|
|
43
46
|
engine: mysql
|
|
44
47
|
access_level: all_pii_safe
|
|
48
|
+
# Verified TLS for MySQL/MariaDB: the URL must set ssl_ca (or ssl_capath).
|
|
45
49
|
connection_url: "${SHOP_MYSQL_URL}"
|
|
46
50
|
pii_key_env: SHOP_PII_KEY
|
|
47
51
|
pii:
|
|
@@ -38,6 +38,9 @@ pii_rules:
|
|
|
38
38
|
schema: dbo # Optional for SQL Server; omit it to match every schema.
|
|
39
39
|
table: "Users[0-9]?"
|
|
40
40
|
columns: [Email, FirstName, LastName]
|
|
41
|
+
# Optional token domain (alias character set). Tokens of one domain are accepted only on
|
|
42
|
+
# columns of that domain; without it the domain is the server alias.
|
|
43
|
+
domain: users_identity
|
|
41
44
|
|
|
42
45
|
servers:
|
|
43
46
|
legacy-prod:
|
|
@@ -65,6 +68,21 @@ servers:
|
|
|
65
68
|
table: Cards
|
|
66
69
|
columns: [HolderName]
|
|
67
70
|
|
|
71
|
+
peds-deny-by-default:
|
|
72
|
+
engine: sqlserver
|
|
73
|
+
access_level: all_pii_safe
|
|
74
|
+
connection_url: "${PEDS_SQL_URL}"
|
|
75
|
+
pii_key_env: PEDS_PII_KEY
|
|
76
|
+
pii:
|
|
77
|
+
# `deny-by-default` protects every column that exposed_columns does not list.
|
|
78
|
+
mode: deny-by-default
|
|
79
|
+
exposed_columns: # `database` is optional here and defaults to "*".
|
|
80
|
+
- table: Visits
|
|
81
|
+
columns: [VisitId, DepartmentCode, VisitYear]
|
|
82
|
+
deny: # Unreachable even as a token; columns: ["*"] denies a whole table.
|
|
83
|
+
- table: "*"
|
|
84
|
+
columns: [Notes, Anamnesis, Attachment]
|
|
85
|
+
|
|
68
86
|
reporting-metadata:
|
|
69
87
|
engine: sqlserver
|
|
70
88
|
access_level: metadata
|
|
@@ -10,6 +10,7 @@ from pathlib import Path
|
|
|
10
10
|
from sql_safe_mcp.config import load_config
|
|
11
11
|
from sql_safe_mcp.errors import DomainError
|
|
12
12
|
from sql_safe_mcp.mcp_server import create_server
|
|
13
|
+
from sql_safe_mcp.pii_audit import collect_catalog, verify_pii_rules
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
def _positive_int(value: str) -> int:
|
|
@@ -41,11 +42,24 @@ def _parser() -> argparse.ArgumentParser:
|
|
|
41
42
|
metavar="N",
|
|
42
43
|
help="Print N base64-encoded 32-byte PII keys (default: 1) and exit.",
|
|
43
44
|
)
|
|
45
|
+
actions.add_argument(
|
|
46
|
+
"--verify-pii-rules",
|
|
47
|
+
action="store_true",
|
|
48
|
+
help="Connect to each all_pii_safe alias and report PII rules that match nothing.",
|
|
49
|
+
)
|
|
50
|
+
parser.add_argument(
|
|
51
|
+
"--strict",
|
|
52
|
+
action="store_true",
|
|
53
|
+
help="With --verify-pii-rules, exit 2 when any rule matches nothing.",
|
|
54
|
+
)
|
|
44
55
|
return parser
|
|
45
56
|
|
|
46
57
|
|
|
47
58
|
def main() -> None:
|
|
48
|
-
|
|
59
|
+
parser = _parser()
|
|
60
|
+
args = parser.parse_args()
|
|
61
|
+
if args.strict and not args.verify_pii_rules:
|
|
62
|
+
parser.error("--strict requires --verify-pii-rules")
|
|
49
63
|
if args.gen_pii_key is not None:
|
|
50
64
|
for _ in range(args.gen_pii_key):
|
|
51
65
|
print(base64.b64encode(secrets.token_bytes(32)).decode("ascii"))
|
|
@@ -58,6 +72,12 @@ def main() -> None:
|
|
|
58
72
|
if args.check_config:
|
|
59
73
|
print(f"Configuration valid: {len(config.servers)} server alias(es).")
|
|
60
74
|
return
|
|
75
|
+
if args.verify_pii_rules:
|
|
76
|
+
report = verify_pii_rules(config, collect_catalog)
|
|
77
|
+
print("\n".join(report.lines), file=sys.stderr)
|
|
78
|
+
if report.errors or (args.strict and report.unmatched_rules):
|
|
79
|
+
raise SystemExit(2)
|
|
80
|
+
return
|
|
61
81
|
create_server(config).run("stdio")
|
|
62
82
|
|
|
63
83
|
|