mcpg 0.8.2__tar.gz → 0.8.3__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.
- mcpg-0.8.3/.oss-scanner/README.md +43 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/CHANGELOG.md +64 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/PKG-INFO +19 -11
- {mcpg-0.8.2 → mcpg-0.8.3}/README.md +16 -8
- {mcpg-0.8.2 → mcpg-0.8.3}/packaging/mcpb/pyproject.toml +2 -2
- {mcpg-0.8.2 → mcpg-0.8.3}/pyproject.toml +5 -3
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/__init__.py +1 -1
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/about.py +32 -1
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/config.py +27 -1
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/diesel.py +6 -1
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/drizzle.py +6 -1
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/ecto.py +6 -1
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/ent.py +6 -1
- mcpg-0.8.3/src/mcpg/guc.py +658 -0
- mcpg-0.8.3/src/mcpg/guc_tools.py +174 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/jooq.py +6 -1
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/prisma.py +6 -1
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/sql/allowlist.py +31 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/sqlalchemy_export.py +6 -1
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/sqlc.py +6 -1
- mcpg-0.8.3/src/mcpg/timescaledb.py +648 -0
- mcpg-0.8.3/src/mcpg/timescaledb_admin.py +707 -0
- mcpg-0.8.3/src/mcpg/timescaledb_tools.py +532 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/tools.py +65 -2
- mcpg-0.8.2/src/mcpg/timescaledb.py +0 -280
- {mcpg-0.8.2 → mcpg-0.8.3}/.gitignore +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/LICENSE +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/NOTICE +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/SECURITY.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/benchmarks/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/benchmarks/results/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/scratch/pg_turboquant/.github/workflows/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/scratch/pg_turboquant/LICENSE +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/scratch/pg_turboquant/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/scratch/pg_turboquant/benchmarks/rag/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/scratch/pg_turboquant/docs/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/scratch/pg_turboquant/pyproject.toml +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/scratch/pg_turboquant/scripts/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/scratch/pg_turboquant/sql/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/scratch/pg_turboquant/src/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/scratch/pg_turboquant/t/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/scratch/pg_turboquant/test/expected/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/scratch/pg_turboquant/test/sql/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/scratch/pg_turboquant/tests/unit/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/scratch/pg_turboquant/third_party/README.md +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/__main__.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/advisors.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/aio.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/analytical.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/audit.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/audit_integrity.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/audit_nl2sql.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/audit_trail.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/autovacuum.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/cache.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/composite.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/config_advisor.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/context.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/cron.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/cursors.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/cypher.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/data_movement.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/database.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/ddl_dryrun.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/demo.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/diagrams.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/dynamic_session_intent.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/errors.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/extensions.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/graph.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/graph_diagram.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/graph_mgmt.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/graph_projection.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/headline_curator.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/health.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/http_runtime.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/identifiers.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/indexing.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/introspection.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/io_stats.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/listen.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/liveops.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/locks.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/logical_replication.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/maintenance.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/middleware/rate_limit.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/migration_history.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/migration_ingestion.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/migrations.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/multidb.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/naming.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/nl2sql.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/obs_logging.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/observability.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/oidc.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/otel_tracing.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/partman.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/pg19_ddl.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/pg19_partitions.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/pg19_runtime.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/pg19_skip_scan.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/pg19_stats.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/pg_prewarm.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/pg_search.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/pgq.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/pitr.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/policy.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/prompts.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/py.typed +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/query.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/rag_efficiency.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/rag_telemetry.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/redis_fdw.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/repack.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/replicas.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/resources.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/rls.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/schema_diff.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/schema_docs.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/secrets.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/server.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/session_advisor.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/session_intent.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/shell.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/sql/__init__.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/sql/driver.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/sql/safety.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/tenancy.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/test_data.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/test_row_factory.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/textsearch.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/tool_introspection.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/turboquant.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/vector_ops.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/vector_tuner_advanced.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/vector_tuning.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/wait_for_lsn.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/wal_archive.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/walinspect.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/warehousepg.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/workload.py +0 -0
- {mcpg-0.8.2 → mcpg-0.8.3}/src/mcpg/write.py +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# OSS Scanner enrollment
|
|
2
|
+
|
|
3
|
+
Artifacts for enrolling MCPg in [Anthropic's OSS
|
|
4
|
+
Scanner](https://github.com/anthropics/oss-scanner), a service that builds a
|
|
5
|
+
project in an isolated, no-network VM and runs a Claude-powered security scan,
|
|
6
|
+
emailing findings (with reproduction steps and proposed patches) privately to
|
|
7
|
+
the `primary_contact`.
|
|
8
|
+
|
|
9
|
+
Files here:
|
|
10
|
+
|
|
11
|
+
- **`Dockerfile`** — the build image the scanner uses. MCPg is pure Python, so
|
|
12
|
+
it just installs the full source + dependency environment (runtime + dev,
|
|
13
|
+
for the adversarial test suites) at build time; the checkout lands at `/src`
|
|
14
|
+
per the scanner contract.
|
|
15
|
+
- **`threat_model.md`** — steers the scan at MCPg's real surface: the SQL-safety
|
|
16
|
+
allowlist, access-mode / tenancy gates, OIDC auth, and the shell tools, with
|
|
17
|
+
app-security severity tiers.
|
|
18
|
+
- **`project.yaml`** — the enrollment manifest (reference copy; see below).
|
|
19
|
+
|
|
20
|
+
## How to enroll (maintainer, one-time)
|
|
21
|
+
|
|
22
|
+
The scanner is enrolled by a pull request **to the `anthropics/oss-scanner`
|
|
23
|
+
repo** — which is separate from this one, so it must be opened by a maintainer
|
|
24
|
+
(fork + PR):
|
|
25
|
+
|
|
26
|
+
1. Fork `anthropics/oss-scanner`.
|
|
27
|
+
2. Add `projects/mcpg/project.yaml` with the contents of
|
|
28
|
+
[`project.yaml`](project.yaml) in this directory (it already points
|
|
29
|
+
`dockerfile` / `threat_model` at the paths here in `devopam/MCPg`, so the
|
|
30
|
+
scanner pulls them from this repo — nothing else to copy).
|
|
31
|
+
3. Optionally run their local checks first: `tools/validate.py` then
|
|
32
|
+
`tools/check mcpg` (needs Docker + Python + PyYAML).
|
|
33
|
+
4. Open the PR. After Anthropic merges it, scans run and findings are emailed
|
|
34
|
+
to `primary_contact`.
|
|
35
|
+
|
|
36
|
+
## Notes
|
|
37
|
+
|
|
38
|
+
- Enrollment is reviewed/merged by Anthropic and targets "critical" OSS —
|
|
39
|
+
acceptance is their call.
|
|
40
|
+
- Reports are model-generated and not human-reviewed (no public disclosure);
|
|
41
|
+
treat findings as leads to verify, per the project's adversarial-test
|
|
42
|
+
discipline.
|
|
43
|
+
- To pin the scanned revision, add `#<tag>` to `repo` in `project.yaml`.
|
|
@@ -6,6 +6,70 @@ adheres to [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.8.3] - 2026-10-14
|
|
10
|
+
|
|
11
|
+
A feature release by content (new tools and opt-in flags, nothing removed or renamed), shipped as a patch per the maintainer's call: the default tool surface only gains five read-only tools, and every new write or admin tool needs an explicit `MCPG_ALLOW_*` flag. See [release notes](docs/release-notes-0.8.3.md).
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`ALTER SYSTEM` GUC tools.** `inspect_guc` (read), plus `alter_system`, `alter_system_reset_all` and
|
|
16
|
+
`reload_config` behind unrestricted mode + `MCPG_ALLOW_ALTER_SYSTEM`. Runs on an autocommit connection,
|
|
17
|
+
requires `confirm=true` plus a per-statement `confirmation_token`, and blocks connectivity/preload GUCs and
|
|
18
|
+
settings that run OS commands or hold credentials (`archive_command`, `restore_command`, `primary_conninfo`, …) by
|
|
19
|
+
default (`MCPG_ALTER_SYSTEM_ALLOWLIST` / `MCPG_ALTER_SYSTEM_DENYLIST`). `RESET ALL` enforces that policy on every
|
|
20
|
+
current override, `inspect_guc` redacts secret-bearing values, and the write tools refuse to run under
|
|
21
|
+
`MCPG_DEFAULT_ROLE` / `MCPG_ALLOWED_ROLES`. See `docs/alter-system.md`. (PR #352)
|
|
22
|
+
- **TimescaleDB read-only functions are now allowed in the SQL-safety kernel** (#353): `time_bucket`, `time_bucket_gapfill`,
|
|
23
|
+
`first`/`last`, `locf`, `interpolate`, `histogram`, the `hypertable_*_size` / `*_compression_stats` / `*_columnstore_stats`
|
|
24
|
+
family, `show_chunks`, `by_range`/`by_hash`, the uuidv7 helpers and `timescaledb_experimental.show_policies`. Mutating
|
|
25
|
+
functions, procedures, `timescaledb_pre/post_restore` and `get_telemetry_report` stay blocked.
|
|
26
|
+
- **TimescaleDB tool family** (design: `docs/plans/timescaledb-tools.md`, reference: `docs/timescaledb.md`): reads
|
|
27
|
+
`get_hypertable_stats`, `list_timescale_jobs`, `list_continuous_aggregates`, `get_timescaledb_telemetry_report`;
|
|
28
|
+
additive DDL `add_dimension`, `set_chunk_time_interval`, `add_continuous_aggregate_policy`, `add_reorder_policy` and four
|
|
29
|
+
`remove_*_policy` tools; and, behind the new `MCPG_ALLOW_TIMESCALEDB_ADMIN` flag with a `dry_run` / `confirm` +
|
|
30
|
+
`confirmation_token` flow, `drop_chunks`, `compress_chunk`, `decompress_chunk`, `reorder_chunk`, `merge_chunks`,
|
|
31
|
+
`refresh_continuous_aggregate`, `run_job`, `alter_job`, `delete_job`. Behaviour was verified on TimescaleDB 2.30.2, and a
|
|
32
|
+
new experimental `TimescaleDB` CI job runs the integration tests.
|
|
33
|
+
|
|
34
|
+
### Security
|
|
35
|
+
|
|
36
|
+
- **Bumped `pyjwt` to ≥ 2.15.0 (2.15.1 resolved)** to clear the October 2026
|
|
37
|
+
advisory cascade against 2.13.0 — thirteen `PYSEC-2026-414x` findings plus
|
|
38
|
+
`CVE-2026-102275`, all flagged by `pip-audit --strict` and fixed in
|
|
39
|
+
2.14.0 / 2.15.0. 2.15's `PyJWKClient` hardened its JWKS fetch against SSRF
|
|
40
|
+
(own `build_opener`/no-redirect handler instead of the module-level
|
|
41
|
+
`urllib.request.urlopen`); the OIDC verifier uses the stable public API so
|
|
42
|
+
no source change was needed, but the `test_oidc.py` JWKS mock now patches
|
|
43
|
+
pyjwt's `PyJWKClient.fetch_data` boundary rather than urllib internals.
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- **`pglast` 8.4 → 8.5** (PR #350; `uv.lock` updated). The SQL-safety kernel's adversarial and fuzz suites pass on 8.5.
|
|
48
|
+
- **The contract fixtures now enable `MCPG_ALLOW_ALTER_SYSTEM` and `MCPG_ALLOW_TIMESCALEDB_ADMIN`**, so the tool-surface
|
|
49
|
+
snapshot (now 281 tools), annotations and return-shape contracts cover the ALTER SYSTEM and TimescaleDB admin tools.
|
|
50
|
+
- **ORM exporters explain why they reject delimited names.** `generate_prisma_schema` and the Drizzle,
|
|
51
|
+
SQLAlchemy, sqlc, Diesel, jOOQ, Ent and Ecto exporters still accept only plain `[A-Za-z_][A-Za-z0-9_]*`
|
|
52
|
+
names (the name becomes an identifier in generated source), but their errors and tool descriptions now
|
|
53
|
+
say so and point at the SQL tools that accept delimited names.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- `docs/tools.md` tool-index heading and the hand-written tool counts (README, tour, user guide) were stale; regenerated.
|
|
58
|
+
- **SQL-safety fuzz harness now actually explores the validator.** `sql_safety_fuzzer` decoded its input
|
|
59
|
+
with `ConsumeUnicodeNoSurrogates`, which turns ASCII SQL into garbage code points, so `pglast` rejected
|
|
60
|
+
nearly every input at the first token and coverage never grew. It now decodes bytes directly and ships a
|
|
61
|
+
seed corpus and SQL dictionary (`.clusterfuzzlite/`); a 60 s run goes from `cov: 4` to `cov: 277`. Roadmap 23.1.
|
|
62
|
+
|
|
63
|
+
### Documentation
|
|
64
|
+
|
|
65
|
+
- New [`docs/identifier-policy.md`](docs/identifier-policy.md): which names SQL tools accept
|
|
66
|
+
(delimited identifiers via `quote_identifier`) versus the plain-identifier-only sinks and why.
|
|
67
|
+
- README "Safe by default" no longer claims identifiers go through a strict regex; `adding-tools.md`
|
|
68
|
+
now recommends `quote_identifier`; the `subscribe_channel` description and a `config.py` comment no
|
|
69
|
+
longer claim plain-identifier-only names.
|
|
70
|
+
- `CODE_OF_CONDUCT.md` (Contributor Covenant 2.1) is now linked from the README, `CONTRIBUTING.md` and
|
|
71
|
+
the docs index.
|
|
72
|
+
|
|
9
73
|
## [0.8.2] - 2026-09-04
|
|
10
74
|
|
|
11
75
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: mcpg
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.3
|
|
4
4
|
Summary: A production-grade PostgreSQL Model Context Protocol (MCP) server.
|
|
5
5
|
Project-URL: Homepage, https://github.com/devopam/MCPg
|
|
6
6
|
Project-URL: Documentation, https://github.com/devopam/MCPg#documentation
|
|
@@ -35,10 +35,10 @@ Requires-Dist: circuitbreaker>=2.1.3
|
|
|
35
35
|
Requires-Dist: httpx>=0.27
|
|
36
36
|
Requires-Dist: mcp-types>=2.0.0
|
|
37
37
|
Requires-Dist: mcp[cli]>=2.0.0
|
|
38
|
-
Requires-Dist: pglast==8.
|
|
38
|
+
Requires-Dist: pglast==8.5
|
|
39
39
|
Requires-Dist: psycopg-pool>=3.3.0
|
|
40
40
|
Requires-Dist: psycopg[binary]>=3.3.2
|
|
41
|
-
Requires-Dist: pyjwt[crypto]>=2.
|
|
41
|
+
Requires-Dist: pyjwt[crypto]>=2.15.0
|
|
42
42
|
Requires-Dist: tenacity>=9.1.4
|
|
43
43
|
Requires-Dist: typing-extensions>=4.12
|
|
44
44
|
Provides-Extra: aws
|
|
@@ -61,7 +61,7 @@ Description-Content-Type: text/markdown
|
|
|
61
61
|
|
|
62
62
|
**A production-grade [Model Context Protocol](https://modelcontextprotocol.io)
|
|
63
63
|
server for PostgreSQL.** It lets AI agents safely inspect, query, operate, and
|
|
64
|
-
tune a Postgres database —
|
|
64
|
+
tune a Postgres database — 279 tools spanning catalog introspection,
|
|
65
65
|
query intelligence, natural-language SQL, structural diffs, hybrid search,
|
|
66
66
|
graph queries, data movement, live ops, and more.
|
|
67
67
|
|
|
@@ -77,6 +77,7 @@ graph queries, data movement, live ops, and more.
|
|
|
77
77
|
[](https://glama.ai/mcp/servers/devopam/MCPg)
|
|
78
78
|
[](https://allmcps.com/mcp/devopam-mcpg?verify=63d9d537-be6b-4e07-a720-77dd0c41411b)
|
|
79
79
|
[](https://mcpvault.io/servers/mcpg/health?utm_source=external_badge&utm_medium=referral&utm_campaign=mcp_health_report)
|
|
80
|
+
[](https://mcp-serverlist.com/mcp/mcpg)
|
|
80
81
|
|
|
81
82
|
> **Try it live:** point an MCP client — or the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) — at the hosted, read-only demo endpoint `https://devopam-mcpg-demo.hf.space/mcp`. It serves read tools against throwaway demo data; for real use, run MCPg next to your own database (see [Quick start](#quick-start)).
|
|
82
83
|
|
|
@@ -87,6 +88,7 @@ graph queries, data movement, live ops, and more.
|
|
|
87
88
|
- **[mcpservers.org](https://mcpservers.org/servers/devopam/mcpg)**
|
|
88
89
|
- **[Smithery](https://smithery.ai/servers/devopam/mcpg)**
|
|
89
90
|
- **[Glama](https://glama.ai/mcp/servers/devopam/MCPg)**
|
|
91
|
+
- **[MCP ServerList](https://mcp-serverlist.com/mcp/mcpg)**
|
|
90
92
|
|
|
91
93
|
---
|
|
92
94
|
|
|
@@ -102,9 +104,9 @@ graph queries, data movement, live ops, and more.
|
|
|
102
104
|
|
|
103
105
|
- **Safe by default.** Read-only access mode. Every user-supplied SQL
|
|
104
106
|
statement parses through a validated AST allowlist before execution.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
107
|
+
Names that reach PostgreSQL as SQL identifiers are encoded with
|
|
108
|
+
delimited-identifier quoting (see [Identifier policy](docs/identifier-policy.md)),
|
|
109
|
+
not rejected merely for containing hyphens or other legal characters.
|
|
108
110
|
Capabilities like DDL, shell, and `LISTEN/NOTIFY` are off until you
|
|
109
111
|
opt in. Every tool publishes MCP `ToolAnnotations` (`readOnlyHint`,
|
|
110
112
|
`openWorldHint`) derived from those same gates, so clients can
|
|
@@ -313,6 +315,8 @@ are one-shot commands, not configuration). The only required one is
|
|
|
313
315
|
|---|---|---|
|
|
314
316
|
| `MCPG_ALLOW_DDL` | `false` | Expose DDL tools (`run_ddl`, `create_graph`, `drop_graph`, hypertable tools, migration tools). Requires `MCPG_ACCESS_MODE=unrestricted`. |
|
|
315
317
|
| `MCPG_ALLOW_SHELL` | `false` | Expose subprocess-backed tools (`dump_database`, `restore_database`, `run_pg_binary`). Required PG client binaries must be on `PATH`. |
|
|
318
|
+
| `MCPG_ALLOW_TIMESCALEDB_ADMIN` | `false` | With unrestricted mode + `MCPG_ALLOW_DDL`, expose the destructive / heavy TimescaleDB tools (`drop_chunks`, `compress_chunk`, `decompress_chunk`, `reorder_chunk`, `merge_chunks`, `refresh_continuous_aggregate`, `run_job`, `alter_job`, `delete_job`); each needs `dry_run` then `confirm=true` + `confirmation_token`. See [docs/timescaledb.md](docs/timescaledb.md). |
|
|
319
|
+
| `MCPG_ALLOW_ALTER_SYSTEM` | `false` | Expose `alter_system`, `alter_system_reset_all`, `reload_config` (unrestricted mode only; two-step `confirm=true` flow — see [docs/alter-system.md](docs/alter-system.md)). `MCPG_ALTER_SYSTEM_ALLOWLIST` / `MCPG_ALTER_SYSTEM_DENYLIST` (comma-separated GUC names) narrow or extend the built-in denylist. |
|
|
316
320
|
| `MCPG_ALLOW_LISTEN` | `false` | Expose `LISTEN/NOTIFY` tools (`subscribe_channel`, `poll_notifications`, `unsubscribe_channel`, `list_notification_subscriptions`). |
|
|
317
321
|
|
|
318
322
|
#### Authentication (HTTP transports only)
|
|
@@ -597,9 +601,11 @@ Compact category list. For the full, current tool reference see
|
|
|
597
601
|
- **Server-side cursors** — `open_cursor`, `fetch_cursor`,
|
|
598
602
|
`close_cursor`, `list_cursors` for pageable reads over millions
|
|
599
603
|
of rows.
|
|
600
|
-
- **TimescaleDB** —
|
|
601
|
-
|
|
602
|
-
`
|
|
604
|
+
- **TimescaleDB** — hypertable / chunk / job / continuous-aggregate
|
|
605
|
+
introspection and stats, policy and dimension management, and gated
|
|
606
|
+
chunk / job administration (`drop_chunks`, `compress_chunk`,
|
|
607
|
+
`refresh_continuous_aggregate`, `run_job`, …). See
|
|
608
|
+
[docs/timescaledb.md](docs/timescaledb.md).
|
|
603
609
|
- **ORM schema exporters** — Prisma, Drizzle, SQLAlchemy, sqlc,
|
|
604
610
|
Diesel, jOOQ, Ent, Ecto.
|
|
605
611
|
- **Event streams** — `subscribe_channel`, `poll_notifications`,
|
|
@@ -661,7 +667,9 @@ page for downloadable artifacts.
|
|
|
661
667
|
|
|
662
668
|
Pull requests welcome — see [`CONTRIBUTING.md`](https://github.com/devopam/MCPg/blob/main/CONTRIBUTING.md) for
|
|
663
669
|
the dev-loop setup, test conventions, and the per-PR review
|
|
664
|
-
checklist.
|
|
670
|
+
checklist. Participation is governed by the
|
|
671
|
+
[Code of Conduct](https://github.com/devopam/MCPg/blob/main/CODE_OF_CONDUCT.md)
|
|
672
|
+
(Contributor Covenant 2.1).
|
|
665
673
|
|
|
666
674
|
---
|
|
667
675
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
**A production-grade [Model Context Protocol](https://modelcontextprotocol.io)
|
|
8
8
|
server for PostgreSQL.** It lets AI agents safely inspect, query, operate, and
|
|
9
|
-
tune a Postgres database —
|
|
9
|
+
tune a Postgres database — 279 tools spanning catalog introspection,
|
|
10
10
|
query intelligence, natural-language SQL, structural diffs, hybrid search,
|
|
11
11
|
graph queries, data movement, live ops, and more.
|
|
12
12
|
|
|
@@ -22,6 +22,7 @@ graph queries, data movement, live ops, and more.
|
|
|
22
22
|
[](https://glama.ai/mcp/servers/devopam/MCPg)
|
|
23
23
|
[](https://allmcps.com/mcp/devopam-mcpg?verify=63d9d537-be6b-4e07-a720-77dd0c41411b)
|
|
24
24
|
[](https://mcpvault.io/servers/mcpg/health?utm_source=external_badge&utm_medium=referral&utm_campaign=mcp_health_report)
|
|
25
|
+
[](https://mcp-serverlist.com/mcp/mcpg)
|
|
25
26
|
|
|
26
27
|
> **Try it live:** point an MCP client — or the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) — at the hosted, read-only demo endpoint `https://devopam-mcpg-demo.hf.space/mcp`. It serves read tools against throwaway demo data; for real use, run MCPg next to your own database (see [Quick start](#quick-start)).
|
|
27
28
|
|
|
@@ -32,6 +33,7 @@ graph queries, data movement, live ops, and more.
|
|
|
32
33
|
- **[mcpservers.org](https://mcpservers.org/servers/devopam/mcpg)**
|
|
33
34
|
- **[Smithery](https://smithery.ai/servers/devopam/mcpg)**
|
|
34
35
|
- **[Glama](https://glama.ai/mcp/servers/devopam/MCPg)**
|
|
36
|
+
- **[MCP ServerList](https://mcp-serverlist.com/mcp/mcpg)**
|
|
35
37
|
|
|
36
38
|
---
|
|
37
39
|
|
|
@@ -47,9 +49,9 @@ graph queries, data movement, live ops, and more.
|
|
|
47
49
|
|
|
48
50
|
- **Safe by default.** Read-only access mode. Every user-supplied SQL
|
|
49
51
|
statement parses through a validated AST allowlist before execution.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
Names that reach PostgreSQL as SQL identifiers are encoded with
|
|
53
|
+
delimited-identifier quoting (see [Identifier policy](docs/identifier-policy.md)),
|
|
54
|
+
not rejected merely for containing hyphens or other legal characters.
|
|
53
55
|
Capabilities like DDL, shell, and `LISTEN/NOTIFY` are off until you
|
|
54
56
|
opt in. Every tool publishes MCP `ToolAnnotations` (`readOnlyHint`,
|
|
55
57
|
`openWorldHint`) derived from those same gates, so clients can
|
|
@@ -258,6 +260,8 @@ are one-shot commands, not configuration). The only required one is
|
|
|
258
260
|
|---|---|---|
|
|
259
261
|
| `MCPG_ALLOW_DDL` | `false` | Expose DDL tools (`run_ddl`, `create_graph`, `drop_graph`, hypertable tools, migration tools). Requires `MCPG_ACCESS_MODE=unrestricted`. |
|
|
260
262
|
| `MCPG_ALLOW_SHELL` | `false` | Expose subprocess-backed tools (`dump_database`, `restore_database`, `run_pg_binary`). Required PG client binaries must be on `PATH`. |
|
|
263
|
+
| `MCPG_ALLOW_TIMESCALEDB_ADMIN` | `false` | With unrestricted mode + `MCPG_ALLOW_DDL`, expose the destructive / heavy TimescaleDB tools (`drop_chunks`, `compress_chunk`, `decompress_chunk`, `reorder_chunk`, `merge_chunks`, `refresh_continuous_aggregate`, `run_job`, `alter_job`, `delete_job`); each needs `dry_run` then `confirm=true` + `confirmation_token`. See [docs/timescaledb.md](docs/timescaledb.md). |
|
|
264
|
+
| `MCPG_ALLOW_ALTER_SYSTEM` | `false` | Expose `alter_system`, `alter_system_reset_all`, `reload_config` (unrestricted mode only; two-step `confirm=true` flow — see [docs/alter-system.md](docs/alter-system.md)). `MCPG_ALTER_SYSTEM_ALLOWLIST` / `MCPG_ALTER_SYSTEM_DENYLIST` (comma-separated GUC names) narrow or extend the built-in denylist. |
|
|
261
265
|
| `MCPG_ALLOW_LISTEN` | `false` | Expose `LISTEN/NOTIFY` tools (`subscribe_channel`, `poll_notifications`, `unsubscribe_channel`, `list_notification_subscriptions`). |
|
|
262
266
|
|
|
263
267
|
#### Authentication (HTTP transports only)
|
|
@@ -542,9 +546,11 @@ Compact category list. For the full, current tool reference see
|
|
|
542
546
|
- **Server-side cursors** — `open_cursor`, `fetch_cursor`,
|
|
543
547
|
`close_cursor`, `list_cursors` for pageable reads over millions
|
|
544
548
|
of rows.
|
|
545
|
-
- **TimescaleDB** —
|
|
546
|
-
|
|
547
|
-
`
|
|
549
|
+
- **TimescaleDB** — hypertable / chunk / job / continuous-aggregate
|
|
550
|
+
introspection and stats, policy and dimension management, and gated
|
|
551
|
+
chunk / job administration (`drop_chunks`, `compress_chunk`,
|
|
552
|
+
`refresh_continuous_aggregate`, `run_job`, …). See
|
|
553
|
+
[docs/timescaledb.md](docs/timescaledb.md).
|
|
548
554
|
- **ORM schema exporters** — Prisma, Drizzle, SQLAlchemy, sqlc,
|
|
549
555
|
Diesel, jOOQ, Ent, Ecto.
|
|
550
556
|
- **Event streams** — `subscribe_channel`, `poll_notifications`,
|
|
@@ -606,7 +612,9 @@ page for downloadable artifacts.
|
|
|
606
612
|
|
|
607
613
|
Pull requests welcome — see [`CONTRIBUTING.md`](https://github.com/devopam/MCPg/blob/main/CONTRIBUTING.md) for
|
|
608
614
|
the dev-loop setup, test conventions, and the per-PR review
|
|
609
|
-
checklist.
|
|
615
|
+
checklist. Participation is governed by the
|
|
616
|
+
[Code of Conduct](https://github.com/devopam/MCPg/blob/main/CODE_OF_CONDUCT.md)
|
|
617
|
+
(Contributor Covenant 2.1).
|
|
610
618
|
|
|
611
619
|
---
|
|
612
620
|
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
# to the release tag by the publish workflow, exactly like server.json.
|
|
6
6
|
[project]
|
|
7
7
|
name = "mcpg-desktop-extension"
|
|
8
|
-
version = "0.8.
|
|
8
|
+
version = "0.8.3"
|
|
9
9
|
description = "MCPB launcher shim for the MCPg PostgreSQL MCP server."
|
|
10
10
|
requires-python = ">=3.12"
|
|
11
11
|
dependencies = [
|
|
12
|
-
"mcpg==0.8.
|
|
12
|
+
"mcpg==0.8.3",
|
|
13
13
|
]
|
|
@@ -53,7 +53,7 @@ dependencies = [
|
|
|
53
53
|
"mcp[cli]>=2.0.0",
|
|
54
54
|
"psycopg[binary]>=3.3.2",
|
|
55
55
|
"psycopg-pool>=3.3.0",
|
|
56
|
-
"pglast==8.
|
|
56
|
+
"pglast==8.5",
|
|
57
57
|
"typing-extensions>=4.12",
|
|
58
58
|
# httpx ships transitively via mcp; declare it explicitly so the
|
|
59
59
|
# NL→SQL providers in mcpg.nl2sql have a guaranteed surface.
|
|
@@ -62,8 +62,10 @@ dependencies = [
|
|
|
62
62
|
# mcpg.dynamic_session_intent has a guaranteed surface.
|
|
63
63
|
"mcp-types>=2.0.0",
|
|
64
64
|
# JWT validation for the OIDC auth path. ``[crypto]`` pulls in
|
|
65
|
-
# ``cryptography`` so RS256 / ES256 signature checks work.
|
|
66
|
-
|
|
65
|
+
# ``cryptography`` so RS256 / ES256 signature checks work. Floor raised
|
|
66
|
+
# to 2.15.0 to clear the 2026 pyjwt advisories (PYSEC-2026-414x +
|
|
67
|
+
# CVE-2026-102275), all fixed in 2.14.0 / 2.15.0.
|
|
68
|
+
"pyjwt[crypto]>=2.15.0",
|
|
67
69
|
"circuitbreaker>=2.1.3",
|
|
68
70
|
"tenacity>=9.1.4",
|
|
69
71
|
]
|
|
@@ -253,7 +253,11 @@ CAPABILITIES: tuple[Capability, ...] = (
|
|
|
253
253
|
detail=(
|
|
254
254
|
"If TimescaleDB is installed: `create_hypertable`, "
|
|
255
255
|
"`add_compression_policy`, `add_retention_policy`, `list_hypertables`, "
|
|
256
|
-
"`list_chunks
|
|
256
|
+
"`list_chunks`, `get_hypertable_stats`, `list_timescale_jobs`, "
|
|
257
|
+
"`list_continuous_aggregates`, dimension / policy management, and "
|
|
258
|
+
"(with `MCPG_ALLOW_TIMESCALEDB_ADMIN`) `drop_chunks`, chunk compression / "
|
|
259
|
+
"merge / reorder, continuous-aggregate refresh and job control. "
|
|
260
|
+
"For PostgreSQL native partitioning managed by "
|
|
257
261
|
"pg_partman: `partman_create_parent`, `partman_run_maintenance`, "
|
|
258
262
|
"`partman_drop_partition`, `list_partitions`. Both backends are "
|
|
259
263
|
"first-class for the audit / RAG telemetry tables (see PR-4 / PR-5 "
|
|
@@ -540,6 +544,28 @@ _TOOL_TO_BUCKET_OVERRIDES: dict[str, str] = {
|
|
|
540
544
|
# list_hypertables / list_chunks / list_partitions are time-series.
|
|
541
545
|
"list_hypertables": "timeseries_partitioning",
|
|
542
546
|
"list_chunks": "timeseries_partitioning",
|
|
547
|
+
# TimescaleDB stats / jobs / policies / chunk + job admin (docs/plans/timescaledb-tools.md).
|
|
548
|
+
"get_hypertable_stats": "timeseries_partitioning",
|
|
549
|
+
"list_timescale_jobs": "timeseries_partitioning",
|
|
550
|
+
"list_continuous_aggregates": "timeseries_partitioning",
|
|
551
|
+
"get_timescaledb_telemetry_report": "timeseries_partitioning",
|
|
552
|
+
"add_dimension": "timeseries_partitioning",
|
|
553
|
+
"set_chunk_time_interval": "timeseries_partitioning",
|
|
554
|
+
"add_continuous_aggregate_policy": "timeseries_partitioning",
|
|
555
|
+
"add_reorder_policy": "timeseries_partitioning",
|
|
556
|
+
"remove_retention_policy": "timeseries_partitioning",
|
|
557
|
+
"remove_compression_policy": "timeseries_partitioning",
|
|
558
|
+
"remove_continuous_aggregate_policy": "timeseries_partitioning",
|
|
559
|
+
"remove_reorder_policy": "timeseries_partitioning",
|
|
560
|
+
"drop_chunks": "timeseries_partitioning",
|
|
561
|
+
"compress_chunk": "timeseries_partitioning",
|
|
562
|
+
"decompress_chunk": "timeseries_partitioning",
|
|
563
|
+
"reorder_chunk": "timeseries_partitioning",
|
|
564
|
+
"merge_chunks": "timeseries_partitioning",
|
|
565
|
+
"refresh_continuous_aggregate": "timeseries_partitioning",
|
|
566
|
+
"run_job": "timeseries_partitioning",
|
|
567
|
+
"alter_job": "timeseries_partitioning",
|
|
568
|
+
"delete_job": "timeseries_partitioning",
|
|
543
569
|
"list_partitions": "timeseries_partitioning",
|
|
544
570
|
# list_turboquant_indexes / list_pg_search_indexes are search-bucket.
|
|
545
571
|
"list_turboquant_indexes": "vector_search",
|
|
@@ -711,6 +737,11 @@ _TOOL_TO_BUCKET_OVERRIDES: dict[str, str] = {
|
|
|
711
737
|
"drop_property_graph": "property_graph_queries",
|
|
712
738
|
# PG 19 in-server REPACK — operational maintenance, sits next to
|
|
713
739
|
# run_maintenance / check_database_health.
|
|
740
|
+
# inspect_guc / alter_system family (ALTER SYSTEM tools, docs/alter-system.md).
|
|
741
|
+
"inspect_guc": "operations_and_health",
|
|
742
|
+
"alter_system": "operations_and_health",
|
|
743
|
+
"alter_system_reset_all": "operations_and_health",
|
|
744
|
+
"reload_config": "operations_and_health",
|
|
714
745
|
"get_repack_status": "operations_and_health",
|
|
715
746
|
"repack_table": "operations_and_health",
|
|
716
747
|
# PG 19 async-I/O subsystem — observability + advisor; sits in the
|
|
@@ -66,6 +66,10 @@ class Settings:
|
|
|
66
66
|
allow_ddl: bool = False
|
|
67
67
|
allow_shell: bool = False
|
|
68
68
|
allow_listen: bool = False
|
|
69
|
+
allow_timescaledb_admin: bool = False
|
|
70
|
+
allow_alter_system: bool = False
|
|
71
|
+
alter_system_allowlist: tuple[str, ...] = ()
|
|
72
|
+
alter_system_denylist: tuple[str, ...] = ()
|
|
69
73
|
elicit_confirm_writes: bool = False
|
|
70
74
|
shell_timeout_sec: int = 60
|
|
71
75
|
shell_max_output_bytes: int = 64 * 1024 * 1024
|
|
@@ -131,7 +135,8 @@ class Settings:
|
|
|
131
135
|
# query when set. HTTP requests can override per-request by sending
|
|
132
136
|
# ``X-MCPG-Role: <role>``; when ``allowed_roles`` is set the header
|
|
133
137
|
# value must appear in it (otherwise a 403 is returned). Role names
|
|
134
|
-
#
|
|
138
|
+
# must be addressable identifiers (non-empty, no NUL, <= 63 bytes);
|
|
139
|
+
# delimited names (hyphens, spaces, mixed case) are quoted safely.
|
|
135
140
|
default_role: str | None = None
|
|
136
141
|
allowed_roles: tuple[str, ...] = ()
|
|
137
142
|
# Read-replica routing. When ``replica_urls`` is non-empty, every
|
|
@@ -314,6 +319,8 @@ class Settings:
|
|
|
314
319
|
f"allow_ddl={self.allow_ddl}, "
|
|
315
320
|
f"allow_shell={self.allow_shell}, "
|
|
316
321
|
f"allow_listen={self.allow_listen}, "
|
|
322
|
+
f"allow_timescaledb_admin={self.allow_timescaledb_admin}, "
|
|
323
|
+
f"allow_alter_system={self.allow_alter_system}, "
|
|
317
324
|
f"elicit_confirm_writes={self.elicit_confirm_writes}, "
|
|
318
325
|
f"shell_timeout_sec={self.shell_timeout_sec}, "
|
|
319
326
|
f"shell_max_output_bytes={self.shell_max_output_bytes}, "
|
|
@@ -553,6 +560,21 @@ def load_settings(env: Mapping[str, str] | None = None) -> Settings: # noqa: C9
|
|
|
553
560
|
if (raw := env.get("MCPG_ALLOW_DDL")) is not None:
|
|
554
561
|
allow_ddl = _parse_bool("MCPG_ALLOW_DDL", raw)
|
|
555
562
|
|
|
563
|
+
allow_timescaledb_admin = False
|
|
564
|
+
if (raw := env.get("MCPG_ALLOW_TIMESCALEDB_ADMIN")) is not None:
|
|
565
|
+
allow_timescaledb_admin = _parse_bool("MCPG_ALLOW_TIMESCALEDB_ADMIN", raw)
|
|
566
|
+
allow_alter_system = False
|
|
567
|
+
if (raw := env.get("MCPG_ALLOW_ALTER_SYSTEM")) is not None:
|
|
568
|
+
allow_alter_system = _parse_bool("MCPG_ALLOW_ALTER_SYSTEM", raw)
|
|
569
|
+
|
|
570
|
+
alter_system_allowlist: tuple[str, ...] = ()
|
|
571
|
+
if (raw := env.get("MCPG_ALTER_SYSTEM_ALLOWLIST")) is not None:
|
|
572
|
+
alter_system_allowlist = tuple(n.strip().lower() for n in raw.split(",") if n.strip())
|
|
573
|
+
|
|
574
|
+
alter_system_denylist: tuple[str, ...] = ()
|
|
575
|
+
if (raw := env.get("MCPG_ALTER_SYSTEM_DENYLIST")) is not None:
|
|
576
|
+
alter_system_denylist = tuple(n.strip().lower() for n in raw.split(",") if n.strip())
|
|
577
|
+
|
|
556
578
|
allow_shell = False
|
|
557
579
|
if (raw := env.get("MCPG_ALLOW_SHELL")) is not None:
|
|
558
580
|
allow_shell = _parse_bool("MCPG_ALLOW_SHELL", raw)
|
|
@@ -1279,6 +1301,10 @@ def load_settings(env: Mapping[str, str] | None = None) -> Settings: # noqa: C9
|
|
|
1279
1301
|
allow_ddl=allow_ddl,
|
|
1280
1302
|
allow_shell=allow_shell,
|
|
1281
1303
|
allow_listen=allow_listen,
|
|
1304
|
+
allow_timescaledb_admin=allow_timescaledb_admin,
|
|
1305
|
+
allow_alter_system=allow_alter_system,
|
|
1306
|
+
alter_system_allowlist=alter_system_allowlist,
|
|
1307
|
+
alter_system_denylist=alter_system_denylist,
|
|
1282
1308
|
elicit_confirm_writes=elicit_confirm_writes,
|
|
1283
1309
|
shell_timeout_sec=shell_timeout_sec,
|
|
1284
1310
|
shell_max_output_bytes=shell_max_output_bytes,
|
|
@@ -43,7 +43,12 @@ class DieselExportError(MCPgError):
|
|
|
43
43
|
|
|
44
44
|
def _check_identifier(name: str, kind: str) -> None:
|
|
45
45
|
if not _IDENTIFIER.match(name):
|
|
46
|
-
raise DieselExportError(
|
|
46
|
+
raise DieselExportError(
|
|
47
|
+
f"invalid {kind} name {name!r}; this exporter only accepts plain "
|
|
48
|
+
f"identifiers [A-Za-z_][A-Za-z0-9_]* because the name becomes a source "
|
|
49
|
+
f"identifier in generated code. SQL tools (export_table, dump_database, …) "
|
|
50
|
+
f"accept delimited names via quoting — see docs/identifier-policy.md."
|
|
51
|
+
)
|
|
47
52
|
|
|
48
53
|
|
|
49
54
|
def _strip_type_params(data_type: str) -> str:
|
|
@@ -40,7 +40,12 @@ class DrizzleError(MCPgError):
|
|
|
40
40
|
|
|
41
41
|
def _check_identifier(name: str, kind: str) -> None:
|
|
42
42
|
if not _IDENTIFIER.match(name):
|
|
43
|
-
raise DrizzleError(
|
|
43
|
+
raise DrizzleError(
|
|
44
|
+
f"invalid {kind} name {name!r}; this exporter only accepts plain "
|
|
45
|
+
f"identifiers [A-Za-z_][A-Za-z0-9_]* because the name becomes a source "
|
|
46
|
+
f"identifier in generated code. SQL tools (export_table, dump_database, …) "
|
|
47
|
+
f"accept delimited names via quoting — see docs/identifier-policy.md."
|
|
48
|
+
)
|
|
44
49
|
|
|
45
50
|
|
|
46
51
|
_SNAKE_BOUNDARY = re.compile(r"_+([a-z0-9])")
|
|
@@ -41,7 +41,12 @@ class EctoExportError(MCPgError):
|
|
|
41
41
|
|
|
42
42
|
def _check_identifier(name: str, kind: str) -> None:
|
|
43
43
|
if not _IDENTIFIER.match(name):
|
|
44
|
-
raise EctoExportError(
|
|
44
|
+
raise EctoExportError(
|
|
45
|
+
f"invalid {kind} name {name!r}; this exporter only accepts plain "
|
|
46
|
+
f"identifiers [A-Za-z_][A-Za-z0-9_]* because the name becomes a source "
|
|
47
|
+
f"identifier in generated code. SQL tools (export_table, dump_database, …) "
|
|
48
|
+
f"accept delimited names via quoting — see docs/identifier-policy.md."
|
|
49
|
+
)
|
|
45
50
|
|
|
46
51
|
|
|
47
52
|
def _strip_type_params(data_type: str) -> str:
|
|
@@ -37,7 +37,12 @@ class EntExportError(MCPgError):
|
|
|
37
37
|
|
|
38
38
|
def _check_identifier(name: str, kind: str) -> None:
|
|
39
39
|
if not _IDENTIFIER.match(name):
|
|
40
|
-
raise EntExportError(
|
|
40
|
+
raise EntExportError(
|
|
41
|
+
f"invalid {kind} name {name!r}; this exporter only accepts plain "
|
|
42
|
+
f"identifiers [A-Za-z_][A-Za-z0-9_]* because the name becomes a source "
|
|
43
|
+
f"identifier in generated code. SQL tools (export_table, dump_database, …) "
|
|
44
|
+
f"accept delimited names via quoting — see docs/identifier-policy.md."
|
|
45
|
+
)
|
|
41
46
|
|
|
42
47
|
|
|
43
48
|
def _pascal(snake: str) -> str:
|