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.
Metadata
Release files for anomalyarmor-query-gateway 1.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| anomalyarmor_query_gateway-1.0.2.tar.gz | 35.3 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| anomalyarmor_query_gateway-1.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 63.2 kB
Release files / anomalyarmor_query_gateway-1.0.2.tar.gz
| Download URL | anomalyarmor_query_gateway-1.0.2.tar.gz |
|---|---|
| Size | 35.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d335928ee37791e07b5d4889c7c83d79900f03ae0d2179a3794ef6ff9b507a13
|
|
BLAKE2b-256 checksum How to use checksums |
10c383824dfcfd39db993620c51a59ea3f6a572bab93bcc69fd412c94abc696d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Dec 13, 2025.
Transparency logRelease files / anomalyarmor_query_gateway-1.0.2-py3-none-any.whl
| Download URL | anomalyarmor_query_gateway-1.0.2-py3-none-any.whl |
|---|---|
| Size | 27.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3d4dec69a884729df7f776a003d32cda64ae5fae49471cb37762b4010f8ab746
|
|
BLAKE2b-256 checksum How to use checksums |
a3cac9f9d8ef968437cd5c13680ac007d0ff7dd5c9399075375b0eb2b7e9e399
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Dec 13, 2025.
Transparency logSecurity for anomalyarmor-query-gateway 1.0.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for anomalyarmor_query_gateway-1.0.2.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Dec 13, 2025.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.