@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/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Judah Aragao
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# opencode-ssh
|
|
2
|
+
|
|
3
|
+
SSH access plugin for OpenCode — secure remote command execution with command blocking and audit.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔐 **SSH Session Management** — Connect to multiple remote servers simultaneously
|
|
8
|
+
- ⚡ **Real-time Command Execution** — Execute commands with live output streaming
|
|
9
|
+
- 🛡️ **Security-First Design** — Destructive commands blocked 100%, risky commands require approval every time
|
|
10
|
+
- 📋 **Full Audit Trail** — Every command is logged with timestamps, results, and details
|
|
11
|
+
- 🔒 **Three Security Modes** — Full, Restricted, or Read-Only
|
|
12
|
+
- 📤 **File Transfer** — Upload and download files via SCP/SFTP
|
|
13
|
+
- 🎯 **Command Safety Checker** — Preview command safety before execution
|
|
14
|
+
- ⚙️ **Configurable Policies** — Add custom blocklist/allowlist patterns
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
Add to your `opencode.json`:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"plugin": ["@judaharagao/opencode-ssh"]
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or with configuration:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"plugin": [
|
|
31
|
+
["@judaharagao/opencode-ssh", {
|
|
32
|
+
"mode": "full",
|
|
33
|
+
"max_sessions": 5,
|
|
34
|
+
"default_timeout": 30,
|
|
35
|
+
"audit_enabled": true
|
|
36
|
+
}]
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Configuration Options
|
|
42
|
+
|
|
43
|
+
| Option | Type | Default | Description |
|
|
44
|
+
|--------|------|---------|-------------|
|
|
45
|
+
| `mode` | `"full"` \| `"restricted"` \| `"read_only"` | `"full"` | Security mode for command execution |
|
|
46
|
+
| `max_sessions` | number | `5` | Maximum concurrent SSH sessions |
|
|
47
|
+
| `default_timeout` | number | `30` | Default command timeout in seconds |
|
|
48
|
+
| `audit_enabled` | boolean | `true` | Enable audit logging |
|
|
49
|
+
| `blocklist_extra` | string[] | `[]` | Additional regex patterns to block |
|
|
50
|
+
| `allowlist` | string[] | `[]` | Additional allowed patterns (restricted mode) |
|
|
51
|
+
|
|
52
|
+
## Security Modes
|
|
53
|
+
|
|
54
|
+
### Full Mode
|
|
55
|
+
All commands are allowed except those in the blocklist. Destructive commands are always blocked. Risky commands require approval.
|
|
56
|
+
|
|
57
|
+
### Restricted Mode
|
|
58
|
+
Only commands in the allowlist + read-only commands are allowed. Risky and destructive commands are blocked.
|
|
59
|
+
|
|
60
|
+
### Read-Only Mode
|
|
61
|
+
Only read-only commands (ls, cat, grep, docker ps, etc.) are allowed. No write operations.
|
|
62
|
+
|
|
63
|
+
## Commands (Tools)
|
|
64
|
+
|
|
65
|
+
### `ssh.connect`
|
|
66
|
+
Establish an SSH connection to a remote server.
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
ssh.connect(host="192.168.1.100", username="admin", auth_method="key")
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### `ssh.disconnect`
|
|
73
|
+
Close an SSH session.
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
ssh.disconnect(session_id="ssh-abc123")
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### `ssh.list_sessions`
|
|
80
|
+
List all active SSH sessions.
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
ssh.list_sessions()
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `ssh.exec`
|
|
87
|
+
Execute a command on a remote server.
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
ssh.exec(session_id="prod-server", command="docker ps -a")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### `ssh.exec_batch`
|
|
94
|
+
Execute multiple commands in sequence.
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
ssh.exec_batch(session_id="prod-server", commands="cd /app\nls -la\ndocker ps")
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `ssh.upload`
|
|
101
|
+
Upload a file via SCP.
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
ssh.upload(session_id="prod-server", local_path="./config.yml", remote_path="/app/config.yml")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### `ssh.download`
|
|
108
|
+
Download a file via SCP.
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
ssh.download(session_id="prod-server", remote_path="/var/log/app.log", local_path="./app.log")
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### `ssh.check_command`
|
|
115
|
+
Check if a command is safe (dry-run).
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
ssh.check_command(command="rm -rf /tmp/cache")
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### `ssh.security_policy`
|
|
122
|
+
View or modify the security policy.
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
ssh.security_policy(action="view")
|
|
126
|
+
ssh.security_policy(action="add_blocklist", pattern="custom-dangerous-.*")
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### `ssh.audit_log`
|
|
130
|
+
View the command audit trail.
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
ssh.audit_log(limit=20)
|
|
134
|
+
ssh.audit_log(session_id="prod-server", command_filter="docker")
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Security
|
|
138
|
+
|
|
139
|
+
### Destructive Commands (100% Blocked)
|
|
140
|
+
These commands are **permanently blocked** with no exceptions:
|
|
141
|
+
|
|
142
|
+
- `rm -rf /`, `rm -rf ~`, `rm -rf .*`
|
|
143
|
+
- `mkfs`, `dd if=/dev/zero`
|
|
144
|
+
- Fork bombs (`:(){:|:&};:`)
|
|
145
|
+
- `chmod -R 777 /`, `chmod -R 000 /`
|
|
146
|
+
- `shutdown`, `reboot`, `init 0/6`
|
|
147
|
+
- `kill -9 1`, `killall`
|
|
148
|
+
- `iptables -F`, `ufw disable`
|
|
149
|
+
- `wget/curl | sh|bash`
|
|
150
|
+
|
|
151
|
+
### Risky Commands (Approval Required Every Time)
|
|
152
|
+
These commands require your explicit approval each time:
|
|
153
|
+
|
|
154
|
+
- `DROP TABLE`, `DELETE FROM`, `TRUNCATE`
|
|
155
|
+
- `sudo su`, `sudo -i`
|
|
156
|
+
- `systemctl stop/disable`
|
|
157
|
+
- `kill -9`, `kill -15`
|
|
158
|
+
- `npm uninstall -g`, `apt remove/purge`
|
|
159
|
+
- `userdel`, `groupdel`
|
|
160
|
+
- `iptables -A/-D`
|
|
161
|
+
|
|
162
|
+
### Credential Safety
|
|
163
|
+
- Passwords and SSH keys are **never** stored in logs or output
|
|
164
|
+
- Session info only contains host, username, and port
|
|
165
|
+
- Credentials are held in memory only during the session
|
|
166
|
+
- All sessions are destroyed when the plugin is disposed
|
|
167
|
+
|
|
168
|
+
## Audit Log
|
|
169
|
+
|
|
170
|
+
All commands are logged in `.opencode-ssh/audit.jsonl` with:
|
|
171
|
+
|
|
172
|
+
- Timestamp
|
|
173
|
+
- Session ID (host@user)
|
|
174
|
+
- Command executed
|
|
175
|
+
- Result (success/blocked/approved/error)
|
|
176
|
+
- Exit code
|
|
177
|
+
- Duration
|
|
178
|
+
- Matched security rule (if any)
|
|
179
|
+
|
|
180
|
+
View the audit log with `ssh.audit_log`.
|
|
181
|
+
|
|
182
|
+
## License
|
|
183
|
+
|
|
184
|
+
MIT
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type SshPluginConfigType } from "./schema.js";
|
|
2
|
+
/**
|
|
3
|
+
* Get merged configuration with user overrides.
|
|
4
|
+
*/
|
|
5
|
+
export declare function resolveConfig(userConfig?: Record<string, unknown>): SshPluginConfigType;
|
|
6
|
+
/**
|
|
7
|
+
* Get the SSH data directory path for a project.
|
|
8
|
+
* Stores sessions, audit logs, and policy files.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getSshDataDir(projectDir: string): string;
|
|
11
|
+
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAEtE;;GAEG;AACH,wBAAgB,aAAa,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,mBAAmB,CAYvF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAExD"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DEFAULT_CONFIG } from "./schema.js";
|
|
2
|
+
/**
|
|
3
|
+
* Get merged configuration with user overrides.
|
|
4
|
+
*/
|
|
5
|
+
export function resolveConfig(userConfig) {
|
|
6
|
+
if (!userConfig)
|
|
7
|
+
return { ...DEFAULT_CONFIG };
|
|
8
|
+
const merged = { ...DEFAULT_CONFIG };
|
|
9
|
+
for (const [key, value] of Object.entries(userConfig)) {
|
|
10
|
+
if (value !== undefined && value !== null) {
|
|
11
|
+
merged[key] = value;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return merged;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Get the SSH data directory path for a project.
|
|
18
|
+
* Stores sessions, audit logs, and policy files.
|
|
19
|
+
*/
|
|
20
|
+
export function getSshDataDir(projectDir) {
|
|
21
|
+
return `${projectDir}/.opencode-ssh`;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAA4B,MAAM,aAAa,CAAA;AAEtE;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,UAAoC;IAChE,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,GAAG,cAAc,EAAE,CAAA;IAE7C,MAAM,MAAM,GAA4B,EAAE,GAAG,cAAc,EAAE,CAAA;IAE7D,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACtD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAC1C,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACrB,CAAC;IACH,CAAC;IAED,OAAO,MAA6B,CAAA;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,UAAkB;IAC9C,OAAO,GAAG,UAAU,gBAAgB,CAAA;AACtC,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Security mode for SSH command execution.
|
|
4
|
+
* - "full": All commands allowed except blocklist
|
|
5
|
+
* - "restricted": Only allowlist + read-only commands
|
|
6
|
+
* - "read_only": Only read-only commands (ls, cat, grep, etc.)
|
|
7
|
+
*/
|
|
8
|
+
export declare const SecurityMode: z.ZodEnum<["full", "restricted", "read_only"]>;
|
|
9
|
+
export type SecurityMode = z.infer<typeof SecurityMode>;
|
|
10
|
+
/**
|
|
11
|
+
* Configuration schema for the opencode-ssh plugin.
|
|
12
|
+
*/
|
|
13
|
+
export declare const SshPluginConfig: z.ZodObject<{
|
|
14
|
+
/** Security mode for command execution */
|
|
15
|
+
mode: z.ZodDefault<z.ZodEnum<["full", "restricted", "read_only"]>>;
|
|
16
|
+
/** Maximum concurrent SSH sessions */
|
|
17
|
+
max_sessions: z.ZodDefault<z.ZodNumber>;
|
|
18
|
+
/** Default command timeout in seconds */
|
|
19
|
+
default_timeout: z.ZodDefault<z.ZodNumber>;
|
|
20
|
+
/** Whether to enable audit logging */
|
|
21
|
+
audit_enabled: z.ZodDefault<z.ZodBoolean>;
|
|
22
|
+
/** Additional command patterns to block (regex strings) */
|
|
23
|
+
blocklist_extra: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
24
|
+
/** Additional command patterns to allow (used in restricted mode) */
|
|
25
|
+
allowlist: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
26
|
+
/** Path to SSH config file (~/.ssh/config) */
|
|
27
|
+
ssh_config_path: z.ZodOptional<z.ZodString>;
|
|
28
|
+
/** Auto-connect on plugin boot (requires saved session) */
|
|
29
|
+
auto_connect: z.ZodDefault<z.ZodBoolean>;
|
|
30
|
+
}, "strict", z.ZodTypeAny, {
|
|
31
|
+
mode: "full" | "restricted" | "read_only";
|
|
32
|
+
max_sessions: number;
|
|
33
|
+
default_timeout: number;
|
|
34
|
+
audit_enabled: boolean;
|
|
35
|
+
blocklist_extra: string[];
|
|
36
|
+
allowlist: string[];
|
|
37
|
+
auto_connect: boolean;
|
|
38
|
+
ssh_config_path?: string | undefined;
|
|
39
|
+
}, {
|
|
40
|
+
mode?: "full" | "restricted" | "read_only" | undefined;
|
|
41
|
+
max_sessions?: number | undefined;
|
|
42
|
+
default_timeout?: number | undefined;
|
|
43
|
+
audit_enabled?: boolean | undefined;
|
|
44
|
+
blocklist_extra?: string[] | undefined;
|
|
45
|
+
allowlist?: string[] | undefined;
|
|
46
|
+
ssh_config_path?: string | undefined;
|
|
47
|
+
auto_connect?: boolean | undefined;
|
|
48
|
+
}>;
|
|
49
|
+
export type SshPluginConfigType = z.infer<typeof SshPluginConfig>;
|
|
50
|
+
export declare const DEFAULT_CONFIG: SshPluginConfigType;
|
|
51
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;GAKG;AACH,eAAO,MAAM,YAAY,gDAA8C,CAAA;AACvE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAEvD;;GAEG;AACH,eAAO,MAAM,eAAe;IAExB,0CAA0C;;IAG1C,sCAAsC;;IAGtC,yCAAyC;;IAGzC,sCAAsC;;IAGtC,2DAA2D;;IAG3D,qEAAqE;;IAGrE,8CAA8C;;IAG9C,2DAA2D;;;;;;;;;;;;;;;;;;;;EAGpD,CAAA;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAEjE,eAAO,MAAM,cAAc,EAAE,mBAQ5B,CAAA"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Security mode for SSH command execution.
|
|
4
|
+
* - "full": All commands allowed except blocklist
|
|
5
|
+
* - "restricted": Only allowlist + read-only commands
|
|
6
|
+
* - "read_only": Only read-only commands (ls, cat, grep, etc.)
|
|
7
|
+
*/
|
|
8
|
+
export const SecurityMode = z.enum(["full", "restricted", "read_only"]);
|
|
9
|
+
/**
|
|
10
|
+
* Configuration schema for the opencode-ssh plugin.
|
|
11
|
+
*/
|
|
12
|
+
export const SshPluginConfig = z
|
|
13
|
+
.object({
|
|
14
|
+
/** Security mode for command execution */
|
|
15
|
+
mode: SecurityMode.default("full"),
|
|
16
|
+
/** Maximum concurrent SSH sessions */
|
|
17
|
+
max_sessions: z.number().int().min(1).max(50).default(5),
|
|
18
|
+
/** Default command timeout in seconds */
|
|
19
|
+
default_timeout: z.number().int().min(1).max(600).default(30),
|
|
20
|
+
/** Whether to enable audit logging */
|
|
21
|
+
audit_enabled: z.boolean().default(true),
|
|
22
|
+
/** Additional command patterns to block (regex strings) */
|
|
23
|
+
blocklist_extra: z.array(z.string()).default([]),
|
|
24
|
+
/** Additional command patterns to allow (used in restricted mode) */
|
|
25
|
+
allowlist: z.array(z.string()).default([]),
|
|
26
|
+
/** Path to SSH config file (~/.ssh/config) */
|
|
27
|
+
ssh_config_path: z.string().optional(),
|
|
28
|
+
/** Auto-connect on plugin boot (requires saved session) */
|
|
29
|
+
auto_connect: z.boolean().default(false),
|
|
30
|
+
})
|
|
31
|
+
.strict();
|
|
32
|
+
export const DEFAULT_CONFIG = {
|
|
33
|
+
mode: "full",
|
|
34
|
+
max_sessions: 5,
|
|
35
|
+
default_timeout: 30,
|
|
36
|
+
audit_enabled: true,
|
|
37
|
+
blocklist_extra: [],
|
|
38
|
+
allowlist: [],
|
|
39
|
+
auto_connect: false,
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC,CAAA;AAGvE;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC;KAC7B,MAAM,CAAC;IACN,0CAA0C;IAC1C,IAAI,EAAE,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC;IAElC,sCAAsC;IACtC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAExD,yCAAyC;IACzC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAE7D,sCAAsC;IACtC,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAExC,2DAA2D;IAC3D,eAAe,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAEhD,qEAAqE;IACrE,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAE1C,8CAA8C;IAC9C,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAEtC,2DAA2D;IAC3D,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;CACzC,CAAC;KACD,MAAM,EAAE,CAAA;AAIX,MAAM,CAAC,MAAM,cAAc,GAAwB;IACjD,IAAI,EAAE,MAAM;IACZ,YAAY,EAAE,CAAC;IACf,eAAe,EAAE,EAAE;IACnB,aAAa,EAAE,IAAI;IACnB,eAAe,EAAE,EAAE;IACnB,SAAS,EAAE,EAAE;IACb,YAAY,EAAE,KAAK;CACpB,CAAA"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ExecResult } from "../ssh/executor.js";
|
|
2
|
+
import type { SshConnectionInfo } from "../ssh/connection.js";
|
|
3
|
+
/**
|
|
4
|
+
* Format an SSH execution result for display in the terminal.
|
|
5
|
+
*/
|
|
6
|
+
export declare function formatExecResult(result: ExecResult): string;
|
|
7
|
+
/**
|
|
8
|
+
* Format a session list for display.
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatSessionList(sessions: SshConnectionInfo[]): string;
|
|
11
|
+
/**
|
|
12
|
+
* Format a connection success message.
|
|
13
|
+
*/
|
|
14
|
+
export declare function formatConnectResult(sessionId: string, host: string, port: number, username: string, alias?: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Format a disconnection message.
|
|
17
|
+
*/
|
|
18
|
+
export declare function formatDisconnectResult(sessionId: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Format a blocked command message.
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatBlockedCommand(command: string, reason: string, level: "destructive" | "risky"): string;
|
|
23
|
+
/**
|
|
24
|
+
* Format a command check result (dry-run validation).
|
|
25
|
+
*/
|
|
26
|
+
export declare function formatCheckResult(command: string, validation: {
|
|
27
|
+
safe: boolean;
|
|
28
|
+
level: string;
|
|
29
|
+
reason?: string;
|
|
30
|
+
matched_rule?: string;
|
|
31
|
+
}): string;
|
|
32
|
+
/**
|
|
33
|
+
* Format a security policy for display.
|
|
34
|
+
*/
|
|
35
|
+
export declare function formatSecurityPolicy(policy: {
|
|
36
|
+
mode: string;
|
|
37
|
+
extraBlocklist: string[];
|
|
38
|
+
customAllowlist: string[];
|
|
39
|
+
updatedAt: string;
|
|
40
|
+
}): string;
|
|
41
|
+
//# sourceMappingURL=formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/display/formatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAE7D;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA+C3D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAsBvE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,MAAM,GACb,MAAM,CAWR;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,aAAa,GAAG,OAAO,GAC7B,MAAM,CAqBR;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GACnF,MAAM,CAmBR;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,IAAI,EAAE,MAAM,CAAA;IACZ,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,SAAS,EAAE,MAAM,CAAA;CAClB,GAAG,MAAM,CAuCT"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format an SSH execution result for display in the terminal.
|
|
3
|
+
*/
|
|
4
|
+
export function formatExecResult(result) {
|
|
5
|
+
const lines = [];
|
|
6
|
+
// ── Header with session and command info ──
|
|
7
|
+
const durationStr = result.duration < 1000
|
|
8
|
+
? `${result.duration}ms`
|
|
9
|
+
: `${(result.duration / 1000).toFixed(1)}s`;
|
|
10
|
+
const exitIcon = result.exitCode === 0 ? "✅" : "❌";
|
|
11
|
+
lines.push(`### SSH Execution [${result.sessionId}]`);
|
|
12
|
+
lines.push("");
|
|
13
|
+
// Command
|
|
14
|
+
lines.push(`**$ ${result.command}**`);
|
|
15
|
+
if (result.validation.level === "risky") {
|
|
16
|
+
lines.push(`⚠️ *Risky command — executed with user approval*`);
|
|
17
|
+
}
|
|
18
|
+
lines.push("");
|
|
19
|
+
// stdout
|
|
20
|
+
if (result.stdout) {
|
|
21
|
+
const trimmed = result.stdout.trim();
|
|
22
|
+
if (trimmed.length > 0) {
|
|
23
|
+
lines.push("**Output:**");
|
|
24
|
+
lines.push("```");
|
|
25
|
+
lines.push(trimmed);
|
|
26
|
+
lines.push("```");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// stderr
|
|
30
|
+
if (result.stderr) {
|
|
31
|
+
const trimmed = result.stderr.trim();
|
|
32
|
+
if (trimmed.length > 0) {
|
|
33
|
+
lines.push("**Errors:**");
|
|
34
|
+
lines.push("```");
|
|
35
|
+
lines.push(trimmed);
|
|
36
|
+
lines.push("```");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Footer with exit code and duration
|
|
40
|
+
lines.push(`${exitIcon} Exit: ${result.exitCode ?? "?"} | Duration: ${durationStr}`);
|
|
41
|
+
return lines.join("\n");
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Format a session list for display.
|
|
45
|
+
*/
|
|
46
|
+
export function formatSessionList(sessions) {
|
|
47
|
+
if (sessions.length === 0) {
|
|
48
|
+
return "📋 No active SSH sessions.";
|
|
49
|
+
}
|
|
50
|
+
const lines = [`## Active SSH Sessions (${sessions.length})\n`];
|
|
51
|
+
for (const session of sessions) {
|
|
52
|
+
const status = session.connected ? "🟢 Connected" : "🔴 Disconnected";
|
|
53
|
+
const alias = session.config.alias ? ` (${session.config.alias})` : "";
|
|
54
|
+
const uptime = session.connectedAt
|
|
55
|
+
? formatUptime(new Date(session.connectedAt))
|
|
56
|
+
: "N/A";
|
|
57
|
+
lines.push(`- **${session.id}**${alias}: ${session.config.username}@${session.config.host}:${session.config.port} — ${status}`);
|
|
58
|
+
lines.push(` Uptime: ${uptime} | Auth: ${session.config.authMethod}`);
|
|
59
|
+
lines.push("");
|
|
60
|
+
}
|
|
61
|
+
return lines.join("\n");
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Format a connection success message.
|
|
65
|
+
*/
|
|
66
|
+
export function formatConnectResult(sessionId, host, port, username, alias) {
|
|
67
|
+
const aliasStr = alias ? ` ("${alias}")` : "";
|
|
68
|
+
return [
|
|
69
|
+
`## SSH Connected${aliasStr}`,
|
|
70
|
+
"",
|
|
71
|
+
`- **Session:** \`${sessionId}\``,
|
|
72
|
+
`- **Host:** ${username}@${host}:${port}`,
|
|
73
|
+
`- **Status:** 🟢 Connected`,
|
|
74
|
+
"",
|
|
75
|
+
`Use \`ssh.exec\` with session_id=\`${sessionId}\` to run commands.`,
|
|
76
|
+
].join("\n");
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Format a disconnection message.
|
|
80
|
+
*/
|
|
81
|
+
export function formatDisconnectResult(sessionId) {
|
|
82
|
+
return `## SSH Disconnected\n\nSession \`${sessionId}\` has been closed.`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Format a blocked command message.
|
|
86
|
+
*/
|
|
87
|
+
export function formatBlockedCommand(command, reason, level) {
|
|
88
|
+
if (level === "destructive") {
|
|
89
|
+
return [
|
|
90
|
+
"## 🚫 Command Blocked (Destructive)",
|
|
91
|
+
"",
|
|
92
|
+
`**Command:** \`${command}\``,
|
|
93
|
+
`**Reason:** ${reason}`,
|
|
94
|
+
"",
|
|
95
|
+
"This command is **permanently blocked** and cannot be overridden.",
|
|
96
|
+
"Destructive commands are blocked for your safety.",
|
|
97
|
+
].join("\n");
|
|
98
|
+
}
|
|
99
|
+
return [
|
|
100
|
+
"## ⚠️ Command Requires Approval",
|
|
101
|
+
"",
|
|
102
|
+
`**Command:** \`${command}\``,
|
|
103
|
+
`**Reason:** ${reason}`,
|
|
104
|
+
"",
|
|
105
|
+
"This command has been classified as risky and requires your approval.",
|
|
106
|
+
].join("\n");
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Format a command check result (dry-run validation).
|
|
110
|
+
*/
|
|
111
|
+
export function formatCheckResult(command, validation) {
|
|
112
|
+
const icon = validation.safe ? "✅" : validation.level === "destructive" ? "🚫" : "⚠️";
|
|
113
|
+
const lines = [
|
|
114
|
+
`## Command Safety Check`,
|
|
115
|
+
"",
|
|
116
|
+
`**Command:** \`${command}\``,
|
|
117
|
+
`**Status:** ${icon} ${validation.safe ? "Safe" : validation.level === "destructive" ? "BLOCKED" : "Requires Approval"}`,
|
|
118
|
+
];
|
|
119
|
+
if (validation.reason) {
|
|
120
|
+
lines.push(`**Reason:** ${validation.reason}`);
|
|
121
|
+
}
|
|
122
|
+
if (validation.matched_rule) {
|
|
123
|
+
lines.push(`**Rule:** ${validation.matched_rule}`);
|
|
124
|
+
}
|
|
125
|
+
return lines.join("\n");
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Format a security policy for display.
|
|
129
|
+
*/
|
|
130
|
+
export function formatSecurityPolicy(policy) {
|
|
131
|
+
const lines = [
|
|
132
|
+
"## SSH Security Policy",
|
|
133
|
+
"",
|
|
134
|
+
`**Mode:** \`${policy.mode}\``,
|
|
135
|
+
`**Last Updated:** ${policy.updatedAt}`,
|
|
136
|
+
"",
|
|
137
|
+
];
|
|
138
|
+
if (policy.extraBlocklist.length > 0) {
|
|
139
|
+
lines.push("### Extra Blocklist Patterns");
|
|
140
|
+
for (const p of policy.extraBlocklist) {
|
|
141
|
+
lines.push(`- \`${p}\``);
|
|
142
|
+
}
|
|
143
|
+
lines.push("");
|
|
144
|
+
}
|
|
145
|
+
if (policy.customAllowlist.length > 0) {
|
|
146
|
+
lines.push("### Custom Allowlist Patterns");
|
|
147
|
+
for (const p of policy.customAllowlist) {
|
|
148
|
+
lines.push(`- \`${p}\``);
|
|
149
|
+
}
|
|
150
|
+
lines.push("");
|
|
151
|
+
}
|
|
152
|
+
lines.push("### Mode Description");
|
|
153
|
+
switch (policy.mode) {
|
|
154
|
+
case "full":
|
|
155
|
+
lines.push("All commands allowed except those in the blocklist.");
|
|
156
|
+
break;
|
|
157
|
+
case "restricted":
|
|
158
|
+
lines.push("Only commands in the allowlist + read-only commands are allowed.");
|
|
159
|
+
break;
|
|
160
|
+
case "read_only":
|
|
161
|
+
lines.push("Only read-only commands are allowed (ls, cat, grep, etc.).");
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
return lines.join("\n");
|
|
165
|
+
}
|
|
166
|
+
// ── Helpers ──
|
|
167
|
+
function formatUptime(connectedAt) {
|
|
168
|
+
const now = Date.now();
|
|
169
|
+
const diff = now - connectedAt.getTime();
|
|
170
|
+
const seconds = Math.floor(diff / 1000);
|
|
171
|
+
const minutes = Math.floor(seconds / 60);
|
|
172
|
+
const hours = Math.floor(minutes / 60);
|
|
173
|
+
if (hours > 0)
|
|
174
|
+
return `${hours}h ${minutes % 60}m`;
|
|
175
|
+
if (minutes > 0)
|
|
176
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
177
|
+
return `${seconds}s`;
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../src/display/formatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Real-time SSH output stream handler.
|
|
3
|
+
* Formats and prepares output chunks for display as they arrive.
|
|
4
|
+
*/
|
|
5
|
+
export interface StreamChunk {
|
|
6
|
+
/** Type of output */
|
|
7
|
+
type: "stdout" | "stderr" | "info" | "error";
|
|
8
|
+
/** The data chunk */
|
|
9
|
+
data: string;
|
|
10
|
+
/** Timestamp */
|
|
11
|
+
timestamp: number;
|
|
12
|
+
/** Session identifier */
|
|
13
|
+
sessionId: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Create a stream handler that collects and formats output chunks.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createStreamHandler(sessionId: string): {
|
|
19
|
+
chunks: StreamChunk[];
|
|
20
|
+
onStdout: (data: string) => void;
|
|
21
|
+
onStderr: (data: string) => void;
|
|
22
|
+
onInfo: (data: string) => void;
|
|
23
|
+
onError: (data: string) => void;
|
|
24
|
+
getOutput: () => {
|
|
25
|
+
stdout: string;
|
|
26
|
+
stderr: string;
|
|
27
|
+
};
|
|
28
|
+
formatOutput: () => string;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Format a progress indicator for long-running commands.
|
|
32
|
+
*/
|
|
33
|
+
export declare function formatProgress(sessionId: string, command: string, elapsed: number): string;
|
|
34
|
+
/**
|
|
35
|
+
* Format a timeout warning.
|
|
36
|
+
*/
|
|
37
|
+
export declare function formatTimeout(sessionId: string, command: string, timeout: number): string;
|
|
38
|
+
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/display/stream.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,WAAW;IAC1B,qBAAqB;IACrB,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAA;IAC5C,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,gBAAgB;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG;IACtD,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,SAAS,EAAE,MAAM;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACnD,YAAY,EAAE,MAAM,MAAM,CAAA;CAC3B,CAgFA;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAO1F;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAUzF"}
|