feat(seed): pre-configured database connections via YAML/JSON config#50
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d role-based access control
…SON configuration and role-based access control
Add managed/seedId fields to DatabaseConnection interface and create src/lib/seed/types.ts with SeedConnectionSchema, SeedConfigSchema, SeedDefaultsSchema validated by Zod v4 with 19 passing unit tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ts merge Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…and audit Add SeedConnectionError class with statusCode, resolveConnection utility that differentiates between 403 (role denied) and 404 (not found), and extend AuditEventType with 'managed_connection'. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements role-filtered managed connections API with password sanitization, cache hint header, and 401 guard. Fixes pre-existing SSLConfig type error in connection-filter.ts (optional ssl.mode cast to SSLConfig). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add seed connection support to all 13 DB API routes (query, multi-query, schema, transaction, cancel, maintenance, monitoring, pool-stats, profile, provider-meta, test-connection, schema-snapshot, health). Each route now calls getSession() + resolveConnection() to support both traditional connection objects and seed connectionId references. Added SeedConnectionError handling to the centralized createErrorResponse utility. Updated all corresponding test files with auth and seed resolution mocks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…merge Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ch calls Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nnections Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a “Seed Connections” system to the app so operators can pre-configure DB connections via a mounted YAML/JSON file, resolve credentials from ${ENV_VAR} server-side, filter by user role, and expose managed connections through a dedicated API endpoint—while updating client/server flows to use seed: connection IDs instead of sending secrets to the browser.
Changes:
- Introduces
src/lib/seed/module (schemas, config loader w/ TTL cache, env credential resolver, role filtering, andresolveConnection()). - Adds
GET /api/connections/managedand wiresresolveConnection()into multiple DB API routes for server-side credential resolution. - Updates client hooks/UI to support managed connections (send
connectionId, lock icon, merge managed + user connections) and adds Helm/Docker/env docs + extensive tests/fixtures.
Reviewed changes
Copilot reviewed 64 out of 65 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/seed/types.test.ts | Unit tests for Zod schemas (seed config/connection/defaults). |
| tests/unit/seed/resolve-connection.test.ts | Unit tests for resolveConnection() behavior (seed IDs, role gating, errors). |
| tests/unit/seed/index.test.ts | Unit tests for seed module orchestrator APIs. |
| tests/unit/seed/credential-resolver.test.ts | Unit tests for ${ENV_VAR} resolution and plaintext warnings. |
| tests/unit/seed/connection-filter.test.ts | Unit tests for defaults merge + role filtering + mapping to managed connections. |
| tests/unit/seed/config-loader.test.ts | Unit tests for YAML/JSON parsing, caching, and error handling. |
| tests/integration/seed/seed-pipeline.test.ts | Integration coverage of end-to-end seed pipeline behavior. |
| tests/fixtures/seed-connections/valid-config.yaml | Seed config fixture (YAML). |
| tests/fixtures/seed-connections/valid-config.json | Seed config fixture (JSON). |
| tests/fixtures/seed-connections/multi-role-config.yaml | Seed fixture to validate role filtering. |
| tests/fixtures/seed-connections/mixed-credentials.yaml | Seed fixture to validate partial credential resolution. |
| tests/fixtures/seed-connections/minimal-config.yaml | Minimal seed fixture for required fields. |
| tests/fixtures/seed-connections/invalid-config.yaml | Invalid seed fixture for schema rejection. |
| tests/api/seed/managed-route.test.ts | API tests for /api/connections/managed (auth, filtering, sanitization). |
| tests/api/db/transaction.test.ts | Updates DB route tests to accommodate seed resolution mocking. |
| tests/api/db/test-connection.test.ts | Updates DB route tests to accommodate seed resolution mocking. |
| tests/api/db/schema.test.ts | Updates DB route tests to accommodate seed resolution mocking. |
| tests/api/db/schema-snapshot.test.ts | Updates DB route tests to accommodate seed resolution mocking. |
| tests/api/db/query.test.ts | Updates DB route tests to accommodate seed resolution mocking. |
| tests/api/db/provider-meta.test.ts | Updates DB route tests to accommodate seed resolution mocking. |
| tests/api/db/profile.test.ts | Updates DB route tests to accommodate seed resolution mocking. |
| tests/api/db/pool-stats.test.ts | Updates DB route tests to accommodate seed resolution mocking. |
| tests/api/db/multi-query.test.ts | Updates DB route tests to accommodate seed resolution mocking. |
| tests/api/db/monitoring.test.ts | Updates DB route tests to accommodate seed resolution mocking. |
| tests/api/db/maintenance.test.ts | Updates DB route tests to accommodate seed resolution mocking. |
| tests/api/db/health.test.ts | Updates DB route tests to accommodate seed resolution mocking. |
| tests/api/db/cancel.test.ts | Updates DB route tests to accommodate seed resolution mocking. |
| src/lib/types.ts | Adds managed + seedId to DatabaseConnection. |
| src/lib/seed/types.ts | Defines seed schemas/types + ManagedConnection. |
| src/lib/seed/resolve-connection.ts | Implements server-side resolution of seed: connection IDs with role checks. |
| src/lib/seed/index.ts | Public seed module API for listing/lookup of managed connections. |
| src/lib/seed/credential-resolver.ts | Resolves ${ENV_VAR} credentials; logs plaintext password warnings. |
| src/lib/seed/connection-filter.ts | Applies defaults + role filtering and maps seed -> managed connection objects. |
| src/lib/seed/config-loader.ts | Loads YAML/JSON seed config from disk with TTL caching. |
| src/lib/audit.ts | Adds new audit event type for managed connections. |
| src/lib/api/errors.ts | Adds API error mapping for SeedConnectionError. |
| src/hooks/use-transaction-control.ts | Sends connection payload via connectionId for managed connections. |
| src/hooks/use-query-execution.ts | Sends connection payload via connectionId for managed connections across fetch sites. |
| src/hooks/use-connection-payload.ts | Centralizes {connection} vs {connectionId} request body construction. |
| src/hooks/use-connection-manager.ts | Fetches/merges managed connections into client connection list; updates schema/health calls. |
| src/components/sidebar/ConnectionItem.tsx | Shows lock icon + hides edit/delete for managed connections. |
| src/app/api/db/transaction/route.ts | Uses session + resolveConnection(); supports seed connection IDs. |
| src/app/api/db/test-connection/route.ts | Uses session + resolveConnection(); supports multiple request body shapes. |
| src/app/api/db/schema/route.ts | Switches to JSON parsing + session + resolveConnection(). |
| src/app/api/db/schema-snapshot/route.ts | Uses session + resolveConnection(). |
| src/app/api/db/query/route.ts | Uses session + resolveConnection(). |
| src/app/api/db/provider-meta/route.ts | Uses session + resolveConnection(). |
| src/app/api/db/profile/route.ts | Uses session + resolveConnection(). |
| src/app/api/db/pool-stats/route.ts | Uses session + resolveConnection(). |
| src/app/api/db/multi-query/route.ts | Uses session + resolveConnection(). |
| src/app/api/db/monitoring/route.ts | Uses session + resolveConnection(). |
| src/app/api/db/maintenance/route.ts | Resolves seed connections under existing admin session check. |
| src/app/api/db/health/route.ts | Uses session + resolveConnection() for connection-level health check. |
| src/app/api/db/cancel/route.ts | Uses session + resolveConnection(). |
| src/app/api/connections/managed/route.ts | New endpoint to return role-filtered managed connections with sanitization. |
| package.json | Adds yaml dependency for YAML parsing. |
| docs/superpowers/specs/2026-03-25-seed-connections-design.md | Design spec for seed connections feature. |
| docs/superpowers/plans/2026-03-25-seed-connections.md | Implementation plan for the feature. |
| docker-compose.yml | Documents seed config volume mount and env usage. |
| charts/libredb-studio/values.yaml | Adds seedConnections Helm values. |
| charts/libredb-studio/values.schema.json | Adds schema for seedConnections values. |
| charts/libredb-studio/templates/seed-configmap.yaml | Adds ConfigMap template for inline seed config. |
| charts/libredb-studio/templates/deployment.yaml | Adds volume mount + env vars for seed config. |
| bun.lock | Locks yaml dependency. |
| .env.example | Documents SEED_CONFIG_PATH and SEED_CACHE_TTL_MS. |
Comments suppressed due to low confidence (4)
src/app/api/db/multi-query/route.ts:36
- The validation checks
if (!sql)but the error message says “Connection and query are required”. Since connection is already resolved/validated earlier, this message is now misleading. Consider updating it to only mention the missing field (e.g., “SQL is required”).
if (!sql) {
return NextResponse.json(
{ error: 'Connection and query are required' },
{ status: 400 }
);
src/app/api/db/cancel/route.ts:23
- The validation checks
if (!queryId)but the error message says “Connection and queryId are required”. Since connection is already resolved/validated earlier, this message is now misleading. Consider updating it to only mention the missing field (e.g., “queryId is required”).
if (!queryId) {
return NextResponse.json(
{ error: 'Connection and queryId are required' },
{ status: 400 }
);
src/app/api/db/query/route.ts:23
- The validation checks
if (!sql)but the error message says “Connection and query are required”. Since connection is already resolved/validated earlier (and missing-connection cases will throw a different error), this message is now misleading. Consider updating it to only mention the missing field (e.g., “SQL query is required”).
if (!sql) {
return NextResponse.json(
{ error: 'Connection and query are required' },
{ status: 400 }
);
src/app/api/db/transaction/route.ts:41
- The validation checks
if (!action)but the error message says “Connection and action are required”. Since connection is already resolved/validated earlier, this message is now misleading. Consider updating it to only mention the missing field (e.g., “action is required”).
if (!action) {
return NextResponse.json(
{ error: 'Connection and action are required' },
{ status: 400 }
);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return conn; | ||
| }); | ||
|
|
||
| const cacheTTL = Number(process.env.SEED_CACHE_TTL_MS) || 60_000; |
There was a problem hiding this comment.
cacheTTL uses Number(process.env.SEED_CACHE_TTL_MS) || 60_000, so setting SEED_CACHE_TTL_MS=0 won’t be reflected in cacheHint (it will report 60000). Consider aligning this with the loader’s TTL parsing via an explicit Number.isFinite() check (and optionally allow 0 to mean “no caching”).
| const cacheTTL = Number(process.env.SEED_CACHE_TTL_MS) || 60_000; | |
| const rawCacheTTL = Number(process.env.SEED_CACHE_TTL_MS); | |
| const cacheTTL = Number.isFinite(rawCacheTTL) ? rawCacheTTL : 60_000; |
| return NextResponse.json( | ||
| { error: error.message, code: ApiErrorCode.CONFIG_ERROR, statusCode: error.statusCode }, | ||
| { status: error.statusCode } | ||
| ); |
There was a problem hiding this comment.
SeedConnectionError is mapped to ApiErrorCode.CONFIG_ERROR for all statuses, including 403/404. That makes client-side error handling ambiguous (403 is auth/authorization, 404 is missing resource). Consider setting the code based on error.statusCode (e.g., AUTH_ERROR for 401/403, keep CONFIG_ERROR for 400), and potentially omit code for 404 if there’s no matching enum value.
| return NextResponse.json( | |
| { error: error.message, code: ApiErrorCode.CONFIG_ERROR, statusCode: error.statusCode }, | |
| { status: error.statusCode } | |
| ); | |
| let code: ApiErrorCode | undefined; | |
| switch (error.statusCode) { | |
| case 400: | |
| code = ApiErrorCode.CONFIG_ERROR; | |
| break; | |
| case 401: | |
| case 403: | |
| code = ApiErrorCode.AUTH_ERROR; | |
| break; | |
| case 404: | |
| code = undefined; | |
| break; | |
| default: | |
| code = ApiErrorCode.CONFIG_ERROR; | |
| break; | |
| } | |
| const body: ApiErrorResponse = { | |
| error: error.message, | |
| statusCode: error.statusCode, | |
| ...(code ? { code } : {}), | |
| }; | |
| return NextResponse.json(body, { status: error.statusCode }); |
| const FIXTURES = path.resolve(__dirname, '../../fixtures/seed-connections'); | ||
| process.env.SEED_CONFIG_PATH = path.join(FIXTURES, 'multi-role-config.yaml'); | ||
| process.env.ADMIN_PG_PASS = 'admin-secret'; | ||
| process.env.USER_MYSQL_PASS = 'user-secret'; | ||
| process.env.SHARED_PG_PASS = 'shared-secret'; | ||
| process.env.BOTH_PG_PASS = 'both-secret'; | ||
|
|
There was a problem hiding this comment.
This test sets process.env.SEED_CONFIG_PATH and credential env vars at module load time and never restores them. That can leak state into other tests and cause order-dependent failures. Prefer moving these env assignments into beforeEach (or beforeAll) and cleaning them up in afterEach/afterAll.
| const FIXTURES = path.resolve(__dirname, '../../fixtures/seed-connections'); | ||
| process.env.SEED_CONFIG_PATH = path.join(FIXTURES, 'multi-role-config.yaml'); | ||
| process.env.ADMIN_PG_PASS = 'admin-secret'; | ||
| process.env.USER_MYSQL_PASS = 'user-secret'; | ||
| process.env.SHARED_PG_PASS = 'shared-secret'; | ||
| process.env.BOTH_PG_PASS = 'both-secret'; | ||
|
|
||
| import { resolveConnection, SeedConnectionError } from '@/lib/seed/resolve-connection'; |
There was a problem hiding this comment.
This test sets process.env.SEED_CONFIG_PATH and credential env vars at module load time and doesn’t clean them up. That can leak state across test files (especially when the runner reuses the same process). Prefer setting env vars in beforeEach/beforeAll and deleting/restoring them in afterEach/afterAll.
| import { loadConfig, resetCache } from './config-loader'; | ||
| import { resolveAllCredentials } from './credential-resolver'; |
There was a problem hiding this comment.
resetCache is imported but never used (the file already re-exports it via export { resetCache } from './config-loader'). This will trip lint rules in many setups; please remove the unused import from line 1.
| function getCacheTTL(): number { | ||
| return Number(process.env.SEED_CACHE_TTL_MS) || 60_000; | ||
| } |
There was a problem hiding this comment.
getCacheTTL() uses Number(process.env.SEED_CACHE_TTL_MS) || 60_000, which treats a configured value of 0 as falsy and silently falls back to 60s. If you want to allow 0 (disable caching) or reject non-numeric values explicitly, switch to a NaN check (e.g., const ttl = Number(...); return Number.isFinite(ttl) ? ttl : 60_000;) and optionally clamp negative values.
| const connection = await resolveConnection(body, session); | ||
|
|
||
| if (!tableName) { | ||
| return NextResponse.json({ error: 'Connection and tableName required' }, { status: 400 }); |
There was a problem hiding this comment.
The validation checks if (!tableName) but the error message says “Connection and tableName required”. Since connection is already resolved/validated earlier, this message is now misleading. Consider updating it to only mention the missing field (e.g., “tableName is required”).
| return NextResponse.json({ error: 'Connection and tableName required' }, { status: 400 }); | |
| return NextResponse.json({ error: 'tableName is required' }, { status: 400 }); |
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove demo type checks, isDemo flags, showcase-queries imports, and the demo-connection fetch block from all source files. Source files now have 0 typecheck errors related to demo removal. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove all demo connection references from test fixtures, hook tests, API tests, component tests, and configuration files. Replace /api/demo-connection mock intercepts with clean fetch mocks, drop isDemo/type:'demo' from mock objects, and remove the Helm demo: section, configmap DEMO_MODE block, schema demo property, DEMO_DB_* env vars from CI and playwright config. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace 'demo' type with 'sqlite' in factory cache tests - Update DEFAULT_TAB query to empty string (demo showcase removed) - Remove DemoProvider mock from 6 test files
Add beforeEach/afterEach to always restore JWT_SECRET, and use try/finally in the "throws when not set" test to prevent leaked state on failure. Fixes flaky encryptState/decryptState failures in CI coverage mode.
…ation
auth.test.ts was using mock.module('jose') which is process-wide in bun.
When CI ran auth.test.ts before oidc.test.ts in the same process,
the jose mock replaced real SignJWT/jwtVerify, causing encryptState/
decryptState tests to fail.
Fix: Remove jose mock from auth.test.ts, use real JWT sign/verify
with JWT_SECRET from test setup. Only next/headers (cookies) remains
mocked. This eliminates the process-wide contamination.
- Add managed:false credential pass-through test (covers line 21-22) - Add invalid config 500 error test (covers line 28-32) - Add 401 no-session test for POST /api/db/health (covers line 30) - Add 400 missing-type test for POST /api/db/health (covers line 36-39)
- logout/route.ts: add error-path tests that trigger the catch block (lines 22-23) by making logout() throw both synchronously and asynchronously, verifying createErrorResponse returns HTTP 500 - db/factory.ts: add targeted tests for previously uncovered branches: - getOrCreateProvider connect-failure path (no tunnel) hits line 218 - SSH tunnel cleanup when connect fails (lines 220-222) - removeProvider disconnect-error gracefully caught (line 244) - removeProvider closeSSHTunnel-error gracefully caught (line 253) - clearProviderCache disconnect-error via .catch callback (line 272) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- config.test.ts: Introduced controllable mock for getStorageConfig to simulate different storage configurations and added a test for error handling, ensuring a 500 response on config read failures. - storage-routes.test.ts: Added tests for missing data field in PUT requests, returning a 400 status, and for handling errors when provider.setCollection fails, returning a 500 status. - factory.test.ts: Added tests for getStorageProvider and closeStorageProvider functions, ensuring correct behavior for local paths and proper cleanup. - sqlite.test.ts: Expanded tests for SQLite provider, verifying singleton behavior and proper closure of the provider.
Reverts coverage test additions that caused test:coverage:core to hang in CI. The SQLite factory singleton tests and db factory connect-failure tests manipulated module-level state that caused deadlocks in coverage mode. Coverage improvements will be done in a separate PR.
- Add comprehensive Seed Connections section with config format, Docker/docker-compose/Helm examples, and full config reference table - Add SEED_CONFIG_PATH and SEED_CACHE_TTL_MS to Environment Variables - Remove DEMO_DB_* env vars from Koyeb deploy button URL - Update Live Test section to reference seed connections - Add seed-connections.yaml to .gitignore
…nents Components were calling storage.getConnections() directly, which only returns localStorage user connections — missing managed seed connections. - Add useAllConnections() hook: merges user + managed connections - Update MonitoringDashboard, OverviewTab, OperationsTab, SchemaDiff to use useAllConnections() instead of storage.getConnections() - Update Studio.tsx delete/save handlers to preserve managed connections - Fix: seed connections now appear in Monitoring, Admin, and Schema Diff
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 123 out of 125 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
src/app/api/db/transaction/route.ts:41
- This 400 response is returned when
actionis missing, but by this point the connection has already been resolved/validated (and missing connections would have thrown earlier). The error message "Connection and action are required" is now misleading—consider changing it to only mention the missingaction(or validateactionbefore callingresolveConnection).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const res = await fetch('/api/admin/fleet-health', { | ||
| method: 'POST', | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| body: JSON.stringify({ connections: nonDemo }), | ||
| body: JSON.stringify({ connections }), | ||
| }); |
There was a problem hiding this comment.
connections may include managed: true seed connections (password/connectionString stripped on the client). /api/admin/fleet-health currently calls getOrCreateProvider(conn) directly and will fail for these because credentials are missing. Consider sending { connectionId: "seed:..." } for managed connections (or splitting managed vs unmanaged payloads) and updating the fleet-health route to resolve seed credentials server-side before creating providers; alternatively filter managed connections out here if fleet-health can’t support them yet.
| // Load connections (user + managed seed connections) | ||
| const { connections: allConns } = useAllConnections(); | ||
| useEffect(() => { | ||
| const loadedConnections = storage.getConnections(); | ||
| setConnections(loadedConnections); | ||
| if (allConns.length === 0) return; | ||
| setConnections(allConns); |
There was a problem hiding this comment.
useAllConnections() now includes managed: true seed connections (credentials stripped), but useMonitoringData() still posts the full connection object to monitoring/maintenance endpoints. Selecting a managed connection will likely break monitoring actions because the server won’t receive credentials unless you send a connectionId and resolve it server-side. Recommend updating the monitoring requests to use the same managed-connection payload pattern as query/transaction (e.g., build a {connectionId} payload when conn.managed && conn.seedId).
| } = useMonitoringData(selectedConnection, monitoringOptions); | ||
|
|
||
| const { connections: allConns } = useAllConnections(); | ||
| useEffect(() => { | ||
| const loadedConnections = storage.getConnections(); | ||
| setConnections(loadedConnections); | ||
| if (loadedConnections.length > 0) { | ||
| const savedId = storage.getActiveConnectionId(); | ||
| const saved = savedId ? loadedConnections.find((c) => c.id === savedId) : null; | ||
| setSelectedConnection(saved ?? loadedConnections[0]); | ||
| } | ||
| }, []); | ||
| if (allConns.length === 0) return; |
There was a problem hiding this comment.
Same managed-connection issue as MonitoringDashboard: this tab allows selecting connections from useAllConnections() (including managed seed connections without credentials), but useMonitoringData() currently sends connection: currentConnection in its requests. That will fail for managed connections unless the payload uses connectionId and the server resolves it. Please align monitoring/maintenance calls with the new seed connection resolution flow.
| // Get all connections for cross-connection comparison | ||
| const allConnections = useMemo(() => storage.getConnections(), []); | ||
| const { connections: allConnections } = useAllConnections(); | ||
| const [fetchingRemote, setFetchingRemote] = useState(false); | ||
|
|
||
| // Fetch schema from a remote connection |
There was a problem hiding this comment.
useAllConnections() can include managed: true seed connections (credentials stripped). Downstream, fetchRemoteSchema() posts a connection object to /api/db/schema-snapshot; for managed connections this will fail because the server won’t receive credentials and no connectionId is provided for seed resolution. Consider filtering managed connections out of the “Fetch from connection” list, or switch the request payload to send connectionId for managed connections and update the schema-snapshot route to resolve it server-side.
Critical fixes: - Use buildConnectionPayload() in useMonitoringData (3 fetch sites) - Use connectionId for managed connections in SchemaDiff fetchRemoteSchema - Resolve seed credentials server-side in fleet-health route Improvements: - Map SeedConnectionError 403→AUTH_ERROR instead of CONFIG_ERROR - Use Number.isFinite() for SEED_CACHE_TTL_MS (allow 0 value) - Remove unused resetCache import from seed/index.ts - Fix misleading error message in profile route
|



Summary
src/lib/seed/) — YAML/JSON config file loading with TTL cache,${ENV_VAR}credential injection, role-based filtering (admin,user,*wildcard), and hybrid managed/unmanaged connection modelGET /api/connections/managed— returns role-filtered connections with credential stripping for managed connectionsresolveConnection()utility for server-side credential resolution viaseed:prefixed connection IDsconnectionIdinstead of full credentials for managed connections (7 fetch sites acrossuseQueryExecution,useTransactionControl,useConnectionManager)How It Works
/app/config/seed-connections.yamlroles(whitelist) andmanagedflag (read-only vs editable copy)${ENV_VAR}syntax — resolved server-side from K8s Secrets or env varsmanaged: trueconnections never expose passwords to the clientConfig Example
Test plan
🤖 Generated with Claude Code