dsh-sql 0.5.4 → 0.5.5
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/CHANGELOG.md +4 -0
- package/docs/USAGE.en.md +4 -0
- package/docs/USAGE.md +4 -0
- package/docs/VALIDATION.md +4 -0
- package/docs/validation-0.5.5.md +7 -0
- package/lib/approval.d.ts +13 -0
- package/lib/approval.js +18 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.js +11 -1
- package/lib/tools.d.ts +1 -1
- package/lib/tools.js +10 -4
- package/lib/update-client.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
[返回简介](README.md) · [使用说明](docs/USAGE.md) · [验证记录](docs/VALIDATION.md)
|
|
4
4
|
|
|
5
|
+
## 0.5.5 (2026-10-28)
|
|
6
|
+
|
|
7
|
+
- 写入确认与健康检查正确读取会话审批策略。never 或未知策略明确说明操作未执行及恢复方式;保留宿主拒绝、只读限制与完整 SQL 审批摘要。
|
|
8
|
+
|
|
5
9
|
## 0.5.4 (2026-10-28)
|
|
6
10
|
|
|
7
11
|
- 修复 PostgreSQL 查询能修改会话默认设置,再通过写函数绕过只读保护的问题。每次查询强制使用独立只读事务并回滚;允许审批写入时查询工具仍保持只读。
|
package/docs/USAGE.en.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# dsh-sql usage guide
|
|
2
2
|
|
|
3
|
+
## Confirmation in Full Access
|
|
4
|
+
|
|
5
|
+
The plugin keeps its confirmation requirement. With approval policy `never`, it reports that confirmation is unavailable and performs no write. Switch to a mode that can ask, or explicitly set `writeApproval: false` yourself. Host denials still apply.
|
|
6
|
+
|
|
3
7
|
[Overview](../README.en.md) · [Changelog](../CHANGELOG.md) · [Validation](VALIDATION.md)
|
|
4
8
|
|
|
5
9
|
## Current improvements
|
package/docs/USAGE.md
CHANGED
package/docs/VALIDATION.md
CHANGED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# 0.5.5 验证记录(2026-10-28)
|
|
2
|
+
|
|
3
|
+
Windows 74 项回归:73 通过、1 项真实 PostgreSQL 因本轮未配置服务而跳过。数据库适配器和只读事务代码本轮未改动;不以此冒充本轮真实 MySQL/PostgreSQL 验收。
|
|
4
|
+
|
|
5
|
+
官方 DSH 0.2.1-rc.4 的真实 agent 回合调用 sql_exec:策略 never 返回插件的明确原因,未请求无效确认,也没有声称用户点了拒绝。原生 SQLite 查询通过;sql_health 将连接正常与写确认可用分开,never 时整体检查不误报正常。
|
|
6
|
+
|
|
7
|
+
回归覆盖可询问策略、未知服务、保留宿主拒绝、只读配置、显式关闭审批和完整 SQL 摘要。未自动放宽任何写入保护;Electron 原生窗口未验收。
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Read the effective Host policy without importing a second copy of its services. */
|
|
2
|
+
export type ApprovalPolicy = 'ask' | 'never' | 'unknown';
|
|
3
|
+
export interface ApprovalContext {
|
|
4
|
+
get?(name: string): unknown;
|
|
5
|
+
approval?: {
|
|
6
|
+
config?: {
|
|
7
|
+
policy?: unknown;
|
|
8
|
+
};
|
|
9
|
+
overrideOf?(session: unknown): unknown;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export declare function approvalPolicy(ctx: ApprovalContext, execution: unknown): ApprovalPolicy;
|
|
13
|
+
export declare function approvalProblem(policy: ApprovalPolicy, setting: string): string | undefined;
|
package/lib/approval.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function approvalPolicy(ctx, execution) {
|
|
2
|
+
try {
|
|
3
|
+
const service = (ctx.get ? ctx.get('approval') : ctx.approval);
|
|
4
|
+
const session = execution?.agent?.session;
|
|
5
|
+
const policy = (session === undefined ? undefined : service?.overrideOf?.(session)) ?? service?.config?.policy;
|
|
6
|
+
return policy === 'ask' || policy === 'never' ? policy : 'unknown';
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return 'unknown';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function approvalProblem(policy, setting) {
|
|
13
|
+
if (policy === 'ask')
|
|
14
|
+
return undefined;
|
|
15
|
+
if (policy === 'never')
|
|
16
|
+
return '插件要求确认,但当前会话审批策略 never 不允许询问,操作未执行。请切换到可询问模式,或由用户明确设置 ' + setting + '=false / Confirmation is required but this session cannot ask; no action was performed.';
|
|
17
|
+
return '无法读取宿主审批策略,操作未执行。请检查 DSH 审批服务或插件配置 / Host approval policy unavailable; no action was performed.';
|
|
18
|
+
}
|
package/lib/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { type SqlConfig } from './config.js';
|
|
12
12
|
import { type SqlToolDefinition } from './tools.js';
|
|
13
|
+
import { type ApprovalContext } from './approval.js';
|
|
13
14
|
/** cordis 服务注入:apply 里要用 ctx.tools,必须显式声明。 */
|
|
14
15
|
export declare const name = "sql";
|
|
15
16
|
export declare const inject: string[];
|
|
@@ -31,7 +32,7 @@ interface SqlToolExecution {
|
|
|
31
32
|
/** Harness `tools/pre-execute` waterfall 监听器。 */
|
|
32
33
|
type SqlPreExecuteListener = (exec: SqlToolExecution, next: () => Promise<SqlPreToolDecision>) => Promise<SqlPreToolDecision>;
|
|
33
34
|
/** 插件所需的最小 ctx 面。 */
|
|
34
|
-
export interface SqlPluginContext {
|
|
35
|
+
export interface SqlPluginContext extends ApprovalContext {
|
|
35
36
|
tools: {
|
|
36
37
|
register(definition: SqlToolDefinition): () => void;
|
|
37
38
|
};
|
package/lib/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import { registerUpdates } from '@stardustlc/dsh-updates';
|
|
|
11
11
|
*/
|
|
12
12
|
import { resolveConfig } from './config.js';
|
|
13
13
|
import { buildSqlTools, summarizeWriteScript } from './tools.js';
|
|
14
|
+
import { approvalPolicy, approvalProblem } from './approval.js';
|
|
14
15
|
/** cordis 服务注入:apply 里要用 ctx.tools,必须显式声明。 */
|
|
15
16
|
export const name = 'sql';
|
|
16
17
|
export const inject = ['tools'];
|
|
@@ -20,11 +21,20 @@ export const inject = ['tools'];
|
|
|
20
21
|
export function apply(ctx, config) {
|
|
21
22
|
registerUpdates(ctx, { name: "dsh-sql" });
|
|
22
23
|
const cfg = resolveConfig(config);
|
|
23
|
-
const
|
|
24
|
+
const policyOf = (exec) => approvalPolicy(ctx, exec);
|
|
25
|
+
const { tools, adapters } = buildSqlTools(cfg, policyOf);
|
|
24
26
|
if (cfg.writeApproval) {
|
|
25
27
|
ctx.on('tools/pre-execute', async (exec, next) => {
|
|
26
28
|
if (exec.name !== 'sql_exec')
|
|
27
29
|
return next();
|
|
30
|
+
const downstream = await next();
|
|
31
|
+
if (downstream.kind === 'deny')
|
|
32
|
+
return downstream;
|
|
33
|
+
if (cfg.readOnly)
|
|
34
|
+
return { kind: 'deny', reason: '当前连接为只读配置,sql_exec 已禁用 / Read-only configuration; sql_exec is disabled.' };
|
|
35
|
+
const problem = approvalProblem(policyOf(exec), 'writeApproval');
|
|
36
|
+
if (problem)
|
|
37
|
+
return { kind: 'deny', reason: problem };
|
|
28
38
|
const args = (typeof exec.arguments === 'object' && exec.arguments !== null ? exec.arguments : {});
|
|
29
39
|
const sql = typeof args.sql === 'string' ? args.sql : '';
|
|
30
40
|
return {
|
package/lib/tools.d.ts
CHANGED
|
@@ -52,7 +52,7 @@ export interface SqlExecGateContext {
|
|
|
52
52
|
signal?: unknown;
|
|
53
53
|
}
|
|
54
54
|
/** 构建六个工具定义;adapters 惰性创建并按连接名缓存。 */
|
|
55
|
-
export declare function buildSqlTools(config: ResolvedSqlConfig): {
|
|
55
|
+
export declare function buildSqlTools(config: ResolvedSqlConfig, policyOf?: (execution: unknown) => 'ask' | 'never' | 'unknown'): {
|
|
56
56
|
tools: SqlToolDefinition[];
|
|
57
57
|
adapters: Map<string, DatabaseAdapter>;
|
|
58
58
|
};
|
package/lib/tools.js
CHANGED
|
@@ -402,7 +402,7 @@ const healthSchema = {
|
|
|
402
402
|
additionalProperties: true,
|
|
403
403
|
};
|
|
404
404
|
/** 构建六个工具定义;adapters 惰性创建并按连接名缓存。 */
|
|
405
|
-
export function buildSqlTools(config) {
|
|
405
|
+
export function buildSqlTools(config, policyOf = () => 'unknown') {
|
|
406
406
|
const cfg = config;
|
|
407
407
|
const adapters = new Map();
|
|
408
408
|
/** 只解析连接配置(不建连接),用于在打开数据库前挑选词法规则。 */
|
|
@@ -669,13 +669,13 @@ export function buildSqlTools(config) {
|
|
|
669
669
|
const rec = asRecord(value);
|
|
670
670
|
const connections = Array.isArray(rec.connections) ? rec.connections : [];
|
|
671
671
|
const bad = connections.filter((c) => asRecord(c).ok !== true);
|
|
672
|
-
const lines = ['dsh-sql 自检' + (
|
|
672
|
+
const lines = ['dsh-sql 自检' + (rec.ok === true ? ':正常。' : ':发现问题。')];
|
|
673
673
|
for (const item of connections) {
|
|
674
674
|
const c = asRecord(item);
|
|
675
675
|
lines.push('- ' + c.name + '(' + c.engine + ')' + (c.ok === true ? ' ✅' : ' ❌ ' + String(c.error ?? '')));
|
|
676
676
|
}
|
|
677
677
|
lines.push('- 只读模式:' + (rec.readOnly === true ? '开(sql_exec 已禁用)' : '关'));
|
|
678
|
-
lines.push('- 写审批门:' + (rec.writeApproval === true ? '开' : '关'));
|
|
678
|
+
lines.push('- 写审批门:' + String(rec.writeApprovalDetail ?? (rec.writeApproval === true ? '开' : '关')));
|
|
679
679
|
lines.push('- 行数上限:' + String(rec.maxRows) + ';查询超时 ' + String(rec.queryTimeoutMs) + 'ms;写超时 ' + String(rec.execTimeoutMs) + 'ms');
|
|
680
680
|
return [{ type: 'text', text: lines.join('\n') }];
|
|
681
681
|
},
|
|
@@ -683,12 +683,18 @@ export function buildSqlTools(config) {
|
|
|
683
683
|
async execute(_rawArgs, exec) {
|
|
684
684
|
const connections = await pingAllConnections(executionSignal(exec));
|
|
685
685
|
const bad = connections.filter((c) => c.ok !== true);
|
|
686
|
+
const policy = policyOf(exec);
|
|
687
|
+
const writeApprovalReady = cfg.readOnly || !cfg.writeApproval || policy === 'ask';
|
|
688
|
+
const writeApprovalDetail = cfg.readOnly ? '只读配置,不允许写入' : !cfg.writeApproval ? '关闭;其它宿主策略仍生效' : policy === 'ask' ? '开启;经宿主询问' : policy === 'never' ? '当前策略 never 无法询问;请切换模式或由用户明确设置 writeApproval=false' : '无法读取宿主审批策略';
|
|
686
689
|
return {
|
|
687
|
-
ok: bad.length === 0,
|
|
690
|
+
ok: bad.length === 0 && writeApprovalReady,
|
|
688
691
|
plugin: 'dsh-sql',
|
|
689
692
|
connections,
|
|
690
693
|
readOnly: cfg.readOnly,
|
|
691
694
|
writeApproval: cfg.writeApproval,
|
|
695
|
+
approvalPolicy: policy,
|
|
696
|
+
writeApprovalReady,
|
|
697
|
+
writeApprovalDetail,
|
|
692
698
|
maxRows: cfg.maxRows,
|
|
693
699
|
queryTimeoutMs: cfg.queryTimeoutMs,
|
|
694
700
|
execTimeoutMs: cfg.execTimeoutMs,
|
package/lib/update-client.js
CHANGED
|
@@ -437,7 +437,7 @@ function __stardustUpdatesClient(ctx, React, require, shared) {
|
|
|
437
437
|
}
|
|
438
438
|
|
|
439
439
|
/* STARDUSTLC_UPDATE_CLIENT_BODY_START */
|
|
440
|
-
window.__ModuleLoader__.load(__stardustUpdatesWrap({id:"dsh-sql",factory:require=>({apply(){}})},{"name":"dsh-sql","version":"0.1.0","hasWorkbench":false,"packageVersion":"0.5.
|
|
440
|
+
window.__ModuleLoader__.load(__stardustUpdatesWrap({id:"dsh-sql",factory:require=>({apply(){}})},{"name":"dsh-sql","version":"0.1.0","hasWorkbench":false,"packageVersion":"0.5.5","label":"数据库","labelEn":"SQL","suiteComponent":true}));
|
|
441
441
|
|
|
442
442
|
/* STARDUSTLC_UPDATE_CLIENT_BODY_END */
|
|
443
443
|
})();
|