fix: scope admin infra pages to current tenant's tables and indices
Database tables filtered to current_schema(), active queries to current_database(), OpenSearch indices to configured index-prefix. Delete endpoint rejects indices outside application scope. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -72,13 +72,14 @@ public class DatabaseAdminController {
|
||||
@Operation(summary = "Get table sizes and row counts")
|
||||
public ResponseEntity<List<TableSizeResponse>> getTables() {
|
||||
var tables = jdbc.query("""
|
||||
SELECT schemaname || '.' || relname AS table_name,
|
||||
SELECT relname AS table_name,
|
||||
n_live_tup AS row_count,
|
||||
pg_size_pretty(pg_total_relation_size(relid)) AS data_size,
|
||||
pg_total_relation_size(relid) AS data_size_bytes,
|
||||
pg_size_pretty(pg_indexes_size(relid)) AS index_size,
|
||||
pg_indexes_size(relid) AS index_size_bytes
|
||||
FROM pg_stat_user_tables
|
||||
WHERE schemaname = current_schema()
|
||||
ORDER BY pg_total_relation_size(relid) DESC
|
||||
""", (rs, row) -> new TableSizeResponse(
|
||||
rs.getString("table_name"), rs.getLong("row_count"),
|
||||
@@ -94,7 +95,7 @@ public class DatabaseAdminController {
|
||||
SELECT pid, EXTRACT(EPOCH FROM (now() - query_start)) AS duration_seconds,
|
||||
state, query
|
||||
FROM pg_stat_activity
|
||||
WHERE state != 'idle' AND pid != pg_backend_pid()
|
||||
WHERE state != 'idle' AND pid != pg_backend_pid() AND datname = current_database()
|
||||
ORDER BY query_start ASC
|
||||
""", (rs, row) -> new ActiveQueryResponse(
|
||||
rs.getInt("pid"), rs.getDouble("duration_seconds"),
|
||||
|
||||
@@ -48,17 +48,20 @@ public class OpenSearchAdminController {
|
||||
private final AuditService auditService;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final String opensearchUrl;
|
||||
private final String indexPrefix;
|
||||
|
||||
public OpenSearchAdminController(OpenSearchClient client, RestClient restClient,
|
||||
SearchIndexerStats indexerStats, AuditService auditService,
|
||||
ObjectMapper objectMapper,
|
||||
@Value("${opensearch.url:http://localhost:9200}") String opensearchUrl) {
|
||||
@Value("${opensearch.url:http://localhost:9200}") String opensearchUrl,
|
||||
@Value("${opensearch.index-prefix:executions-}") String indexPrefix) {
|
||||
this.client = client;
|
||||
this.restClient = restClient;
|
||||
this.indexerStats = indexerStats;
|
||||
this.auditService = auditService;
|
||||
this.objectMapper = objectMapper;
|
||||
this.opensearchUrl = opensearchUrl;
|
||||
this.indexPrefix = indexPrefix;
|
||||
}
|
||||
|
||||
@GetMapping("/status")
|
||||
@@ -109,6 +112,9 @@ public class OpenSearchAdminController {
|
||||
List<IndexInfoResponse> allIndices = new ArrayList<>();
|
||||
for (JsonNode idx : indices) {
|
||||
String name = idx.path("index").asText("");
|
||||
if (!name.startsWith(indexPrefix)) {
|
||||
continue;
|
||||
}
|
||||
if (!search.isEmpty() && !name.contains(search)) {
|
||||
continue;
|
||||
}
|
||||
@@ -146,6 +152,9 @@ public class OpenSearchAdminController {
|
||||
@Operation(summary = "Delete an OpenSearch index")
|
||||
public ResponseEntity<Void> deleteIndex(@PathVariable String name, HttpServletRequest request) {
|
||||
try {
|
||||
if (!name.startsWith(indexPrefix)) {
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Cannot delete index outside application scope");
|
||||
}
|
||||
boolean exists = client.indices().exists(r -> r.index(name)).value();
|
||||
if (!exists) {
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Index not found: " + name);
|
||||
|
||||
Reference in New Issue
Block a user