SQL query security gateway for validating database access levels
Project description
AnomalyArmor Query Gateway
What is this?
This is the open-source SQL security layer that AnomalyArmor uses to control access to customer databases. Every query we execute against your database passes through this gateway.
Why open source? So you can verify exactly what queries we can and cannot run. No black boxes.
What does it do?
┌─────────────────────────────────┐
│ AnomalyArmor Platform │
└─────────────────────────────────┘
│
│
▼
┌────-─────────────────────────────────────────-────────────────────────-───────┐
│ Query Security Gateway │
│ ┌─────────────────┐ ┌─────────────────-┐ ┌────────────────────────┐ │
│ │ SQL Parser │ -> │ Access Validator │ -> │ Allow / Block + Log │ │
│ │ (sqlglot) │ │ (level rules) │ │ (audit trail) │ │
│ └─────────────────┘ └─────────────────-┘ └────────────────────────┘ │
└─────-─────────────────────────────────────────────────────────────────────────┘
│
| ALLOWED OPERATIONS ONLY
▼
┌────────────────-────────────────┐
│ Your Database │
└────────────────-────────────────┘
Validates SQL queries against three access levels:
| Level | What We Can Query | What We Cannot Query |
|---|---|---|
| Schema Only | Table names, column types, indexes | Any actual data |
| Aggregates | COUNT(*), AVG(salary), MAX(date) |
SELECT email FROM users |
| Full | Any SELECT query | - |
The gateway parses your SQL using sqlglot and blocks queries that violate the configured access level. If parsing fails, the query is blocked (fail-closed).
How do we know it works?
97 tests covering access level enforcement, SQL parsing, and security edge cases.
See TEST_RESULTS.md for the full breakdown, or run them yourself:
pip install -e ".[dev]"
pytest -v
Overview
The Query Security Gateway provides a transparent, auditable layer for controlling what types of SQL queries can be executed against customer databases. It supports three access levels:
| Level | Description | Allowed Queries |
|---|---|---|
schema_only |
Metadata access only | information_schema, pg_catalog, DESCRIBE, system tables |
aggregates |
Aggregate functions only | COUNT, SUM, AVG, MIN, MAX, COUNT DISTINCT - no raw column values |
full |
Unrestricted read access | Any SELECT query |
Installation
pip install anomalyarmor-query-gateway
Quick Start
from anomalyarmor_query_gateway import QuerySecurityGateway, AccessLevel
# Create gateway with desired access level
gateway = QuerySecurityGateway(
access_level=AccessLevel.AGGREGATES,
dialect="postgresql",
)
# Validate a query
result = gateway.validate_query_sync("SELECT COUNT(*) FROM users")
if result.allowed:
print("Query is allowed")
else:
print(f"Query blocked: {result.reason}")
Access Levels Explained
schema_only
Only allows queries against system/metadata tables:
- PostgreSQL:
information_schema.*,pg_catalog.* - MySQL:
information_schema.*,mysql.*,performance_schema.* - Databricks:
information_schema.*,system.* - ClickHouse:
system.* - SQLite:
sqlite_master,sqlite_schema
aggregates
Allows aggregate functions but blocks raw column values:
# Allowed
"SELECT COUNT(*) FROM users"
"SELECT AVG(salary) FROM employees"
"SELECT MIN(created_at), MAX(created_at) FROM orders"
# Blocked
"SELECT * FROM users"
"SELECT email FROM users"
"SELECT salary FROM employees WHERE id = 1"
full
Allows any valid SELECT query.
Async Support
from anomalyarmor_query_gateway import QuerySecurityGateway, AccessLevel
gateway = QuerySecurityGateway(
access_level=AccessLevel.AGGREGATES,
dialect="postgresql",
)
# Async validation with audit logging
result = await gateway.validate_query(
"SELECT COUNT(*) FROM users",
metadata={"asset_id": "123", "user_id": "456"}
)
Audit Logging
Implement the AuditLoggerProtocol to log all query validation attempts:
from anomalyarmor_query_gateway import (
QuerySecurityGateway,
AccessLevel,
AuditLoggerProtocol,
)
class MyAuditLogger(AuditLoggerProtocol):
async def log_query(
self,
query: str,
access_level: AccessLevel,
dialect: str,
allowed: bool,
rejection_reason: str | None,
metadata: dict,
) -> None:
# Store to your audit log
print(f"Query {'allowed' if allowed else 'blocked'}: {query[:50]}...")
gateway = QuerySecurityGateway(
access_level=AccessLevel.AGGREGATES,
dialect="postgresql",
audit_logger=MyAuditLogger(),
)
Supported Dialects
postgresql/postgresmysqldatabricksclickhousesqlite
Security
This package is designed to be a security control layer. Key security features:
- Fail-closed: If parsing fails, the query is blocked
- Comment stripping: SQL comments are removed before parsing to prevent obfuscation
- Recursive validation: Subqueries and CTEs are validated against the same rules
- Window function blocking: Window functions blocked in
aggregatesmode (can expose row-level data)
Development
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run linter
ruff check src/ tests/
# Run type checker
mypy src/
License
Apache 2.0 - See LICENSE for details.
Contributing
See CONTRIBUTING.md for guidelines.
Security Issues
See SECURITY.md for reporting security vulnerabilities.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file anomalyarmor_query_gateway-1.0.0.tar.gz.
File metadata
- Download URL: anomalyarmor_query_gateway-1.0.0.tar.gz
- Upload date:
- Size: 27.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
74cbe9ddf4acb895052e744b2efd7a5aff4a037cb3c9d173a963fd5c4bab8010
|
|
| MD5 |
ddd9fc3227bb101c73d517fd322429c6
|
|
| BLAKE2b-256 |
ada3ecc11f0c777667473c17de5e93ef18f89280b8ee054ef919870309d8dc5b
|
Provenance
The following attestation bundles were made for anomalyarmor_query_gateway-1.0.0.tar.gz:
Publisher:
publish.yml on anomalyarmor/anomalyarmor-query-gateway
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
anomalyarmor_query_gateway-1.0.0.tar.gz -
Subject digest:
74cbe9ddf4acb895052e744b2efd7a5aff4a037cb3c9d173a963fd5c4bab8010 - Sigstore transparency entry: 739287934
- Sigstore integration time:
-
Permalink:
anomalyarmor/anomalyarmor-query-gateway@ea18183c3b2ac689ec3e15221c9a9b5697ad17f1 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/anomalyarmor
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ea18183c3b2ac689ec3e15221c9a9b5697ad17f1 -
Trigger Event:
release
-
Statement type:
File details
Details for the file anomalyarmor_query_gateway-1.0.0-py3-none-any.whl.
File metadata
- Download URL: anomalyarmor_query_gateway-1.0.0-py3-none-any.whl
- Upload date:
- Size: 25.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
141637c81564b20fb13be1ff8148c3343a0277ae9de3ce313765608bb29f6da6
|
|
| MD5 |
aa70c5a519d89c128c311fbd14447835
|
|
| BLAKE2b-256 |
c7932c03bb91bfb54fb42bf5904c832df64e292502e82f2d1fa09ca1068346e8
|
Provenance
The following attestation bundles were made for anomalyarmor_query_gateway-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on anomalyarmor/anomalyarmor-query-gateway
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
anomalyarmor_query_gateway-1.0.0-py3-none-any.whl -
Subject digest:
141637c81564b20fb13be1ff8148c3343a0277ae9de3ce313765608bb29f6da6 - Sigstore transparency entry: 739287939
- Sigstore integration time:
-
Permalink:
anomalyarmor/anomalyarmor-query-gateway@ea18183c3b2ac689ec3e15221c9a9b5697ad17f1 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/anomalyarmor
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ea18183c3b2ac689ec3e15221c9a9b5697ad17f1 -
Trigger Event:
release
-
Statement type: