@judaharagao/opencode-ssh 1.0.0
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/LICENSE +21 -0
- package/README.md +184 -0
- package/dist/config/defaults.d.ts +11 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +23 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/schema.d.ts +51 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +41 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/display/formatter.d.ts +41 -0
- package/dist/display/formatter.d.ts.map +1 -0
- package/dist/display/formatter.js +179 -0
- package/dist/display/formatter.js.map +1 -0
- package/dist/display/stream.d.ts +38 -0
- package/dist/display/stream.d.ts.map +1 -0
- package/dist/display/stream.js +102 -0
- package/dist/display/stream.js.map +1 -0
- package/dist/hooks.d.ts +13 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +151 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/security/allowlist.d.ts +23 -0
- package/dist/security/allowlist.d.ts.map +1 -0
- package/dist/security/allowlist.js +105 -0
- package/dist/security/allowlist.js.map +1 -0
- package/dist/security/blocklist.d.ts +35 -0
- package/dist/security/blocklist.d.ts.map +1 -0
- package/dist/security/blocklist.js +351 -0
- package/dist/security/blocklist.js.map +1 -0
- package/dist/security/policy.d.ts +40 -0
- package/dist/security/policy.d.ts.map +1 -0
- package/dist/security/policy.js +133 -0
- package/dist/security/policy.js.map +1 -0
- package/dist/security/validator.d.ts +32 -0
- package/dist/security/validator.d.ts.map +1 -0
- package/dist/security/validator.js +152 -0
- package/dist/security/validator.js.map +1 -0
- package/dist/ssh/audit.d.ts +47 -0
- package/dist/ssh/audit.d.ts.map +1 -0
- package/dist/ssh/audit.js +126 -0
- package/dist/ssh/audit.js.map +1 -0
- package/dist/ssh/connection.d.ts +73 -0
- package/dist/ssh/connection.d.ts.map +1 -0
- package/dist/ssh/connection.js +210 -0
- package/dist/ssh/connection.js.map +1 -0
- package/dist/ssh/executor.d.ts +49 -0
- package/dist/ssh/executor.d.ts.map +1 -0
- package/dist/ssh/executor.js +275 -0
- package/dist/ssh/executor.js.map +1 -0
- package/dist/ssh/manager.d.ts +43 -0
- package/dist/ssh/manager.d.ts.map +1 -0
- package/dist/ssh/manager.js +98 -0
- package/dist/ssh/manager.js.map +1 -0
- package/dist/ssh/sanitizer.d.ts +41 -0
- package/dist/ssh/sanitizer.d.ts.map +1 -0
- package/dist/ssh/sanitizer.js +108 -0
- package/dist/ssh/sanitizer.js.map +1 -0
- package/dist/tools.d.ts +7 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +584 -0
- package/dist/tools.js.map +1 -0
- package/package.json +64 -0
package/dist/tools.js
ADDED
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin";
|
|
2
|
+
import { SshSessionManager } from "./ssh/manager.js";
|
|
3
|
+
import { executeCommand } from "./ssh/executor.js";
|
|
4
|
+
import { validateCommand } from "./security/validator.js";
|
|
5
|
+
import { getPolicy, addBlocklistPattern, removeBlocklistPattern, addAllowlistPattern, removeAllowlistPattern } from "./security/policy.js";
|
|
6
|
+
import { readAuditLog, formatAuditLog, getAuditStats } from "./ssh/audit.js";
|
|
7
|
+
import { sanitizeHost, sanitizeUsername, sanitizePath } from "./ssh/sanitizer.js";
|
|
8
|
+
import { formatExecResult, formatSessionList, formatConnectResult, formatDisconnectResult, formatCheckResult, formatSecurityPolicy, } from "./display/formatter.js";
|
|
9
|
+
// ── Shared session manager (one per plugin instance) ──
|
|
10
|
+
let sessionManager = null;
|
|
11
|
+
function getManager(maxSessions = 5) {
|
|
12
|
+
if (!sessionManager) {
|
|
13
|
+
sessionManager = new SshSessionManager({ maxSessions });
|
|
14
|
+
}
|
|
15
|
+
return sessionManager;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create all SSH tools for the plugin.
|
|
19
|
+
*/
|
|
20
|
+
export function createSshTools(mode = "full", maxSessions = 5, defaultTimeout = 30, extraBlocklist = []) {
|
|
21
|
+
return {
|
|
22
|
+
// ═══════════════════════════════════════════════════════════════
|
|
23
|
+
// ssh.connect — Establish SSH connection
|
|
24
|
+
// ═══════════════════════════════════════════════════════════════
|
|
25
|
+
"ssh.connect": tool({
|
|
26
|
+
description: "Establish an SSH connection to a remote server. Returns a session_id for use with other ssh.* tools. " +
|
|
27
|
+
"Supports password and key-based authentication. Credentials are never stored in logs or output.",
|
|
28
|
+
args: {
|
|
29
|
+
host: tool.schema.string().describe("Remote server hostname or IP address"),
|
|
30
|
+
port: tool.schema.number().optional().describe("SSH port (default: 22)"),
|
|
31
|
+
username: tool.schema.string().describe("SSH username"),
|
|
32
|
+
auth_method: tool.schema.enum(["password", "key"]).describe("Authentication method"),
|
|
33
|
+
password: tool.schema.string().optional().describe("Password (only for password auth)"),
|
|
34
|
+
key_path: tool.schema.string().optional().describe("Path to private key file (default: ~/.ssh/id_rsa)"),
|
|
35
|
+
passphrase: tool.schema.string().optional().describe("Passphrase for the private key"),
|
|
36
|
+
alias: tool.schema.string().optional().describe("Friendly name for this session"),
|
|
37
|
+
},
|
|
38
|
+
async execute(args, ctx) {
|
|
39
|
+
// ── Input validation ──
|
|
40
|
+
const hostCheck = sanitizeHost(args.host);
|
|
41
|
+
if (!hostCheck.clean) {
|
|
42
|
+
return `❌ Invalid host: ${hostCheck.reason}`;
|
|
43
|
+
}
|
|
44
|
+
const userCheck = sanitizeUsername(args.username);
|
|
45
|
+
if (!userCheck.clean) {
|
|
46
|
+
return `❌ Invalid username: ${userCheck.reason}`;
|
|
47
|
+
}
|
|
48
|
+
// ── Ask for permission ──
|
|
49
|
+
await ctx.ask({
|
|
50
|
+
permission: "ssh.connect",
|
|
51
|
+
patterns: [`${args.username}@${args.host}:${args.port || 22}`],
|
|
52
|
+
always: [`${args.username}@${args.host}:${args.port || 22}`],
|
|
53
|
+
metadata: {
|
|
54
|
+
host: args.host,
|
|
55
|
+
port: args.port || 22,
|
|
56
|
+
username: args.username,
|
|
57
|
+
auth_method: args.auth_method,
|
|
58
|
+
alias: args.alias,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
// ── Connect ──
|
|
62
|
+
const manager = getManager(maxSessions);
|
|
63
|
+
const config = {
|
|
64
|
+
host: args.host,
|
|
65
|
+
port: args.port || 22,
|
|
66
|
+
username: args.username,
|
|
67
|
+
authMethod: args.auth_method,
|
|
68
|
+
password: args.password,
|
|
69
|
+
keyPath: args.key_path,
|
|
70
|
+
passphrase: args.passphrase,
|
|
71
|
+
alias: args.alias,
|
|
72
|
+
timeout: 10000,
|
|
73
|
+
};
|
|
74
|
+
try {
|
|
75
|
+
const sessionId = await manager.createSession(config);
|
|
76
|
+
return formatConnectResult(sessionId, args.host, args.port || 22, args.username, args.alias);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
80
|
+
return [
|
|
81
|
+
`## ❌ SSH Connection Failed`,
|
|
82
|
+
"",
|
|
83
|
+
`**Host:** ${args.username}@${args.host}:${args.port || 22}`,
|
|
84
|
+
`**Error:** ${msg}`,
|
|
85
|
+
"",
|
|
86
|
+
"Troubleshooting:",
|
|
87
|
+
"- Verify the host is reachable",
|
|
88
|
+
"- Check that the username is correct",
|
|
89
|
+
"- Ensure SSH is running on the remote host",
|
|
90
|
+
"- Verify your credentials or key file",
|
|
91
|
+
].join("\n");
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
}),
|
|
95
|
+
// ═══════════════════════════════════════════════════════════════
|
|
96
|
+
// ssh.disconnect — Close SSH session
|
|
97
|
+
// ═══════════════════════════════════════════════════════════════
|
|
98
|
+
"ssh.disconnect": tool({
|
|
99
|
+
description: "Close an active SSH session and free resources.",
|
|
100
|
+
args: {
|
|
101
|
+
session_id: tool.schema.string().describe("Session ID or alias to disconnect"),
|
|
102
|
+
},
|
|
103
|
+
async execute(args, ctx) {
|
|
104
|
+
await ctx.ask({
|
|
105
|
+
permission: "ssh.disconnect",
|
|
106
|
+
patterns: [args.session_id],
|
|
107
|
+
always: [],
|
|
108
|
+
metadata: { session_id: args.session_id },
|
|
109
|
+
});
|
|
110
|
+
const manager = getManager(maxSessions);
|
|
111
|
+
const closed = await manager.closeSession(args.session_id);
|
|
112
|
+
if (!closed) {
|
|
113
|
+
return `Session \`${args.session_id}\` not found or already closed.`;
|
|
114
|
+
}
|
|
115
|
+
return formatDisconnectResult(args.session_id);
|
|
116
|
+
},
|
|
117
|
+
}),
|
|
118
|
+
// ═══════════════════════════════════════════════════════════════
|
|
119
|
+
// ssh.list_sessions — List active SSH sessions
|
|
120
|
+
// ═══════════════════════════════════════════════════════════════
|
|
121
|
+
"ssh.list_sessions": tool({
|
|
122
|
+
description: "List all active SSH sessions with their status, host, and uptime.",
|
|
123
|
+
args: {},
|
|
124
|
+
async execute(_args, _ctx) {
|
|
125
|
+
const manager = getManager(maxSessions);
|
|
126
|
+
const sessions = manager.listSessions();
|
|
127
|
+
return formatSessionList(sessions);
|
|
128
|
+
},
|
|
129
|
+
}),
|
|
130
|
+
// ═══════════════════════════════════════════════════════════════
|
|
131
|
+
// ssh.exec — Execute command on remote server
|
|
132
|
+
// ═══════════════════════════════════════════════════════════════
|
|
133
|
+
"ssh.exec": tool({
|
|
134
|
+
description: "Execute a command on a remote server via SSH. " +
|
|
135
|
+
"Destructive commands (rm -rf /, mkfs, etc.) are automatically blocked with no exceptions. " +
|
|
136
|
+
"Risky commands (DROP TABLE, sudo su, systemctl stop, etc.) require your explicit approval every time. " +
|
|
137
|
+
"All output is streamed and displayed in real-time.",
|
|
138
|
+
args: {
|
|
139
|
+
session_id: tool.schema.string().describe("Session ID or alias"),
|
|
140
|
+
command: tool.schema.string().describe("Command to execute on the remote server"),
|
|
141
|
+
cwd: tool.schema.string().optional().describe("Working directory for the command"),
|
|
142
|
+
timeout: tool.schema.number().optional().describe("Timeout in seconds (default: 30)"),
|
|
143
|
+
sudo: tool.schema.boolean().optional().describe("Run command with sudo"),
|
|
144
|
+
},
|
|
145
|
+
async execute(args, ctx) {
|
|
146
|
+
// ── Validate session ──
|
|
147
|
+
const manager = getManager(maxSessions);
|
|
148
|
+
const connection = manager.getSession(args.session_id);
|
|
149
|
+
if (!connection) {
|
|
150
|
+
return `❌ Session \`${args.session_id}\` not found. Use ssh.list_sessions to see active sessions.`;
|
|
151
|
+
}
|
|
152
|
+
if (!connection.connected) {
|
|
153
|
+
return `❌ Session \`${args.session_id}\` is disconnected. Reconnect with ssh.connect.`;
|
|
154
|
+
}
|
|
155
|
+
// ── Validate command against blocklist BEFORE asking for permission ──
|
|
156
|
+
const validation = validateCommand(args.command, mode, extraBlocklist);
|
|
157
|
+
// DESTRUCTIVE: 100% blocked, no permission prompt, no override
|
|
158
|
+
if (validation.level === "destructive") {
|
|
159
|
+
return [
|
|
160
|
+
"## 🚫 Command Blocked (Destructive)",
|
|
161
|
+
"",
|
|
162
|
+
`**Command:** \`${args.command}\``,
|
|
163
|
+
`**Reason:** ${validation.reason}`,
|
|
164
|
+
`**Rule:** ${validation.matched_rule}`,
|
|
165
|
+
"",
|
|
166
|
+
"This command is **permanently blocked** for safety.",
|
|
167
|
+
"Destructive commands cannot be executed under any circumstances.",
|
|
168
|
+
].join("\n");
|
|
169
|
+
}
|
|
170
|
+
// NOT IN ALLOWLIST: blocked in restricted/read_only mode
|
|
171
|
+
if (validation.level === "not_in_allowlist") {
|
|
172
|
+
return [
|
|
173
|
+
"## 🔒 Command Not Allowed",
|
|
174
|
+
"",
|
|
175
|
+
`**Command:** \`${args.command}\``,
|
|
176
|
+
`**Reason:** ${validation.reason}`,
|
|
177
|
+
"",
|
|
178
|
+
"This command is not in the allowlist for the current security mode.",
|
|
179
|
+
"Use ssh.security_policy to view or modify the policy.",
|
|
180
|
+
].join("\n");
|
|
181
|
+
}
|
|
182
|
+
// RISKY: Ask for permission EVERY TIME (no "always" pattern)
|
|
183
|
+
if (validation.level === "risky") {
|
|
184
|
+
await ctx.ask({
|
|
185
|
+
permission: "ssh.exec.risky",
|
|
186
|
+
patterns: [args.command],
|
|
187
|
+
always: [], // Empty = ask EVERY time
|
|
188
|
+
metadata: {
|
|
189
|
+
session_id: args.session_id,
|
|
190
|
+
command: args.command,
|
|
191
|
+
host: connection.config.host,
|
|
192
|
+
username: connection.config.username,
|
|
193
|
+
reason: validation.reason,
|
|
194
|
+
rule: validation.matched_rule,
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
// Safe command: ask once with "always" pattern
|
|
200
|
+
await ctx.ask({
|
|
201
|
+
permission: "ssh.exec",
|
|
202
|
+
patterns: [args.command],
|
|
203
|
+
always: [args.command],
|
|
204
|
+
metadata: {
|
|
205
|
+
session_id: args.session_id,
|
|
206
|
+
command: args.command,
|
|
207
|
+
host: connection.config.host,
|
|
208
|
+
username: connection.config.username,
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
// ── Execute ──
|
|
213
|
+
const result = await executeCommand(connection, args.command, mode, extraBlocklist, args.session_id, {
|
|
214
|
+
cwd: args.cwd,
|
|
215
|
+
timeout: args.timeout || defaultTimeout,
|
|
216
|
+
sudo: args.sudo,
|
|
217
|
+
}, ctx.directory);
|
|
218
|
+
return formatExecResult(result);
|
|
219
|
+
},
|
|
220
|
+
}),
|
|
221
|
+
// ═══════════════════════════════════════════════════════════════
|
|
222
|
+
// ssh.exec_batch — Execute multiple commands in sequence
|
|
223
|
+
// ═══════════════════════════════════════════════════════════════
|
|
224
|
+
"ssh.exec_batch": tool({
|
|
225
|
+
description: "Execute multiple commands in sequence on a remote server. " +
|
|
226
|
+
"Each command is validated against the security policy. " +
|
|
227
|
+
"If stop_on_error is true, execution stops on the first failed command.",
|
|
228
|
+
args: {
|
|
229
|
+
session_id: tool.schema.string().describe("Session ID or alias"),
|
|
230
|
+
commands: tool.schema.string().describe("Commands separated by newlines"),
|
|
231
|
+
stop_on_error: tool.schema.boolean().optional().describe("Stop if a command fails (default: true)"),
|
|
232
|
+
cwd: tool.schema.string().optional().describe("Working directory"),
|
|
233
|
+
timeout: tool.schema.number().optional().describe("Timeout per command in seconds"),
|
|
234
|
+
},
|
|
235
|
+
async execute(args, ctx) {
|
|
236
|
+
const manager = getManager(maxSessions);
|
|
237
|
+
const connection = manager.getSession(args.session_id);
|
|
238
|
+
if (!connection) {
|
|
239
|
+
return `❌ Session \`${args.session_id}\` not found.`;
|
|
240
|
+
}
|
|
241
|
+
const commands = args.commands.split("\n").filter((c) => c.trim());
|
|
242
|
+
if (commands.length === 0) {
|
|
243
|
+
return "No commands to execute.";
|
|
244
|
+
}
|
|
245
|
+
// ── Validate all commands first ──
|
|
246
|
+
const validations = [];
|
|
247
|
+
for (const cmd of commands) {
|
|
248
|
+
const v = validateCommand(cmd.trim(), mode, extraBlocklist);
|
|
249
|
+
validations.push({ command: cmd.trim(), validation: v });
|
|
250
|
+
}
|
|
251
|
+
// Check for destructive commands
|
|
252
|
+
const destructive = validations.filter((v) => v.validation.level === "destructive");
|
|
253
|
+
if (destructive.length > 0) {
|
|
254
|
+
const lines = ["## 🚫 Batch Blocked (Destructive Commands Found)", ""];
|
|
255
|
+
for (const d of destructive) {
|
|
256
|
+
lines.push(`- \`${d.command}\`: ${d.validation.reason}`);
|
|
257
|
+
}
|
|
258
|
+
lines.push("");
|
|
259
|
+
lines.push("Destructive commands cannot be executed. Remove them and try again.");
|
|
260
|
+
return lines.join("\n");
|
|
261
|
+
}
|
|
262
|
+
// Check for risky commands and ask permission
|
|
263
|
+
const risky = validations.filter((v) => v.validation.level === "risky");
|
|
264
|
+
if (risky.length > 0) {
|
|
265
|
+
await ctx.ask({
|
|
266
|
+
permission: "ssh.exec_batch.risky",
|
|
267
|
+
patterns: risky.map((r) => r.command),
|
|
268
|
+
always: [], // Ask EVERY time for risky batch commands
|
|
269
|
+
metadata: {
|
|
270
|
+
session_id: args.session_id,
|
|
271
|
+
commands: risky.map((r) => ({
|
|
272
|
+
command: r.command,
|
|
273
|
+
reason: r.validation.reason,
|
|
274
|
+
rule: r.validation.matched_rule,
|
|
275
|
+
})),
|
|
276
|
+
host: connection.config.host,
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
// Safe batch
|
|
282
|
+
await ctx.ask({
|
|
283
|
+
permission: "ssh.exec_batch",
|
|
284
|
+
patterns: commands.map((c) => c.trim()),
|
|
285
|
+
always: [],
|
|
286
|
+
metadata: {
|
|
287
|
+
session_id: args.session_id,
|
|
288
|
+
command_count: commands.length,
|
|
289
|
+
host: connection.config.host,
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
// ── Execute commands sequentially ──
|
|
294
|
+
const results = [];
|
|
295
|
+
const stopOnError = args.stop_on_error !== false;
|
|
296
|
+
for (const cmd of commands) {
|
|
297
|
+
const result = await executeCommand(connection, cmd.trim(), mode, extraBlocklist, args.session_id, {
|
|
298
|
+
cwd: args.cwd,
|
|
299
|
+
timeout: args.timeout || defaultTimeout,
|
|
300
|
+
}, ctx.directory);
|
|
301
|
+
results.push(result);
|
|
302
|
+
if (stopOnError && result.exitCode !== 0) {
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
// ── Format batch results ──
|
|
307
|
+
const lines = [`## SSH Batch Results (${results.length}/${commands.length} executed)\n`];
|
|
308
|
+
for (let i = 0; i < results.length; i++) {
|
|
309
|
+
const r = results[i];
|
|
310
|
+
const icon = r.exitCode === 0 ? "✅" : "❌";
|
|
311
|
+
lines.push(`${icon} **${i + 1}.** \`${r.command}\` — exit: ${r.exitCode}`);
|
|
312
|
+
if (r.stdout.trim()) {
|
|
313
|
+
lines.push(` ${r.stdout.trim().split("\n")[0]}`);
|
|
314
|
+
}
|
|
315
|
+
if (r.stderr.trim()) {
|
|
316
|
+
lines.push(` stderr: ${r.stderr.trim().split("\n")[0]}`);
|
|
317
|
+
}
|
|
318
|
+
lines.push("");
|
|
319
|
+
}
|
|
320
|
+
return lines.join("\n");
|
|
321
|
+
},
|
|
322
|
+
}),
|
|
323
|
+
// ═══════════════════════════════════════════════════════════════
|
|
324
|
+
// ssh.upload — Upload file via SCP
|
|
325
|
+
// ═══════════════════════════════════════════════════════════════
|
|
326
|
+
"ssh.upload": tool({
|
|
327
|
+
description: "Upload a local file to the remote server via SCP/SFTP.",
|
|
328
|
+
args: {
|
|
329
|
+
session_id: tool.schema.string().describe("Session ID or alias"),
|
|
330
|
+
local_path: tool.schema.string().describe("Local file path"),
|
|
331
|
+
remote_path: tool.schema.string().describe("Remote destination path"),
|
|
332
|
+
},
|
|
333
|
+
async execute(args, ctx) {
|
|
334
|
+
const manager = getManager(maxSessions);
|
|
335
|
+
const connection = manager.getSession(args.session_id);
|
|
336
|
+
if (!connection) {
|
|
337
|
+
return `❌ Session \`${args.session_id}\` not found.`;
|
|
338
|
+
}
|
|
339
|
+
// Validate paths
|
|
340
|
+
const pathCheck = sanitizePath(args.local_path);
|
|
341
|
+
if (!pathCheck.clean)
|
|
342
|
+
return `❌ Invalid local path: ${pathCheck.reason}`;
|
|
343
|
+
const remoteCheck = sanitizePath(args.remote_path);
|
|
344
|
+
if (!remoteCheck.clean)
|
|
345
|
+
return `❌ Invalid remote path: ${remoteCheck.reason}`;
|
|
346
|
+
await ctx.ask({
|
|
347
|
+
permission: "ssh.upload",
|
|
348
|
+
patterns: [args.local_path, args.remote_path],
|
|
349
|
+
always: [],
|
|
350
|
+
metadata: {
|
|
351
|
+
session_id: args.session_id,
|
|
352
|
+
local_path: args.local_path,
|
|
353
|
+
remote_path: args.remote_path,
|
|
354
|
+
host: connection.config.host,
|
|
355
|
+
},
|
|
356
|
+
});
|
|
357
|
+
try {
|
|
358
|
+
const sftp = await connection.sftp();
|
|
359
|
+
await new Promise((resolve, reject) => {
|
|
360
|
+
sftp.fastPut(args.local_path, args.remote_path, (err) => {
|
|
361
|
+
if (err)
|
|
362
|
+
reject(err);
|
|
363
|
+
else
|
|
364
|
+
resolve();
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
return [
|
|
368
|
+
"## 📤 File Uploaded",
|
|
369
|
+
"",
|
|
370
|
+
`- **Local:** \`${args.local_path}\``,
|
|
371
|
+
`- **Remote:** \`${args.remote_path}\``,
|
|
372
|
+
`- **Session:** \`${args.session_id}\``,
|
|
373
|
+
].join("\n");
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
377
|
+
return `❌ Upload failed: ${msg}`;
|
|
378
|
+
}
|
|
379
|
+
},
|
|
380
|
+
}),
|
|
381
|
+
// ═══════════════════════════════════════════════════════════════
|
|
382
|
+
// ssh.download — Download file via SCP
|
|
383
|
+
// ═══════════════════════════════════════════════════════════════
|
|
384
|
+
"ssh.download": tool({
|
|
385
|
+
description: "Download a file from the remote server to local via SCP/SFTP.",
|
|
386
|
+
args: {
|
|
387
|
+
session_id: tool.schema.string().describe("Session ID or alias"),
|
|
388
|
+
remote_path: tool.schema.string().describe("Remote file path"),
|
|
389
|
+
local_path: tool.schema.string().describe("Local destination path"),
|
|
390
|
+
},
|
|
391
|
+
async execute(args, ctx) {
|
|
392
|
+
const manager = getManager(maxSessions);
|
|
393
|
+
const connection = manager.getSession(args.session_id);
|
|
394
|
+
if (!connection) {
|
|
395
|
+
return `❌ Session \`${args.session_id}\` not found.`;
|
|
396
|
+
}
|
|
397
|
+
const pathCheck = sanitizePath(args.local_path);
|
|
398
|
+
if (!pathCheck.clean)
|
|
399
|
+
return `❌ Invalid local path: ${pathCheck.reason}`;
|
|
400
|
+
const remoteCheck = sanitizePath(args.remote_path);
|
|
401
|
+
if (!remoteCheck.clean)
|
|
402
|
+
return `❌ Invalid remote path: ${remoteCheck.reason}`;
|
|
403
|
+
await ctx.ask({
|
|
404
|
+
permission: "ssh.download",
|
|
405
|
+
patterns: [args.remote_path, args.local_path],
|
|
406
|
+
always: [],
|
|
407
|
+
metadata: {
|
|
408
|
+
session_id: args.session_id,
|
|
409
|
+
remote_path: args.remote_path,
|
|
410
|
+
local_path: args.local_path,
|
|
411
|
+
host: connection.config.host,
|
|
412
|
+
},
|
|
413
|
+
});
|
|
414
|
+
try {
|
|
415
|
+
const sftp = await connection.sftp();
|
|
416
|
+
await new Promise((resolve, reject) => {
|
|
417
|
+
sftp.fastGet(args.remote_path, args.local_path, (err) => {
|
|
418
|
+
if (err)
|
|
419
|
+
reject(err);
|
|
420
|
+
else
|
|
421
|
+
resolve();
|
|
422
|
+
});
|
|
423
|
+
});
|
|
424
|
+
return [
|
|
425
|
+
"## 📥 File Downloaded",
|
|
426
|
+
"",
|
|
427
|
+
`- **Remote:** \`${args.remote_path}\``,
|
|
428
|
+
`- **Local:** \`${args.local_path}\``,
|
|
429
|
+
`- **Session:** \`${args.session_id}\``,
|
|
430
|
+
].join("\n");
|
|
431
|
+
}
|
|
432
|
+
catch (error) {
|
|
433
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
434
|
+
return `❌ Download failed: ${msg}`;
|
|
435
|
+
}
|
|
436
|
+
},
|
|
437
|
+
}),
|
|
438
|
+
// ═══════════════════════════════════════════════════════════════
|
|
439
|
+
// ssh.check_command — Validate command safety (dry-run)
|
|
440
|
+
// ═══════════════════════════════════════════════════════════════
|
|
441
|
+
"ssh.check_command": tool({
|
|
442
|
+
description: "Check if a command is safe to execute without actually running it. " +
|
|
443
|
+
"Returns the safety level, any matched blocklist rules, and suggestions. " +
|
|
444
|
+
"Use this to preview command safety before execution.",
|
|
445
|
+
args: {
|
|
446
|
+
command: tool.schema.string().describe("Command to validate"),
|
|
447
|
+
},
|
|
448
|
+
async execute(args, _ctx) {
|
|
449
|
+
const validation = validateCommand(args.command, mode, extraBlocklist);
|
|
450
|
+
return formatCheckResult(args.command, validation);
|
|
451
|
+
},
|
|
452
|
+
}),
|
|
453
|
+
// ═══════════════════════════════════════════════════════════════
|
|
454
|
+
// ssh.security_policy — View/manage security policy
|
|
455
|
+
// ═══════════════════════════════════════════════════════════════
|
|
456
|
+
"ssh.security_policy": tool({
|
|
457
|
+
description: "View or modify the SSH security policy. " +
|
|
458
|
+
"Can add/remove patterns from the blocklist or allowlist, " +
|
|
459
|
+
"and view the current security mode.",
|
|
460
|
+
args: {
|
|
461
|
+
action: tool.schema
|
|
462
|
+
.enum(["view", "add_blocklist", "remove_blocklist", "add_allowlist", "remove_allowlist"])
|
|
463
|
+
.describe("Action to perform"),
|
|
464
|
+
pattern: tool.schema.string().optional().describe("Regex pattern to add/remove"),
|
|
465
|
+
},
|
|
466
|
+
async execute(args, ctx) {
|
|
467
|
+
if (!args.pattern && args.action !== "view") {
|
|
468
|
+
return "❌ A pattern is required for add/remove actions.";
|
|
469
|
+
}
|
|
470
|
+
if (args.pattern) {
|
|
471
|
+
// Validate regex
|
|
472
|
+
try {
|
|
473
|
+
new RegExp(args.pattern);
|
|
474
|
+
}
|
|
475
|
+
catch {
|
|
476
|
+
return `❌ Invalid regex pattern: \`${args.pattern}\``;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
await ctx.ask({
|
|
480
|
+
permission: "ssh.security_policy",
|
|
481
|
+
patterns: [`${args.action}: ${args.pattern || ""}`],
|
|
482
|
+
always: [],
|
|
483
|
+
metadata: {
|
|
484
|
+
action: args.action,
|
|
485
|
+
pattern: args.pattern,
|
|
486
|
+
},
|
|
487
|
+
});
|
|
488
|
+
switch (args.action) {
|
|
489
|
+
case "view": {
|
|
490
|
+
const policy = getPolicy(ctx.directory, mode);
|
|
491
|
+
return formatSecurityPolicy(policy);
|
|
492
|
+
}
|
|
493
|
+
case "add_blocklist": {
|
|
494
|
+
const policy = addBlocklistPattern(ctx.directory, args.pattern);
|
|
495
|
+
return [
|
|
496
|
+
"## ✅ Blocklist Pattern Added",
|
|
497
|
+
"",
|
|
498
|
+
`Added: \`${args.pattern}\``,
|
|
499
|
+
"",
|
|
500
|
+
formatSecurityPolicy(policy),
|
|
501
|
+
].join("\n");
|
|
502
|
+
}
|
|
503
|
+
case "remove_blocklist": {
|
|
504
|
+
const policy = removeBlocklistPattern(ctx.directory, args.pattern);
|
|
505
|
+
return [
|
|
506
|
+
"## ✅ Blocklist Pattern Removed",
|
|
507
|
+
"",
|
|
508
|
+
`Removed: \`${args.pattern}\``,
|
|
509
|
+
"",
|
|
510
|
+
formatSecurityPolicy(policy),
|
|
511
|
+
].join("\n");
|
|
512
|
+
}
|
|
513
|
+
case "add_allowlist": {
|
|
514
|
+
const policy = addAllowlistPattern(ctx.directory, args.pattern);
|
|
515
|
+
return [
|
|
516
|
+
"## ✅ Allowlist Pattern Added",
|
|
517
|
+
"",
|
|
518
|
+
`Added: \`${args.pattern}\``,
|
|
519
|
+
"",
|
|
520
|
+
formatSecurityPolicy(policy),
|
|
521
|
+
].join("\n");
|
|
522
|
+
}
|
|
523
|
+
case "remove_allowlist": {
|
|
524
|
+
const policy = removeAllowlistPattern(ctx.directory, args.pattern);
|
|
525
|
+
return [
|
|
526
|
+
"## ✅ Allowlist Pattern Removed",
|
|
527
|
+
"",
|
|
528
|
+
`Removed: \`${args.pattern}\``,
|
|
529
|
+
"",
|
|
530
|
+
formatSecurityPolicy(policy),
|
|
531
|
+
].join("\n");
|
|
532
|
+
}
|
|
533
|
+
default:
|
|
534
|
+
return `❌ Unknown action: ${args.action}`;
|
|
535
|
+
}
|
|
536
|
+
},
|
|
537
|
+
}),
|
|
538
|
+
// ═══════════════════════════════════════════════════════════════
|
|
539
|
+
// ssh.audit_log — View command audit trail
|
|
540
|
+
// ═══════════════════════════════════════════════════════════════
|
|
541
|
+
"ssh.audit_log": tool({
|
|
542
|
+
description: "View the SSH command audit log. Shows all executed, blocked, and approved commands " +
|
|
543
|
+
"with timestamps, results, and details. Supports filtering by session and command.",
|
|
544
|
+
args: {
|
|
545
|
+
limit: tool.schema.number().optional().describe("Maximum entries to show (default: 20)"),
|
|
546
|
+
session_id: tool.schema.string().optional().describe("Filter by session ID"),
|
|
547
|
+
command_filter: tool.schema.string().optional().describe("Filter by command text"),
|
|
548
|
+
},
|
|
549
|
+
async execute(args, ctx) {
|
|
550
|
+
const entries = readAuditLog(ctx.directory, {
|
|
551
|
+
limit: args.limit || 20,
|
|
552
|
+
sessionId: args.session_id,
|
|
553
|
+
commandFilter: args.command_filter,
|
|
554
|
+
});
|
|
555
|
+
if (entries.length === 0) {
|
|
556
|
+
// Show stats even if no entries match
|
|
557
|
+
const stats = getAuditStats(ctx.directory);
|
|
558
|
+
if (stats.total === 0) {
|
|
559
|
+
return "📋 No audit entries yet. Commands executed via ssh.exec will be logged here.";
|
|
560
|
+
}
|
|
561
|
+
return [
|
|
562
|
+
`## SSH Audit Stats`,
|
|
563
|
+
"",
|
|
564
|
+
`- **Total:** ${stats.total}`,
|
|
565
|
+
`- **Success:** ${stats.success}`,
|
|
566
|
+
`- **Blocked:** ${stats.blocked}`,
|
|
567
|
+
`- **Approved (risky):** ${stats.approved}`,
|
|
568
|
+
`- **Errors:** ${stats.error}`,
|
|
569
|
+
"",
|
|
570
|
+
"No entries match the current filters.",
|
|
571
|
+
].join("\n");
|
|
572
|
+
}
|
|
573
|
+
// Show stats header
|
|
574
|
+
const stats = getAuditStats(ctx.directory);
|
|
575
|
+
const header = [
|
|
576
|
+
`### Stats: ${stats.total} total | ${stats.success} ✅ | ${stats.blocked} 🚫 | ${stats.approved} ⚠️ | ${stats.error} ❌`,
|
|
577
|
+
"",
|
|
578
|
+
].join("\n");
|
|
579
|
+
return header + formatAuditLog(entries);
|
|
580
|
+
},
|
|
581
|
+
}),
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|