Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
d94c77c
docs: add audit-remediation implementation plan and project-incubatio…
devopam Aug 25, 2026
53028a1
chore: audit remediation batch 1 (governance, packaging, configuration)
devopam Aug 25, 2026
f0f017d
fix: correct CODE_OF_CONDUCT.md verbatim text and add missing MCPG_NL…
devopam Aug 25, 2026
57c451f
refactor: introduce MCPgError as the common base for domain exceptions
devopam Aug 25, 2026
fe95e70
fix: log 7 silent except-pass sites and preserve tracebacks in 23 err…
devopam Aug 25, 2026
be8b3aa
fix: remove exc_info from 5 redaction-sensitive log sites; strengthen…
devopam Aug 25, 2026
6fd5a18
feat(http): mount /readyz readiness probe
devopam Aug 25, 2026
9ee5dda
fix(query): bound result-set fetch instead of materialize-then-truncate
devopam Aug 26, 2026
03d566c
security!: HTTP transport fails closed without auth configured
devopam Aug 26, 2026
8ef0352
security!: rate limiting enabled by default
devopam Aug 26, 2026
eaf7abb
security: bump HSTS default to 2 years, add optional TrustedHostMiddl…
devopam Aug 26, 2026
6d55775
feat(nl2sql): record schema-context provenance on TranslationResult
devopam Aug 26, 2026
d35239e
perf: reuse a shared httpx.AsyncClient in NL2SQL providers and OIDCVe…
devopam Aug 26, 2026
e916ff4
feat: add circuit breaker around external LLM provider and OIDC JWKS …
devopam Aug 26, 2026
5af2950
feat: add retry-with-backoff around external LLM provider and OIDC JW…
devopam Aug 26, 2026
368cb79
test: cover translate_nl_to_sql's CircuitBreakerError -> NL2SQLError …
devopam Aug 26, 2026
41b5bf4
security: add centralized log-redaction filter as a backstop
devopam Aug 26, 2026
05f09f1
security: fix RedactionFilter scope claims and add end-to-end redacti…
devopam Aug 26, 2026
16d6c30
ci: add license enumeration (pip-licenses) as a non-blocking report
devopam Aug 26, 2026
9a43acf
docs(ci): document the verified [bot]-namespace assumption in auto-me…
devopam Aug 26, 2026
2aecffc
fix(ci): move [bot]-namespace comment out of the if: block scalar
devopam Aug 26, 2026
e2b8258
fix(graph): validate catalog-derived label names before SQL interpola…
devopam Aug 26, 2026
a746536
test: strengthen 5 bare-truthy assertions to check actual expected va…
devopam Aug 26, 2026
aad55e9
test: strengthen 5 bare-truthy assertions to check actual interpolate…
devopam Aug 26, 2026
537da62
chore(deps): add pytest-mock, pytest-randomly, pytest-socket, time-ma…
devopam Aug 26, 2026
dfcc0a6
style: fix PTH, C4, SIM, PYI ruff findings (74 violations)
devopam Aug 27, 2026
b5e02dc
fix(contract): regenerate tool-return-shapes snapshot for schema_cont…
devopam Aug 27, 2026
2b3de26
style: assess ASYNC and C901 ruff findings (Task 23 Steps 6-7)
devopam Aug 27, 2026
853e55f
fix(docs): correct run_select_tuned's ASYNC109 noqa rationale + flag …
devopam Aug 27, 2026
eab2ef0
style(tools): make 53 boolean tool parameters keyword-only (FBT, tool…
devopam Aug 31, 2026
525ccc1
docs(changelog): correct stale ~93 FBT remainder figure to 157
devopam Aug 31, 2026
bd1c470
style: make 18 boolean parameters keyword-only (FBT, src/ + tools/)
devopam Aug 31, 2026
393cb61
docs(changelog): correct FBT Part D call-site counts
devopam Aug 31, 2026
2f16abe
docs(changelog): state the 20-signature count for FBT Part D
devopam Aug 31, 2026
66d9d46
style(tests): make 126 boolean parameters/call-sites keyword-only (FB…
devopam Aug 31, 2026
bad1f96
style: enable C90, ASYNC, C4, SIM, PTH, PYI, FBT in ruff select list …
devopam Aug 31, 2026
01bc5a5
docs: fix final-review Minor findings (M-1..M-4)
devopam Aug 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .clusterfuzzlite/sql_safety_fuzzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
known-shape attacks; this harness covers unknown-shape inputs).
"""

import contextlib
import sys

import atheris
Expand All @@ -27,10 +28,8 @@
def test_one_input(data: bytes) -> None:
fdp = atheris.FuzzedDataProvider(data)
query = fdp.ConsumeUnicodeNoSurrogates(fdp.remaining_bytes())
try:
with contextlib.suppress(ValueError): # expected: malformed or policy-disallowed SQL is rejected
_driver._validate(query) # fuzzing the private validator directly
except ValueError:
pass # expected: malformed or policy-disallowed SQL is rejected


atheris.Setup(sys.argv, test_one_input)
Expand Down
21 changes: 21 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
root = true

[*]
indent_style = space
indent_size = 4
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true

[*.py]
indent_size = 4

[*.md]
trim_trailing_whitespace = false

[*.{yml,yaml,json,toml}]
indent_size = 2

[*.{bat,cmd}]
end_of_line = crlf
149 changes: 149 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# MCPg configuration template — copy to .env and fill in real values.
# Every MCPG_* variable this server reads; see docs/user-guide.md for full detail on each.

# --- Database (required) ---
MCPG_DATABASE_URL=postgresql://user:password@localhost:5432/dbname

# --- Secondary databases (optional) ---
# MCPG_SECONDARY_DATABASE_URLS=db1=postgresql://user:password@localhost:5432/db1,db2=postgresql://user:password@localhost:5432/db2

# --- Read replicas (optional) ---
# MCPG_REPLICA_URLS=postgresql://user:password@replica1:5432/dbname,postgresql://user:password@replica2:5432/dbname

# --- Access mode ---
# MCPG_ACCESS_MODE=read-only # read-only | restricted | unrestricted

# --- Capability gates (unrestricted mode only) ---
# MCPG_ALLOW_DDL=false
# MCPG_ALLOW_SHELL=false
# MCPG_ALLOW_LISTEN=false
# MCPG_ALLOW_INSECURE_TLS=false

# --- Connection pool ---
# MCPG_POOL_MIN_SIZE=1
# MCPG_POOL_MAX_SIZE=5

# --- HTTP transport ---
# MCPG_TRANSPORT=stdio # stdio | streamable-http | sse
# MCPG_HTTP_HOST=127.0.0.1
# MCPG_HTTP_PORT=8000
# MCPG_HTTP_AUTH_TOKEN=your-bearer-token
# MCPG_HTTP_MAX_BODY_BYTES=1048576
# MCPG_HTTP_ALLOWED_ORIGINS=http://localhost:3000,https://example.com
# MCPG_HTTP_IP_ALLOWLIST=127.0.0.1,192.168.1.0/24
# MCPG_HTTP_HSTS_MAX_AGE=63072000
# MCPG_HTTP_REQUEST_TIMEOUT_SECONDS=0
# MCPG_HTTP_TRUSTED_HOSTS=api.example.com,*.example.com

# --- HTTP transport TLS/mTLS ---
# MCPG_HTTP_TLS_CERTFILE=/path/to/cert.pem
# MCPG_HTTP_TLS_KEYFILE=/path/to/key.pem
# MCPG_HTTP_TLS_CA_CERTS=/path/to/ca-certs.pem
# MCPG_HTTP_TLS_CLIENT_CERT_REQUIRED=false

# --- Authentication ---
# MCPG_AUTH_MODE=static # static | oidc
# MCPG_OIDC_ISSUER=https://example.auth0.com/
# MCPG_OIDC_AUDIENCE=https://api.example.com
# MCPG_OIDC_JWKS_URL=https://example.auth0.com/.well-known/jwks.json
# MCPG_OIDC_ROLE_CLAIM=pg_role

# --- Multi-tenancy via PG roles ---
# MCPG_DEFAULT_ROLE=app_user
# MCPG_ALLOWED_ROLES=app_user,analyst,admin

# --- Logging ---
# MCPG_LOG_LEVEL=INFO # DEBUG | INFO | WARNING | ERROR | CRITICAL
# MCPG_LOG_FORMAT=text # text | json

# --- Shell (PG binaries: pg_dump, pg_restore, psql) ---
# MCPG_SHELL_TIMEOUT_SEC=60
# MCPG_SHELL_MAX_OUTPUT_BYTES=67108864
# MCPG_SUBPROCESS_BIN_ALLOWLIST=/usr/lib/postgresql/bin:/usr/local/bin
# MCPG_SUBPROCESS_CPU_SECONDS=300
# MCPG_SUBPROCESS_MEMORY_MB=512

# --- Query execution ---
# MCPG_STATEMENT_TIMEOUT_MS=30000
# MCPG_LOCK_TIMEOUT_MS=5000
# MCPG_SLOW_CALL_THRESHOLD_MS=1000
# MCPG_ELICIT_CONFIRM_WRITES=false
# MCPG_LISTEN_QUEUE_MAX=1000

# --- Analytical queries ---
# MCPG_ENABLE_ANALYTICAL_QUERIES=true
# MCPG_ANALYTICAL_TIMEOUT_MS=120000
# MCPG_ANALYTICAL_MAX_TIMEOUT_MS=600000
# MCPG_ANALYTICAL_MAX_CONCURRENCY=2

# --- Audit trail ---
# MCPG_AUDIT_PERSIST=false
# MCPG_AUDIT_REDACT_KEYS=password,secret,token # Comma-separated keys to redact in audit logs
# MCPG_AUDIT_EVENTS_BACKEND=timescaledb # timescaledb | pg_partman | native
# MCPG_AUDIT_EVENTS_RETENTION_DAYS=90
# MCPG_AUDIT_EVENTS_CHUNK_INTERVAL=1 day
# MCPG_AUDIT_EVENTS_COMPRESS_AFTER=7 days
# MCPG_AUDIT_EVENTS_RLS=true
# MCPG_AUDIT_EVENTS_READER_ROLE=audit_reader

# --- RAG telemetry ---
# MCPG_RAG_TELEMETRY_BACKEND=timescaledb # timescaledb | pg_partman | native
# MCPG_RAG_TELEMETRY_RETENTION_DAYS=90
# MCPG_RAG_TELEMETRY_CHUNK_INTERVAL=1 day
# MCPG_RAG_TELEMETRY_COMPRESS_AFTER=7 days
# MCPG_RAG_TELEMETRY_RLS=true
# MCPG_RAG_TELEMETRY_READER_ROLE=rag_reader

# --- NL→SQL (natural language to SQL) ---
# MCPG_NL2SQL_PROVIDER=anthropic # anthropic | openai | gemini | deepinfra | etc.
# MCPG_NL2SQL_API_KEY=your-nl2sql-provider-api-key
# MCPG_NL2SQL_MODEL=claude-3-5-sonnet-20241022
# MCPG_NL2SQL_BASE_URL=https://api.anthropic.com/v1
# MCPG_NL2SQL_MAX_TOKENS=2048
# MCPG_NL2SQL_CUSTOM_PROVIDERS=ollama=http://localhost:11434|llama2

# --- NL→SQL audit ---
# MCPG_NL2SQL_AUDIT_PERSIST=false
# MCPG_NL2SQL_AUDIT_BACKEND=timescaledb # timescaledb | pg_partman | native
# MCPG_NL2SQL_AUDIT_RETENTION_DAYS=90
# MCPG_NL2SQL_AUDIT_CHUNK_INTERVAL=1 day
# MCPG_NL2SQL_AUDIT_COMPRESS_AFTER=7 days
# MCPG_NL2SQL_AUDIT_RLS=true
# MCPG_NL2SQL_AUDIT_READER_ROLE=nl2sql_audit_reader

# --- Rate limiting ---
# MCPG_RATE_LIMIT_ENABLED=false
# MCPG_RATE_LIMIT_MAX_REQUESTS=60
# MCPG_RATE_LIMIT_WINDOW_SECONDS=60
# MCPG_RATE_LIMIT_HEAVY_MAX=5
# MCPG_RATE_LIMIT_HEAVY_WINDOW=60

# --- Caching ---
# MCPG_CACHE_ENABLED=true
# MCPG_CACHE_TTL_SECONDS=300
# MCPG_CACHE_MAXSIZE=1024
# MCPG_REDIS_URL=redis://localhost:6379/0

# --- OpenTelemetry (OTEL) tracing ---
# MCPG_OTEL_ENABLED=false
# MCPG_OTEL_SERVICE_NAME=mcpg

# --- Session intent ---
# MCPG_SESSION_INTENT=lookup,migration,vector_rag,monitor,admin
# MCPG_DYNAMIC_SESSION_INTENT=false

# --- Observability and diagnostics ---
# MCPG_ENABLE_HEAVY_DIAGNOSTICS=true

# --- Migrations ---
# MCPG_MIGRATION_SCRIPTS_ROOTS=/app/migrations

# --- Audit integrity ---
# MCPG_AUDIT_HMAC_KEY=your-secret-hmac-key
# MCPG_AUDIT_INTEGRITY=false

# --- Secrets backend ---
# MCPG_SECRETS_BACKEND=env # env | file | vault | aws | gcp

# --- Server lifecycle ---
# MCPG_SHUTDOWN_DRAIN_SECONDS=30
5 changes: 5 additions & 0 deletions .github/workflows/auto-merge-bot-prs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ jobs:
auto-merge-bot-prs:
name: Auto-merge unsigned bot PRs
runs-on: ubuntu-latest
# The `[bot]`-suffix username namespace is reserved for GitHub App identities
# (confirmed via `gh api users/dependabot%5Bbot%5D` — `type: Bot`); a human account
# cannot register one, so the `endsWith(github.actor, '[bot]')` clause below
# doesn't broaden trust beyond the three named bots in practice. Re-verify this
# assumption if GitHub's account-namespace rules ever change.
if: |
github.actor == 'dependabot[bot]' ||
github.actor == 'renovate[bot]' ||
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ jobs:
uv run pip-audit --strict --disable-pip -r /tmp/mcpg-reqs.txt
- name: Bandit static analysis (SAST)
run: uv run bandit -r src/mcpg --skip B101,B608,B110 -ll
# Non-blocking license inventory: report the dependency tree's
# license mix so a maintainer can review it, without gating merge
# on any particular license yet (no `--fail-on`). Promote to a
# blocking check once the current mix has been reviewed and an
# explicit allow/deny policy is written.
- name: License enumeration (pip-licenses)
continue-on-error: true
run: uv run pip-licenses --format=markdown --with-urls --order=license

test:
name: Tests (PG ${{ matrix.postgres }})
Expand Down
Loading
Loading