taurusdb-core 0.5.0-rc.10 → 0.5.0-rc.3
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.
- package/dist/auth/sql-profile-loader/env-source.js +20 -6
- package/dist/auth/sql-profile-loader/parsing.js +9 -3
- package/dist/auth/sql-profile-loader/types.d.ts +3 -1
- package/dist/config/env.js +0 -1
- package/dist/config/schema.d.ts +0 -5
- package/dist/config/schema.js +2 -3
- package/dist/engine.d.ts +1 -3
- package/dist/engine.js +1 -4
- package/dist/executor/connection-pool.js +8 -7
- package/dist/utils/formatter.d.ts +0 -5
- package/dist/utils/formatter.js +0 -5
- package/package.json +1 -1
|
@@ -12,8 +12,7 @@ export function parseEngineFromDsnProtocol(protocol) {
|
|
|
12
12
|
export function parseEnvProfile(env) {
|
|
13
13
|
const dsn = asString(env.TAURUSDB_SQL_DSN);
|
|
14
14
|
const explicitHost = asString(env.TAURUSDB_SQL_HOST);
|
|
15
|
-
const
|
|
16
|
-
const profileName = explicitProfileName ?? "taurus_mcp";
|
|
15
|
+
const profileName = asString(env.TAURUSDB_SQL_DATASOURCE) ?? "taurus_mcp";
|
|
17
16
|
let engine;
|
|
18
17
|
let host;
|
|
19
18
|
let port;
|
|
@@ -41,7 +40,6 @@ export function parseEnvProfile(env) {
|
|
|
41
40
|
}
|
|
42
41
|
if (!dsn &&
|
|
43
42
|
!explicitHost &&
|
|
44
|
-
!explicitProfileName &&
|
|
45
43
|
!asString(env.TAURUSDB_SQL_USER) &&
|
|
46
44
|
!asString(env.TAURUSDB_SQL_PASSWORD) &&
|
|
47
45
|
!database) {
|
|
@@ -51,13 +49,23 @@ export function parseEnvProfile(env) {
|
|
|
51
49
|
throw new Error("Failed to resolve SQL port from environment.");
|
|
52
50
|
}
|
|
53
51
|
username = username ?? asString(env.TAURUSDB_SQL_USER);
|
|
52
|
+
if (!username) {
|
|
53
|
+
throw new Error("Missing SQL username in environment. Set TAURUSDB_SQL_USER or include it in DSN.");
|
|
54
|
+
}
|
|
54
55
|
passwordRef =
|
|
55
56
|
passwordRef ??
|
|
56
57
|
(Object.hasOwn(env, "TAURUSDB_SQL_PASSWORD")
|
|
57
58
|
? parseCredentialRef(env.TAURUSDB_SQL_PASSWORD, "TAURUSDB_SQL_PASSWORD")
|
|
58
59
|
: undefined);
|
|
59
|
-
if (
|
|
60
|
-
throw new Error("SQL
|
|
60
|
+
if (!passwordRef) {
|
|
61
|
+
throw new Error("Missing SQL password in environment. Set TAURUSDB_SQL_PASSWORD or include it in DSN.");
|
|
62
|
+
}
|
|
63
|
+
const mutationUsername = asString(env.TAURUSDB_SQL_MUTATION_USER);
|
|
64
|
+
const mutationPasswordRef = Object.hasOwn(env, "TAURUSDB_SQL_MUTATION_PASSWORD")
|
|
65
|
+
? parseCredentialRef(env.TAURUSDB_SQL_MUTATION_PASSWORD, "TAURUSDB_SQL_MUTATION_PASSWORD")
|
|
66
|
+
: undefined;
|
|
67
|
+
if ((mutationUsername && !mutationPasswordRef) || (!mutationUsername && mutationPasswordRef)) {
|
|
68
|
+
throw new Error("Mutation credentials require both TAURUSDB_SQL_MUTATION_USER and TAURUSDB_SQL_MUTATION_PASSWORD.");
|
|
61
69
|
}
|
|
62
70
|
const poolSize = asInteger(env.TAURUSDB_SQL_POOL_SIZE);
|
|
63
71
|
if (poolSize !== undefined && poolSize <= 0) {
|
|
@@ -69,7 +77,13 @@ export function parseEnvProfile(env) {
|
|
|
69
77
|
host,
|
|
70
78
|
port,
|
|
71
79
|
database,
|
|
72
|
-
user:
|
|
80
|
+
user: {
|
|
81
|
+
username,
|
|
82
|
+
password: passwordRef,
|
|
83
|
+
},
|
|
84
|
+
mutationUser: mutationUsername && mutationPasswordRef
|
|
85
|
+
? { username: mutationUsername, password: mutationPasswordRef }
|
|
86
|
+
: undefined,
|
|
73
87
|
poolSize,
|
|
74
88
|
});
|
|
75
89
|
}
|
|
@@ -196,14 +196,19 @@ export function parseProfileRecord(name, value, context) {
|
|
|
196
196
|
if (poolSize !== undefined && poolSize <= 0) {
|
|
197
197
|
throw new Error(`Invalid datasource profile ${name} in ${context}: poolSize must be positive.`);
|
|
198
198
|
}
|
|
199
|
-
// `user` is the
|
|
199
|
+
// `user` is the read-only credential. Keep older read-only aliases for compatibility.
|
|
200
200
|
const userRaw = value.user ??
|
|
201
201
|
value.readonlyUser ??
|
|
202
202
|
value.readonly ??
|
|
203
203
|
value.readOnlyUser;
|
|
204
|
-
|
|
204
|
+
if (userRaw === undefined) {
|
|
205
|
+
throw new Error(`Invalid datasource profile ${name} in ${context}: missing user.`);
|
|
206
|
+
}
|
|
207
|
+
const user = parseUserCredential(userRaw, `${context}.${name}.user`);
|
|
208
|
+
const mutationUserRaw = value.mutationUser ?? value.writeUser ?? value.rwUser;
|
|
209
|
+
const mutationUser = mutationUserRaw === undefined
|
|
205
210
|
? undefined
|
|
206
|
-
: parseUserCredential(
|
|
211
|
+
: parseUserCredential(mutationUserRaw, `${context}.${name}.mutationUser`);
|
|
207
212
|
const tls = parseTlsOptions(value.tls, `${context}.${name}.tls`);
|
|
208
213
|
return withRedactedToString({
|
|
209
214
|
name,
|
|
@@ -214,6 +219,7 @@ export function parseProfileRecord(name, value, context) {
|
|
|
214
219
|
instanceId,
|
|
215
220
|
nodeId,
|
|
216
221
|
user,
|
|
222
|
+
mutationUser,
|
|
217
223
|
tls,
|
|
218
224
|
poolSize,
|
|
219
225
|
});
|
|
@@ -33,8 +33,10 @@ export interface DataSourceProfile {
|
|
|
33
33
|
database?: string;
|
|
34
34
|
instanceId?: string;
|
|
35
35
|
nodeId?: string;
|
|
36
|
-
/**
|
|
36
|
+
/** Read-only credential used by discovery, diagnostics, and query tools. */
|
|
37
37
|
user?: UserCredential;
|
|
38
|
+
/** Separate credential required for mutation tools. No fallback is allowed. */
|
|
39
|
+
mutationUser?: UserCredential;
|
|
38
40
|
tls?: TlsOptions;
|
|
39
41
|
poolSize?: number;
|
|
40
42
|
toString(): string;
|
package/dist/config/env.js
CHANGED
|
@@ -161,7 +161,6 @@ export function buildRawConfigFromEnv(env) {
|
|
|
161
161
|
},
|
|
162
162
|
security: {
|
|
163
163
|
dynamicTargetsEnabled: parseBoolean(env.TAURUSDB_ENABLE_DYNAMIC_TARGETS, "TAURUSDB_ENABLE_DYNAMIC_TARGETS"),
|
|
164
|
-
recycleBinRestoreEnabled: parseBoolean(env.TAURUSDB_ENABLE_RECYCLE_BIN_RESTORE, "TAURUSDB_ENABLE_RECYCLE_BIN_RESTORE"),
|
|
165
164
|
requireTls: parseBoolean(env.TAURUSDB_REQUIRE_TLS, "TAURUSDB_REQUIRE_TLS"),
|
|
166
165
|
approvalSecretPath: expandTildePath(readString(env.TAURUSDB_MUTATION_APPROVAL_SECRET_FILE)),
|
|
167
166
|
approvalTtlSeconds: parseInteger(env.TAURUSDB_MUTATION_APPROVAL_TTL_SECONDS, "TAURUSDB_MUTATION_APPROVAL_TTL_SECONDS"),
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -106,7 +106,6 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
106
106
|
}>>;
|
|
107
107
|
security: z.ZodDefault<z.ZodObject<{
|
|
108
108
|
dynamicTargetsEnabled: z.ZodDefault<z.ZodBoolean>;
|
|
109
|
-
recycleBinRestoreEnabled: z.ZodDefault<z.ZodBoolean>;
|
|
110
109
|
requireTls: z.ZodDefault<z.ZodBoolean>;
|
|
111
110
|
approvalSecretPath: z.ZodOptional<z.ZodString>;
|
|
112
111
|
approvalTtlSeconds: z.ZodDefault<z.ZodNumber>;
|
|
@@ -114,7 +113,6 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
114
113
|
credentialMaxTtlMinutes: z.ZodDefault<z.ZodNumber>;
|
|
115
114
|
}, "strip", z.ZodTypeAny, {
|
|
116
115
|
dynamicTargetsEnabled: boolean;
|
|
117
|
-
recycleBinRestoreEnabled: boolean;
|
|
118
116
|
requireTls: boolean;
|
|
119
117
|
approvalTtlSeconds: number;
|
|
120
118
|
credentialIdleTtlMinutes: number;
|
|
@@ -122,7 +120,6 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
122
120
|
approvalSecretPath?: string | undefined;
|
|
123
121
|
}, {
|
|
124
122
|
dynamicTargetsEnabled?: boolean | undefined;
|
|
125
|
-
recycleBinRestoreEnabled?: boolean | undefined;
|
|
126
123
|
requireTls?: boolean | undefined;
|
|
127
124
|
approvalSecretPath?: string | undefined;
|
|
128
125
|
approvalTtlSeconds?: number | undefined;
|
|
@@ -365,7 +362,6 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
365
362
|
};
|
|
366
363
|
security: {
|
|
367
364
|
dynamicTargetsEnabled: boolean;
|
|
368
|
-
recycleBinRestoreEnabled: boolean;
|
|
369
365
|
requireTls: boolean;
|
|
370
366
|
approvalTtlSeconds: number;
|
|
371
367
|
credentialIdleTtlMinutes: number;
|
|
@@ -458,7 +454,6 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
458
454
|
} | undefined;
|
|
459
455
|
security?: {
|
|
460
456
|
dynamicTargetsEnabled?: boolean | undefined;
|
|
461
|
-
recycleBinRestoreEnabled?: boolean | undefined;
|
|
462
457
|
requireTls?: boolean | undefined;
|
|
463
458
|
approvalSecretPath?: string | undefined;
|
|
464
459
|
approvalTtlSeconds?: number | undefined;
|
package/dist/config/schema.js
CHANGED
|
@@ -22,9 +22,8 @@ const AuditSchema = z
|
|
|
22
22
|
.default({});
|
|
23
23
|
const SecuritySchema = z
|
|
24
24
|
.object({
|
|
25
|
-
dynamicTargetsEnabled: z.boolean().default(
|
|
26
|
-
|
|
27
|
-
requireTls: z.boolean().default(false),
|
|
25
|
+
dynamicTargetsEnabled: z.boolean().default(false),
|
|
26
|
+
requireTls: z.boolean().default(true),
|
|
28
27
|
approvalSecretPath: z.string().min(1).optional(),
|
|
29
28
|
approvalTtlSeconds: z.number().int().positive().max(3600).default(300),
|
|
30
29
|
credentialIdleTtlMinutes: z.number().int().positive().max(30).default(30),
|
package/dist/engine.d.ts
CHANGED
|
@@ -5,12 +5,11 @@ import type { CapabilitySnapshot, FeatureMatrix, KernelInfo } from "./capability
|
|
|
5
5
|
import { type Config } from "./config/index.js";
|
|
6
6
|
import type { DatasourceResolveInput, DatasourceResolver, SessionContext } from "./context/session-context.js";
|
|
7
7
|
import { type ConnectionPool } from "./executor/connection-pool.js";
|
|
8
|
-
import { type CancelResult, type ExplainResult, type
|
|
8
|
+
import { type CancelResult, type ExplainResult, type QueryResult, type QueryStatus, type ReadonlyOptions, type SqlExecutor } from "./executor/sql-executor.js";
|
|
9
9
|
import { type ConfirmationStore, type ConfirmationRequest, type ConfirmationValidationResult } from "./safety/confirmation-store.js";
|
|
10
10
|
import { type Guardrail, type GuardrailDecision, type InspectInput } from "./safety/guardrail.js";
|
|
11
11
|
import { type DatabaseInfo, type SchemaIntrospector, type TableInfo, type TableSchema } from "./schema/introspector.js";
|
|
12
12
|
import { type FlashbackInput } from "./taurus/flashback.js";
|
|
13
|
-
import type { RestoreRecycleBinTableInput } from "./taurus/recycle-bin.js";
|
|
14
13
|
import { type DbHotspotResult, type DiagnoseDbHotspotInput, type DiagnoseServiceLatencyInput, type FindTopSlowSqlInput, type FindTopSlowSqlResult, type DiagnoseConnectionSpikeInput, type DiagnoseLockContentionInput, type DiagnoseSlowQueryInput, type DiagnoseStoragePressureInput, type DiagnoseReplicationLagInput, type DiagnosticResult, type ServiceLatencyResult } from "./diagnostics/types.js";
|
|
15
14
|
import { type SlowSqlSource } from "./diagnostics/slow-sql-source.js";
|
|
16
15
|
import { type MetricsSource } from "./diagnostics/metrics-source.js";
|
|
@@ -67,7 +66,6 @@ export declare class TaurusDBEngine {
|
|
|
67
66
|
executeReadonly(sql: string, ctx: SessionContext, opts?: ReadonlyOptions): Promise<QueryResult>;
|
|
68
67
|
flashbackQuery(input: FlashbackInput, ctx: SessionContext, opts?: ReadonlyOptions): Promise<QueryResult>;
|
|
69
68
|
listRecycleBin(ctx: SessionContext, opts?: ReadonlyOptions): Promise<QueryResult>;
|
|
70
|
-
restoreRecycleBinTable(input: RestoreRecycleBinTableInput, ctx: SessionContext, opts?: MutationOptions): Promise<MutationResult>;
|
|
71
69
|
getQueryStatus(queryId: string): Promise<QueryStatus>;
|
|
72
70
|
cancelQuery(queryId: string): Promise<CancelResult>;
|
|
73
71
|
issueConfirmation(input: IssueConfirmationInput): Promise<ConfirmationRequest>;
|
package/dist/engine.js
CHANGED
|
@@ -18,7 +18,7 @@ import { createSlowSqlSource, } from "./diagnostics/slow-sql-source.js";
|
|
|
18
18
|
import { createMetricsSource, } from "./diagnostics/metrics-source.js";
|
|
19
19
|
import { findLatestDeadlock, findMetadataLockWaits, findStatementDigestCandidatesForSqlHints, findStatementDigestSample, findStatementDigestSampleForSql, findStatementWaitEvents, findStorageStatementDigests, findTableStorageStats, findTopStatementDigests, isPerformanceSchemaEnabled, showLockWaits, showProcesslist, } from "./engine/data-access.js";
|
|
20
20
|
import { diagnoseConnectionSpike, diagnoseDbHotspot, diagnoseLockContention, diagnoseServiceLatency, diagnoseSlowQuery, diagnoseStoragePressure, findTopSlowSql, } from "./engine/diagnostics.js";
|
|
21
|
-
import { cancelQuery, close, executeReadonly, explain, explainEnhanced, flashbackQuery, getQueryStatus, handleConfirmation, issueConfirmation, listRecycleBin,
|
|
21
|
+
import { cancelQuery, close, executeReadonly, explain, explainEnhanced, flashbackQuery, getQueryStatus, handleConfirmation, issueConfirmation, listRecycleBin, validateConfirmation, } from "./engine/runtime.js";
|
|
22
22
|
async function readMutationApprovalSecret(filePath) {
|
|
23
23
|
const info = await lstat(filePath);
|
|
24
24
|
if (!info.isFile() || info.isSymbolicLink()) {
|
|
@@ -251,9 +251,6 @@ export class TaurusDBEngine {
|
|
|
251
251
|
async listRecycleBin(ctx, opts) {
|
|
252
252
|
return listRecycleBin(this, ctx, opts);
|
|
253
253
|
}
|
|
254
|
-
async restoreRecycleBinTable(input, ctx, opts) {
|
|
255
|
-
return restoreRecycleBinTable(this, input, ctx, opts);
|
|
256
|
-
}
|
|
257
254
|
async getQueryStatus(queryId) {
|
|
258
255
|
return getQueryStatus(this, queryId);
|
|
259
256
|
}
|
|
@@ -20,12 +20,12 @@ async function resolveTls(tls, secretResolver, host, requireTls) {
|
|
|
20
20
|
if (requireTls && tls?.enabled === false) {
|
|
21
21
|
throw new ConnectionPoolError("TLS is required by server policy and cannot be disabled for this datasource.");
|
|
22
22
|
}
|
|
23
|
+
if (requireTls && tls?.rejectUnauthorized === false) {
|
|
24
|
+
throw new ConnectionPoolError("TLS certificate verification is required by server policy.");
|
|
25
|
+
}
|
|
23
26
|
const resolved = {
|
|
24
27
|
enabled: tls?.enabled ?? true,
|
|
25
|
-
|
|
26
|
-
// certificate is issued to a DNS name. When TLS is explicitly enabled,
|
|
27
|
-
// make CA/hostname verification a separate profile opt-in.
|
|
28
|
-
rejectUnauthorized: tls?.rejectUnauthorized ?? false,
|
|
28
|
+
rejectUnauthorized: tls?.rejectUnauthorized ?? true,
|
|
29
29
|
servername: tls?.servername ?? (isIP(host) === 0 ? host : undefined),
|
|
30
30
|
};
|
|
31
31
|
if (tls?.ca) {
|
|
@@ -39,10 +39,11 @@ async function resolveTls(tls, secretResolver, host, requireTls) {
|
|
|
39
39
|
}
|
|
40
40
|
return resolved;
|
|
41
41
|
}
|
|
42
|
-
function selectCredential(profile,
|
|
43
|
-
const credential = profile.user;
|
|
42
|
+
function selectCredential(profile, mode) {
|
|
43
|
+
const credential = mode === "rw" ? profile.mutationUser : profile.user;
|
|
44
44
|
if (!credential) {
|
|
45
|
-
|
|
45
|
+
const credentialKind = mode === "rw" ? "mutation" : "read-only";
|
|
46
|
+
throw new ConnectionPoolError(`Datasource "${profile.name}" does not define ${credentialKind} SQL credentials. Configure a dedicated ${credentialKind} database username and password reference.`);
|
|
46
47
|
}
|
|
47
48
|
return credential;
|
|
48
49
|
}
|
|
@@ -10,11 +10,6 @@ export declare const ErrorCode: {
|
|
|
10
10
|
readonly QUERY_TIMEOUT: "QUERY_TIMEOUT";
|
|
11
11
|
readonly QUERY_CANCELLED: "QUERY_CANCELLED";
|
|
12
12
|
readonly CONNECTION_FAILED: "CONNECTION_FAILED";
|
|
13
|
-
readonly DB_ENDPOINT_UNREACHABLE: "DB_ENDPOINT_UNREACHABLE";
|
|
14
|
-
readonly DB_CONNECTION_REFUSED: "DB_CONNECTION_REFUSED";
|
|
15
|
-
readonly DB_TLS_FAILED: "DB_TLS_FAILED";
|
|
16
|
-
readonly DB_AUTH_FAILED: "DB_AUTH_FAILED";
|
|
17
|
-
readonly DB_VALIDATION_TIMEOUT: "DB_VALIDATION_TIMEOUT";
|
|
18
13
|
readonly RESULT_TOO_LARGE: "RESULT_TOO_LARGE";
|
|
19
14
|
readonly AUDIT_FAILED: "AUDIT_FAILED";
|
|
20
15
|
readonly SERVER_BUSY: "SERVER_BUSY";
|
package/dist/utils/formatter.js
CHANGED
|
@@ -9,11 +9,6 @@ export const ErrorCode = {
|
|
|
9
9
|
QUERY_TIMEOUT: "QUERY_TIMEOUT",
|
|
10
10
|
QUERY_CANCELLED: "QUERY_CANCELLED",
|
|
11
11
|
CONNECTION_FAILED: "CONNECTION_FAILED",
|
|
12
|
-
DB_ENDPOINT_UNREACHABLE: "DB_ENDPOINT_UNREACHABLE",
|
|
13
|
-
DB_CONNECTION_REFUSED: "DB_CONNECTION_REFUSED",
|
|
14
|
-
DB_TLS_FAILED: "DB_TLS_FAILED",
|
|
15
|
-
DB_AUTH_FAILED: "DB_AUTH_FAILED",
|
|
16
|
-
DB_VALIDATION_TIMEOUT: "DB_VALIDATION_TIMEOUT",
|
|
17
12
|
RESULT_TOO_LARGE: "RESULT_TOO_LARGE",
|
|
18
13
|
AUDIT_FAILED: "AUDIT_FAILED",
|
|
19
14
|
SERVER_BUSY: "SERVER_BUSY",
|