mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 15:51:26 +00:00
feat: external databases — register, probe, encrypted credentials
Databases hosted outside Containr can now be registered alongside
managed ones. The connection is probed before storing (protocol-level
for postgres/redis-family via real drivers, TCP dial for the rest),
credentials are encrypted at rest and never returned, and external rows
skip managed lifecycle actions, backups, and Docker metrics.
- POST /databases/register-external — probe + create
- POST /databases/test-connection — ad-hoc probe (ok/latency_ms/error)
- POST /databases/{id}/test-connection — re-probe stored credentials
- provider/external fields on database services; privileged reads get a
composed connection URL with loopback hosts rewritten to the caller's
- CLI: databases register + test-connection; MCP: 3 new tools
- UI: managed/external toggle in the create modal, external badge and
host display, per-row test button, backups section hidden
- Migration widens the plan CHECK to admit 'external'
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
3664eaed1a
commit
5dc9b5f115
19 files changed
+1274
-48
No files matched your search
@@ -1733,6 +1733,39 @@ export async function createManagedDatabase(
|
||||
return { id: payload.id, status: payload.status ?? 'building' };
|
||||
}
|
||||
|
||||
export type ExternalDatabaseInput = {
|
||||
name?: string;
|
||||
type: string;
|
||||
host: string;
|
||||
port?: number;
|
||||
database?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
ssl?: boolean;
|
||||
};
|
||||
|
||||
export async function registerExternalDatabase(input: ExternalDatabaseInput): Promise<{ id: string }> {
|
||||
const payload = await requestJson<{ id?: string }>('/databases/register-external', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
if (!payload.id) {
|
||||
throw new ApiError('Database response is invalid', 500);
|
||||
}
|
||||
return { id: payload.id };
|
||||
}
|
||||
|
||||
export async function testDatabaseConnection(input: ExternalDatabaseInput): Promise<{ ok: boolean; latency_ms?: number; error?: string }> {
|
||||
return requestJson('/databases/test-connection', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
}
|
||||
|
||||
export async function testDatabaseConnectionByID(id: string): Promise<{ ok: boolean; latency_ms?: number; error?: string }> {
|
||||
return requestJson(`/databases/${encodeURIComponent(id)}/test-connection`, { method: 'POST' });
|
||||
}
|
||||
|
||||
export type ConnectGitRepositoryInput = components['schemas']['ConnectGitRepoRequest'];
|
||||
export type CreateGitWebhookInput = components['schemas']['CreateWebhookRequest'];
|
||||
export type GitWebhookEntity = components['schemas']['GitWebhook'];
|
||||
|
||||
Reference in new issue
Block a user