queryapigate 0.7.1__tar.gz → 0.8.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.
- {queryapigate-0.7.1/queryapigate.egg-info → queryapigate-0.8.0}/PKG-INFO +15 -9
- {queryapigate-0.7.1 → queryapigate-0.8.0}/README.md +14 -8
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/__init__.py +1 -1
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/app.py +10 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/config.py +77 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/openapi.py +5 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/ui.py +785 -310
- {queryapigate-0.7.1 → queryapigate-0.8.0/queryapigate.egg-info}/PKG-INFO +15 -9
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate.egg-info/SOURCES.txt +1 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_queryapigate.py +16 -0
- queryapigate-0.8.0/tests/test_settings.py +73 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/LICENSE +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/pyproject.toml +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/__main__.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/apikeys.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/bundle.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/cache.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/cli.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/collection_admin.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/cors.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/definitions.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/engine.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/errors.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/examples.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/formats.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/lib/h2-2.2.224.jar +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/logging_setup.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/metrics.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/params.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/pool.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/postman.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/ratelimit.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/runners.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/schema.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/sqltools.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate/store.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate.egg-info/dependency_links.txt +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate.egg-info/entry_points.txt +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate.egg-info/requires.txt +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/queryapigate.egg-info/top_level.txt +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/setup.cfg +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_api_keys.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_audit_log.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_cli.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_collection_bundle.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_collection_postman.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_collections.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_connection_encryption.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_cors_and_rate_limit.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_duckdb.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_examples.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_integration.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_jdbc.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_observability.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_params.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_release_check.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_response_cache.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_roles.py +0 -0
- {queryapigate-0.7.1 → queryapigate-0.8.0}/tests/test_sql_guard_fuzz.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: queryapigate
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Turn SQL into a REST API: run queries against MySQL, PostgreSQL, ClickHouse, SQLite or H2 over HTTP and get JSON, CSV, XML, YAML or XLSX back.
|
|
5
5
|
Author-email: Anantha Raju C <arcswdev@gmail.com>
|
|
6
6
|
License-Expression: FSL-1.1-MIT
|
|
@@ -74,8 +74,8 @@ Dynamic: license-file
|
|
|
74
74
|
[**Full documentation**](https://AnanthaRajuC.github.io/QueryAPIGate/)
|
|
75
75
|
|
|
76
76
|
<p align="center">
|
|
77
|
-
<a href="https://www.youtube.com/watch?v=
|
|
78
|
-
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/demo-thumbnail.png" alt="Watch the
|
|
77
|
+
<a href="https://www.youtube.com/watch?v=WWImFj4m95o">
|
|
78
|
+
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/demo-thumbnail.png" alt="Watch the demo: saved SQL queries as REST endpoints, scoped API keys, and the Move preview showing which keys gain or lose access" width="640">
|
|
79
79
|
</a>
|
|
80
80
|
</p>
|
|
81
81
|
|
|
@@ -109,7 +109,7 @@ Crimson Garden,Comedy,PG-13,631,2
|
|
|
109
109
|
<tr>
|
|
110
110
|
<td width="25%">
|
|
111
111
|
<a href="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/connections.png">
|
|
112
|
-
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/connections.png" alt="Connections
|
|
112
|
+
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/connections.png" alt="Connections screen with a sidebar and All/Active/Inactive tabs, listing ClickHouse, MySQL, PostgreSQL and SQLite connections with active/inactive status and each connection's live usage: queries run, failures and average latency">
|
|
113
113
|
</a>
|
|
114
114
|
<br><sub>Manage connections across every supported database, with live usage per connection</sub>
|
|
115
115
|
</td>
|
|
@@ -121,13 +121,13 @@ Crimson Garden,Comedy,PG-13,631,2
|
|
|
121
121
|
</td>
|
|
122
122
|
<td width="25%">
|
|
123
123
|
<a href="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/api-keys.png">
|
|
124
|
-
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/api-keys.png" alt="API keys
|
|
124
|
+
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/api-keys.png" alt="API keys screen showing keys created from roles and scoped to a collection (shown as a dashed name/ tag), an expiring partner key, per-key rate limits, and each key's last-used time and live usage">
|
|
125
125
|
</a>
|
|
126
126
|
<br><sub>Per-key permissions: connections, specific saved queries, expiry, rate limits - and what each key has actually done</sub>
|
|
127
127
|
</td>
|
|
128
128
|
<td width="25%">
|
|
129
129
|
<a href="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/roles.png">
|
|
130
|
-
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/roles.png" alt="Roles
|
|
130
|
+
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/roles.png" alt="Roles screen listing reusable permission templates - connections, read/write access, rate limit and IP allowlisting - with a New key from this shortcut">
|
|
131
131
|
</a>
|
|
132
132
|
<br><sub>Named roles: a reusable grant template, copied onto a key once at creation</sub>
|
|
133
133
|
</td>
|
|
@@ -138,19 +138,19 @@ Crimson Garden,Comedy,PG-13,631,2
|
|
|
138
138
|
<tr>
|
|
139
139
|
<td width="33%">
|
|
140
140
|
<a href="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/saved-query-history.png">
|
|
141
|
-
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/saved-query-history.png" alt="A saved query's History tab: every run with its time,
|
|
141
|
+
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/saved-query-history.png" alt="A saved query's History tab: every run with its time, calling API key, rows, duration and request ID, with a status filter and search box">
|
|
142
142
|
</a>
|
|
143
143
|
<br><sub>Run history per saved query: who called it, how long it took, and the request ID to find it in the logs</sub>
|
|
144
144
|
</td>
|
|
145
145
|
<td width="33%">
|
|
146
146
|
<a href="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/audit-log.png">
|
|
147
|
-
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/audit-log.png" alt="Audit
|
|
147
|
+
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/audit-log.png" alt="Audit log screen listing every administrative change - saved queries, roles and API keys created or updated - with an action filter and search box">
|
|
148
148
|
</a>
|
|
149
149
|
<br><sub>A durable audit log of every configuration change, filterable by action, actor and target</sub>
|
|
150
150
|
</td>
|
|
151
151
|
<td width="33%">
|
|
152
152
|
<a href="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/metrics.png">
|
|
153
|
-
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/metrics.png" alt="Metrics
|
|
153
|
+
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/metrics.png" alt="Metrics screen with stat tiles for requests, error rate, active queries, pool and rate limiting, bars for requests by status and queries by connection, and a per-connection latency table">
|
|
154
154
|
</a>
|
|
155
155
|
<br><sub>Live metrics with no Prometheus required - or import the bundled Grafana dashboard for history</sub>
|
|
156
156
|
</td>
|
|
@@ -341,6 +341,11 @@ version management, API key management, an audit log of administrative changes,
|
|
|
341
341
|
response inspection with a collapsible JSON tree for non-tabular results, a quick bar chart of any numeric
|
|
342
342
|
result, and one-click "copy as curl" / "copy as TSV" for any result.
|
|
343
343
|
|
|
344
|
+
The UI has a collapsible sidebar (Data, Access, Observability; `Ctrl`+`B` toggles it) and a read-only **Settings**
|
|
345
|
+
screen that shows every environment variable, its effective value and whether it was set or is the default (secrets are
|
|
346
|
+
reported as configured or not, never shown), with a "Copy as .env" button. Theme, table density and the default
|
|
347
|
+
result format are per-browser preferences.
|
|
348
|
+
|
|
344
349
|
```text
|
|
345
350
|
Connect Database
|
|
346
351
|
|
|
|
@@ -666,6 +671,7 @@ Clean up with `docker compose down -v`.
|
|
|
666
671
|
| `/api_keys` | GET, POST | List / create scoped API keys (admin only). |
|
|
667
672
|
| `/api_keys/<name>` | PATCH, DELETE | Update / revoke a scoped API key (admin only). |
|
|
668
673
|
| `/audit_log` | GET | Durable record of administrative changes - keys, connections, saved queries (admin only). |
|
|
674
|
+
| `/settings` | GET | The server's own configuration - each setting's effective value and whether it comes from the environment or the default; read-only, secrets never returned (admin only). |
|
|
669
675
|
| `/health`, `/docs`, `/openapi.json` | GET | Liveness, Swagger UI, OpenAPI spec. |
|
|
670
676
|
| `/metrics` | GET | Prometheus text-format metrics: request/query counts and latencies, pool occupancy, rate-limit rejections. |
|
|
671
677
|
| `/ui` | GET | A small admin UI: manage connections and saved queries, run ad-hoc SQL. |
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
[**Full documentation**](https://AnanthaRajuC.github.io/QueryAPIGate/)
|
|
15
15
|
|
|
16
16
|
<p align="center">
|
|
17
|
-
<a href="https://www.youtube.com/watch?v=
|
|
18
|
-
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/demo-thumbnail.png" alt="Watch the
|
|
17
|
+
<a href="https://www.youtube.com/watch?v=WWImFj4m95o">
|
|
18
|
+
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/demo-thumbnail.png" alt="Watch the demo: saved SQL queries as REST endpoints, scoped API keys, and the Move preview showing which keys gain or lose access" width="640">
|
|
19
19
|
</a>
|
|
20
20
|
</p>
|
|
21
21
|
|
|
@@ -49,7 +49,7 @@ Crimson Garden,Comedy,PG-13,631,2
|
|
|
49
49
|
<tr>
|
|
50
50
|
<td width="25%">
|
|
51
51
|
<a href="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/connections.png">
|
|
52
|
-
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/connections.png" alt="Connections
|
|
52
|
+
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/connections.png" alt="Connections screen with a sidebar and All/Active/Inactive tabs, listing ClickHouse, MySQL, PostgreSQL and SQLite connections with active/inactive status and each connection's live usage: queries run, failures and average latency">
|
|
53
53
|
</a>
|
|
54
54
|
<br><sub>Manage connections across every supported database, with live usage per connection</sub>
|
|
55
55
|
</td>
|
|
@@ -61,13 +61,13 @@ Crimson Garden,Comedy,PG-13,631,2
|
|
|
61
61
|
</td>
|
|
62
62
|
<td width="25%">
|
|
63
63
|
<a href="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/api-keys.png">
|
|
64
|
-
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/api-keys.png" alt="API keys
|
|
64
|
+
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/api-keys.png" alt="API keys screen showing keys created from roles and scoped to a collection (shown as a dashed name/ tag), an expiring partner key, per-key rate limits, and each key's last-used time and live usage">
|
|
65
65
|
</a>
|
|
66
66
|
<br><sub>Per-key permissions: connections, specific saved queries, expiry, rate limits - and what each key has actually done</sub>
|
|
67
67
|
</td>
|
|
68
68
|
<td width="25%">
|
|
69
69
|
<a href="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/roles.png">
|
|
70
|
-
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/roles.png" alt="Roles
|
|
70
|
+
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/roles.png" alt="Roles screen listing reusable permission templates - connections, read/write access, rate limit and IP allowlisting - with a New key from this shortcut">
|
|
71
71
|
</a>
|
|
72
72
|
<br><sub>Named roles: a reusable grant template, copied onto a key once at creation</sub>
|
|
73
73
|
</td>
|
|
@@ -78,19 +78,19 @@ Crimson Garden,Comedy,PG-13,631,2
|
|
|
78
78
|
<tr>
|
|
79
79
|
<td width="33%">
|
|
80
80
|
<a href="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/saved-query-history.png">
|
|
81
|
-
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/saved-query-history.png" alt="A saved query's History tab: every run with its time,
|
|
81
|
+
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/saved-query-history.png" alt="A saved query's History tab: every run with its time, calling API key, rows, duration and request ID, with a status filter and search box">
|
|
82
82
|
</a>
|
|
83
83
|
<br><sub>Run history per saved query: who called it, how long it took, and the request ID to find it in the logs</sub>
|
|
84
84
|
</td>
|
|
85
85
|
<td width="33%">
|
|
86
86
|
<a href="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/audit-log.png">
|
|
87
|
-
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/audit-log.png" alt="Audit
|
|
87
|
+
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/audit-log.png" alt="Audit log screen listing every administrative change - saved queries, roles and API keys created or updated - with an action filter and search box">
|
|
88
88
|
</a>
|
|
89
89
|
<br><sub>A durable audit log of every configuration change, filterable by action, actor and target</sub>
|
|
90
90
|
</td>
|
|
91
91
|
<td width="33%">
|
|
92
92
|
<a href="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/metrics.png">
|
|
93
|
-
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/metrics.png" alt="Metrics
|
|
93
|
+
<img src="https://raw.githubusercontent.com/AnanthaRajuC/QueryAPIGate/main/documentation/screenshots/metrics.png" alt="Metrics screen with stat tiles for requests, error rate, active queries, pool and rate limiting, bars for requests by status and queries by connection, and a per-connection latency table">
|
|
94
94
|
</a>
|
|
95
95
|
<br><sub>Live metrics with no Prometheus required - or import the bundled Grafana dashboard for history</sub>
|
|
96
96
|
</td>
|
|
@@ -281,6 +281,11 @@ version management, API key management, an audit log of administrative changes,
|
|
|
281
281
|
response inspection with a collapsible JSON tree for non-tabular results, a quick bar chart of any numeric
|
|
282
282
|
result, and one-click "copy as curl" / "copy as TSV" for any result.
|
|
283
283
|
|
|
284
|
+
The UI has a collapsible sidebar (Data, Access, Observability; `Ctrl`+`B` toggles it) and a read-only **Settings**
|
|
285
|
+
screen that shows every environment variable, its effective value and whether it was set or is the default (secrets are
|
|
286
|
+
reported as configured or not, never shown), with a "Copy as .env" button. Theme, table density and the default
|
|
287
|
+
result format are per-browser preferences.
|
|
288
|
+
|
|
284
289
|
```text
|
|
285
290
|
Connect Database
|
|
286
291
|
|
|
|
@@ -606,6 +611,7 @@ Clean up with `docker compose down -v`.
|
|
|
606
611
|
| `/api_keys` | GET, POST | List / create scoped API keys (admin only). |
|
|
607
612
|
| `/api_keys/<name>` | PATCH, DELETE | Update / revoke a scoped API key (admin only). |
|
|
608
613
|
| `/audit_log` | GET | Durable record of administrative changes - keys, connections, saved queries (admin only). |
|
|
614
|
+
| `/settings` | GET | The server's own configuration - each setting's effective value and whether it comes from the environment or the default; read-only, secrets never returned (admin only). |
|
|
609
615
|
| `/health`, `/docs`, `/openapi.json` | GET | Liveness, Swagger UI, OpenAPI spec. |
|
|
610
616
|
| `/metrics` | GET | Prometheus text-format metrics: request/query counts and latencies, pool occupancy, rate-limit rejections. |
|
|
611
617
|
| `/ui` | GET | A small admin UI: manage connections and saved queries, run ad-hoc SQL. |
|
|
@@ -846,6 +846,16 @@ def audit_log_endpoint():
|
|
|
846
846
|
return jsonify({'entries': list(reversed(store.read_audit_log()))}), 200
|
|
847
847
|
|
|
848
848
|
|
|
849
|
+
@bp.route('/settings', methods=['GET'])
|
|
850
|
+
def settings_endpoint():
|
|
851
|
+
"""The server's own configuration as the admin UI's Settings screen shows it: every environment variable
|
|
852
|
+
that matters, its effective value and whether it was set or is the default. Read-only, and admin only
|
|
853
|
+
like the rest of what reveals the server's configuration. Secrets are reported as configured or not,
|
|
854
|
+
never returned."""
|
|
855
|
+
require_admin()
|
|
856
|
+
return jsonify({'sections': config.describe_settings()}), 200
|
|
857
|
+
|
|
858
|
+
|
|
849
859
|
# --------------------------------------------------------------------------------------
|
|
850
860
|
# Service endpoints
|
|
851
861
|
# --------------------------------------------------------------------------------------
|
|
@@ -278,3 +278,80 @@ def slow_query_threshold():
|
|
|
278
278
|
if value == 0:
|
|
279
279
|
return None
|
|
280
280
|
return value if value > 0 else DEFAULT_SLOW_QUERY_THRESHOLD
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def _seconds(value):
|
|
284
|
+
return None if value is None else f'{value:g} s'
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def describe_settings():
|
|
288
|
+
"""Every server setting the admin UI's Settings screen shows, grouped: [{id, title, description, rows}].
|
|
289
|
+
|
|
290
|
+
Each row is {label, description, env, value, source, env_value}. ``value`` is what to display (secrets are
|
|
291
|
+
reduced to "configured" / "enabled" - never the secret itself), ``source`` is "env" when the variable is set
|
|
292
|
+
and "default" when the built-in default applies, and ``env_value`` is the raw value for a "copy as .env"
|
|
293
|
+
export, or None for a secret so that export can never leak one. Read-only: settings are environment
|
|
294
|
+
variables, changed by restarting the server, not through the API."""
|
|
295
|
+
def row(label, description, env, value, secret=False):
|
|
296
|
+
raw = os.environ.get(env, '').strip()
|
|
297
|
+
return {'label': label, 'description': description, 'env': env, 'value': value,
|
|
298
|
+
'source': 'env' if raw else 'default', 'env_value': None if secret or not raw else raw}
|
|
299
|
+
|
|
300
|
+
def on_off(flag):
|
|
301
|
+
return 'on' if flag else 'off'
|
|
302
|
+
|
|
303
|
+
stream = stream_max_rows()
|
|
304
|
+
timeout, slow = query_timeout(), slow_query_threshold()
|
|
305
|
+
limit, export = rate_limit(), audit_log_export_file()
|
|
306
|
+
cors = cors_origins()
|
|
307
|
+
return [
|
|
308
|
+
{'id': 'general', 'title': 'General',
|
|
309
|
+
'description': 'Where this server keeps its files and what it loads at startup.', 'rows': [
|
|
310
|
+
row('Home directory', 'Folder holding db_connections.json, api_keys.json, roles.json and saved_sql/.',
|
|
311
|
+
'QUERYAPIGATE_HOME', str(home())),
|
|
312
|
+
row('Load examples', 'Load the example APIs at startup. Idempotent.',
|
|
313
|
+
'QUERYAPIGATE_LOAD_EXAMPLES', on_off(load_examples())),
|
|
314
|
+
row('H2 driver', 'JAR used for h2 connections.', 'QUERYAPIGATE_H2_JAR',
|
|
315
|
+
Path(h2_jar()).name + ('' if os.environ.get('QUERYAPIGATE_H2_JAR') else ' (bundled)'))]},
|
|
316
|
+
{'id': 'security', 'title': 'Security',
|
|
317
|
+
'description': 'Admin access, write protection and secrets at rest.', 'rows': [
|
|
318
|
+
row('Admin API key', 'Key with full access to this UI and the admin API. Unset means open access.',
|
|
319
|
+
'QUERYAPIGATE_API_KEY', 'configured' if api_key() else 'not set - open access', secret=True),
|
|
320
|
+
row('Allow writes', 'When off, statements that modify data are rejected.',
|
|
321
|
+
'QUERYAPIGATE_ALLOW_WRITES', on_off(allow_writes())),
|
|
322
|
+
row('Encryption at rest', 'Fernet key used to encrypt connection passwords on disk.',
|
|
323
|
+
'QUERYAPIGATE_SECRET_KEY', 'enabled' if secret_key() else 'off', secret=True),
|
|
324
|
+
row('Trusted proxy hops', 'Reverse proxies whose X-Forwarded-* headers are trusted.',
|
|
325
|
+
'QUERYAPIGATE_TRUST_PROXY', str(proxy_hops()))]},
|
|
326
|
+
{'id': 'execution', 'title': 'Query execution',
|
|
327
|
+
'description': 'Limits applied to every statement this server runs.', 'rows': [
|
|
328
|
+
row('Query timeout', 'Server-wide statement limit. A request may ask for less, never more. '
|
|
329
|
+
'0 disables it.', 'QUERYAPIGATE_QUERY_TIMEOUT', _seconds(timeout) or 'off'),
|
|
330
|
+
row('Max page size', 'Largest page_size a caller may request.', 'QUERYAPIGATE_MAX_PAGE_SIZE',
|
|
331
|
+
f'{max_page_size()} rows'),
|
|
332
|
+
row('Stream row cap', 'Row cap for ?stream=true exports.', 'QUERYAPIGATE_STREAM_MAX_ROWS',
|
|
333
|
+
'unbounded' if stream is None else f'{stream} rows'),
|
|
334
|
+
row('Slow query threshold', 'Queries slower than this are logged as warnings. 0 disables it.',
|
|
335
|
+
'QUERYAPIGATE_SLOW_QUERY_THRESHOLD', _seconds(slow) or 'off')]},
|
|
336
|
+
{'id': 'pool', 'title': 'Connection pool',
|
|
337
|
+
'description': 'Idle connections kept open per distinct connection.', 'rows': [
|
|
338
|
+
row('Pool size', 'Idle connections kept per connection. 0 disables pooling.',
|
|
339
|
+
'QUERYAPIGATE_POOL_SIZE', str(pool_size())),
|
|
340
|
+
row('Idle timeout', 'How long an idle pooled connection is kept before it is closed.',
|
|
341
|
+
'QUERYAPIGATE_POOL_IDLE_TIMEOUT', _seconds(pool_idle_timeout()))]},
|
|
342
|
+
{'id': 'traffic', 'title': 'Rate limits & CORS',
|
|
343
|
+
'description': 'Per-client throttling and browser origins allowed to call the API.', 'rows': [
|
|
344
|
+
row('Rate limit', 'Requests allowed per client. API keys and roles can set their own.',
|
|
345
|
+
'QUERYAPIGATE_RATE_LIMIT', format_rate_limit(limit) or 'off'),
|
|
346
|
+
row('CORS origins', 'Comma-separated origins, or * for any. Unset turns CORS off.',
|
|
347
|
+
'QUERYAPIGATE_CORS_ORIGINS',
|
|
348
|
+
'off' if cors is None else '*' if cors == '*' else ', '.join(sorted(cors)))]},
|
|
349
|
+
{'id': 'audit', 'title': 'Audit & logging',
|
|
350
|
+
'description': 'Retention of administrative actions and log format.', 'rows': [
|
|
351
|
+
row('Audit log limit', 'Entries kept in audit_log.json.', 'QUERYAPIGATE_AUDIT_LOG_LIMIT',
|
|
352
|
+
str(audit_log_limit())),
|
|
353
|
+
row('Audit export file', 'Append-only JSON-lines copy of every audit entry, never rolled off.',
|
|
354
|
+
'QUERYAPIGATE_AUDIT_LOG_EXPORT_FILE', 'not set' if export is None else str(export)),
|
|
355
|
+
row('JSON logs', 'One JSON object per line instead of plain text.', 'QUERYAPIGATE_JSON_LOGS',
|
|
356
|
+
on_off(json_logs()))]},
|
|
357
|
+
]
|
|
@@ -400,6 +400,11 @@ def build_spec(version, saved_queries=None):
|
|
|
400
400
|
'summary': 'A durable record of administrative changes - API keys, roles, connections and '
|
|
401
401
|
'saved queries created, changed or removed (admin only)', 'tags': ['API keys'],
|
|
402
402
|
'responses': {'200': {'description': 'Newest entry first, capped at 500 entries'}, **_ERRORS}}},
|
|
403
|
+
'/settings': {'get': {
|
|
404
|
+
'summary': "The server's own configuration: each setting's effective value and whether it comes "
|
|
405
|
+
'from the environment or is the default (admin only, read-only; secrets are reported '
|
|
406
|
+
'as configured or not, never returned)', 'tags': ['Service'],
|
|
407
|
+
'responses': {'200': {'description': 'Settings grouped into sections'}, **_ERRORS}}},
|
|
403
408
|
'/catalog': {'get': {
|
|
404
409
|
'summary': 'Every saved query this caller can reach, and the terms it is offered under',
|
|
405
410
|
'tags': ['Saved queries'],
|