@agenshield/broker 0.1.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 +201 -0
- package/README.md +141 -0
- package/audit/logger.d.ts +69 -0
- package/audit/logger.d.ts.map +1 -0
- package/client/broker-client.d.ts +91 -0
- package/client/broker-client.d.ts.map +1 -0
- package/client/index.d.ts +8 -0
- package/client/index.d.ts.map +1 -0
- package/client/index.js +222 -0
- package/client/shield-client.d.ts +8 -0
- package/client/shield-client.d.ts.map +1 -0
- package/client/shield-client.js +410 -0
- package/handlers/exec.d.ts +13 -0
- package/handlers/exec.d.ts.map +1 -0
- package/handlers/file.d.ts +20 -0
- package/handlers/file.d.ts.map +1 -0
- package/handlers/http.d.ts +9 -0
- package/handlers/http.d.ts.map +1 -0
- package/handlers/index.d.ts +12 -0
- package/handlers/index.d.ts.map +1 -0
- package/handlers/open-url.d.ts +9 -0
- package/handlers/open-url.d.ts.map +1 -0
- package/handlers/ping.d.ts +9 -0
- package/handlers/ping.d.ts.map +1 -0
- package/handlers/secret-inject.d.ts +9 -0
- package/handlers/secret-inject.d.ts.map +1 -0
- package/handlers/skill-install.d.ts +17 -0
- package/handlers/skill-install.d.ts.map +1 -0
- package/handlers/types.d.ts +28 -0
- package/handlers/types.d.ts.map +1 -0
- package/http-fallback.d.ts +54 -0
- package/http-fallback.d.ts.map +1 -0
- package/index.d.ts +18 -0
- package/index.d.ts.map +1 -0
- package/index.js +2636 -0
- package/main.d.ts +8 -0
- package/main.d.ts.map +1 -0
- package/main.js +2136 -0
- package/package.json +34 -0
- package/policies/builtin.d.ts +15 -0
- package/policies/builtin.d.ts.map +1 -0
- package/policies/command-allowlist.d.ts +62 -0
- package/policies/command-allowlist.d.ts.map +1 -0
- package/policies/enforcer.d.ts +98 -0
- package/policies/enforcer.d.ts.map +1 -0
- package/policies/index.d.ts +8 -0
- package/policies/index.d.ts.map +1 -0
- package/seatbelt/generator.d.ts +39 -0
- package/seatbelt/generator.d.ts.map +1 -0
- package/seatbelt/templates.d.ts +36 -0
- package/seatbelt/templates.d.ts.map +1 -0
- package/secrets/vault.d.ts +67 -0
- package/secrets/vault.d.ts.map +1 -0
- package/server.d.ts +54 -0
- package/server.d.ts.map +1 -0
- package/types.d.ts +285 -0
- package/types.d.ts.map +1 -0
package/client/index.js
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
// libs/shield-broker/src/client/broker-client.ts
|
|
2
|
+
import * as net from "node:net";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
var BrokerClient = class {
|
|
5
|
+
socketPath;
|
|
6
|
+
httpHost;
|
|
7
|
+
httpPort;
|
|
8
|
+
timeout;
|
|
9
|
+
preferSocket;
|
|
10
|
+
constructor(options = {}) {
|
|
11
|
+
this.socketPath = options.socketPath || "/var/run/agenshield/agenshield.sock";
|
|
12
|
+
this.httpHost = options.httpHost || "localhost";
|
|
13
|
+
this.httpPort = options.httpPort || 5201;
|
|
14
|
+
this.timeout = options.timeout || 3e4;
|
|
15
|
+
this.preferSocket = options.preferSocket ?? true;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Make an HTTP request through the broker
|
|
19
|
+
*/
|
|
20
|
+
async httpRequest(params, options) {
|
|
21
|
+
return this.request("http_request", params, options);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read a file through the broker
|
|
25
|
+
*/
|
|
26
|
+
async fileRead(params, options) {
|
|
27
|
+
return this.request("file_read", params, options);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Write a file through the broker
|
|
31
|
+
*/
|
|
32
|
+
async fileWrite(params, options) {
|
|
33
|
+
return this.request("file_write", params, {
|
|
34
|
+
...options,
|
|
35
|
+
channel: "socket"
|
|
36
|
+
// file_write only allowed via socket
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* List files through the broker
|
|
41
|
+
*/
|
|
42
|
+
async fileList(params, options) {
|
|
43
|
+
return this.request("file_list", params, options);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Execute a command through the broker
|
|
47
|
+
*/
|
|
48
|
+
async exec(params, options) {
|
|
49
|
+
return this.request("exec", params, {
|
|
50
|
+
...options,
|
|
51
|
+
channel: "socket"
|
|
52
|
+
// exec only allowed via socket
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Open a URL through the broker
|
|
57
|
+
*/
|
|
58
|
+
async openUrl(params, options) {
|
|
59
|
+
return this.request("open_url", params, options);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Inject a secret through the broker
|
|
63
|
+
*/
|
|
64
|
+
async secretInject(params, options) {
|
|
65
|
+
return this.request("secret_inject", params, {
|
|
66
|
+
...options,
|
|
67
|
+
channel: "socket"
|
|
68
|
+
// secret_inject only allowed via socket
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Ping the broker
|
|
73
|
+
*/
|
|
74
|
+
async ping(echo, options) {
|
|
75
|
+
return this.request("ping", { echo }, options);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Install a skill through the broker
|
|
79
|
+
* Socket-only operation due to privileged file operations
|
|
80
|
+
*/
|
|
81
|
+
async skillInstall(params, options) {
|
|
82
|
+
return this.request("skill_install", params, {
|
|
83
|
+
...options,
|
|
84
|
+
channel: "socket"
|
|
85
|
+
// skill_install only allowed via socket
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Uninstall a skill through the broker
|
|
90
|
+
* Socket-only operation due to privileged file operations
|
|
91
|
+
*/
|
|
92
|
+
async skillUninstall(params, options) {
|
|
93
|
+
return this.request("skill_uninstall", params, {
|
|
94
|
+
...options,
|
|
95
|
+
channel: "socket"
|
|
96
|
+
// skill_uninstall only allowed via socket
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Check if the broker is available
|
|
101
|
+
*/
|
|
102
|
+
async isAvailable() {
|
|
103
|
+
try {
|
|
104
|
+
await this.ping();
|
|
105
|
+
return true;
|
|
106
|
+
} catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Make a request to the broker
|
|
112
|
+
*/
|
|
113
|
+
async request(method, params, options) {
|
|
114
|
+
const channel = options?.channel || (this.preferSocket ? "socket" : "http");
|
|
115
|
+
const timeout = options?.timeout || this.timeout;
|
|
116
|
+
if (channel === "socket") {
|
|
117
|
+
try {
|
|
118
|
+
return await this.socketRequest(method, params, timeout);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
if (!options?.channel) {
|
|
121
|
+
return await this.httpRequest_internal(method, params, timeout);
|
|
122
|
+
}
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
return await this.httpRequest_internal(method, params, timeout);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Make a request via Unix socket
|
|
131
|
+
*/
|
|
132
|
+
async socketRequest(method, params, timeout) {
|
|
133
|
+
return new Promise((resolve, reject) => {
|
|
134
|
+
const socket = net.createConnection(this.socketPath);
|
|
135
|
+
const id = randomUUID();
|
|
136
|
+
let responseData = "";
|
|
137
|
+
let timeoutId;
|
|
138
|
+
socket.on("connect", () => {
|
|
139
|
+
const request = {
|
|
140
|
+
jsonrpc: "2.0",
|
|
141
|
+
id,
|
|
142
|
+
method,
|
|
143
|
+
params
|
|
144
|
+
};
|
|
145
|
+
socket.write(JSON.stringify(request) + "\n");
|
|
146
|
+
timeoutId = setTimeout(() => {
|
|
147
|
+
socket.destroy();
|
|
148
|
+
reject(new Error("Request timeout"));
|
|
149
|
+
}, timeout);
|
|
150
|
+
});
|
|
151
|
+
socket.on("data", (data) => {
|
|
152
|
+
responseData += data.toString();
|
|
153
|
+
const newlineIndex = responseData.indexOf("\n");
|
|
154
|
+
if (newlineIndex !== -1) {
|
|
155
|
+
clearTimeout(timeoutId);
|
|
156
|
+
socket.end();
|
|
157
|
+
try {
|
|
158
|
+
const response = JSON.parse(
|
|
159
|
+
responseData.slice(0, newlineIndex)
|
|
160
|
+
);
|
|
161
|
+
if (response.error) {
|
|
162
|
+
const error = new Error(response.error.message);
|
|
163
|
+
error.code = response.error.code;
|
|
164
|
+
reject(error);
|
|
165
|
+
} else {
|
|
166
|
+
resolve(response.result);
|
|
167
|
+
}
|
|
168
|
+
} catch (error) {
|
|
169
|
+
reject(new Error("Invalid response from broker"));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
socket.on("error", (error) => {
|
|
174
|
+
clearTimeout(timeoutId);
|
|
175
|
+
reject(error);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Make a request via HTTP
|
|
181
|
+
*/
|
|
182
|
+
async httpRequest_internal(method, params, timeout) {
|
|
183
|
+
const url = `http://${this.httpHost}:${this.httpPort}/rpc`;
|
|
184
|
+
const id = randomUUID();
|
|
185
|
+
const request = {
|
|
186
|
+
jsonrpc: "2.0",
|
|
187
|
+
id,
|
|
188
|
+
method,
|
|
189
|
+
params
|
|
190
|
+
};
|
|
191
|
+
const controller = new AbortController();
|
|
192
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
193
|
+
try {
|
|
194
|
+
const response = await fetch(url, {
|
|
195
|
+
method: "POST",
|
|
196
|
+
headers: { "Content-Type": "application/json" },
|
|
197
|
+
body: JSON.stringify(request),
|
|
198
|
+
signal: controller.signal
|
|
199
|
+
});
|
|
200
|
+
clearTimeout(timeoutId);
|
|
201
|
+
if (!response.ok) {
|
|
202
|
+
throw new Error(`HTTP error: ${response.status}`);
|
|
203
|
+
}
|
|
204
|
+
const jsonResponse = await response.json();
|
|
205
|
+
if (jsonResponse.error) {
|
|
206
|
+
const error = new Error(jsonResponse.error.message);
|
|
207
|
+
error.code = jsonResponse.error.code;
|
|
208
|
+
throw error;
|
|
209
|
+
}
|
|
210
|
+
return jsonResponse.result;
|
|
211
|
+
} catch (error) {
|
|
212
|
+
clearTimeout(timeoutId);
|
|
213
|
+
if (error.name === "AbortError") {
|
|
214
|
+
throw new Error("Request timeout");
|
|
215
|
+
}
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
export {
|
|
221
|
+
BrokerClient
|
|
222
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shield-client.d.ts","sourceRoot":"","sources":["../../src/client/shield-client.ts"],"names":[],"mappings":";AACA;;;;GAIG"}
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// libs/shield-broker/src/client/broker-client.ts
|
|
4
|
+
import * as net from "node:net";
|
|
5
|
+
import { randomUUID } from "node:crypto";
|
|
6
|
+
var BrokerClient = class {
|
|
7
|
+
socketPath;
|
|
8
|
+
httpHost;
|
|
9
|
+
httpPort;
|
|
10
|
+
timeout;
|
|
11
|
+
preferSocket;
|
|
12
|
+
constructor(options = {}) {
|
|
13
|
+
this.socketPath = options.socketPath || "/var/run/agenshield/agenshield.sock";
|
|
14
|
+
this.httpHost = options.httpHost || "localhost";
|
|
15
|
+
this.httpPort = options.httpPort || 5201;
|
|
16
|
+
this.timeout = options.timeout || 3e4;
|
|
17
|
+
this.preferSocket = options.preferSocket ?? true;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Make an HTTP request through the broker
|
|
21
|
+
*/
|
|
22
|
+
async httpRequest(params, options) {
|
|
23
|
+
return this.request("http_request", params, options);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Read a file through the broker
|
|
27
|
+
*/
|
|
28
|
+
async fileRead(params, options) {
|
|
29
|
+
return this.request("file_read", params, options);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Write a file through the broker
|
|
33
|
+
*/
|
|
34
|
+
async fileWrite(params, options) {
|
|
35
|
+
return this.request("file_write", params, {
|
|
36
|
+
...options,
|
|
37
|
+
channel: "socket"
|
|
38
|
+
// file_write only allowed via socket
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* List files through the broker
|
|
43
|
+
*/
|
|
44
|
+
async fileList(params, options) {
|
|
45
|
+
return this.request("file_list", params, options);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Execute a command through the broker
|
|
49
|
+
*/
|
|
50
|
+
async exec(params, options) {
|
|
51
|
+
return this.request("exec", params, {
|
|
52
|
+
...options,
|
|
53
|
+
channel: "socket"
|
|
54
|
+
// exec only allowed via socket
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Open a URL through the broker
|
|
59
|
+
*/
|
|
60
|
+
async openUrl(params, options) {
|
|
61
|
+
return this.request("open_url", params, options);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Inject a secret through the broker
|
|
65
|
+
*/
|
|
66
|
+
async secretInject(params, options) {
|
|
67
|
+
return this.request("secret_inject", params, {
|
|
68
|
+
...options,
|
|
69
|
+
channel: "socket"
|
|
70
|
+
// secret_inject only allowed via socket
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Ping the broker
|
|
75
|
+
*/
|
|
76
|
+
async ping(echo, options) {
|
|
77
|
+
return this.request("ping", { echo }, options);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Install a skill through the broker
|
|
81
|
+
* Socket-only operation due to privileged file operations
|
|
82
|
+
*/
|
|
83
|
+
async skillInstall(params, options) {
|
|
84
|
+
return this.request("skill_install", params, {
|
|
85
|
+
...options,
|
|
86
|
+
channel: "socket"
|
|
87
|
+
// skill_install only allowed via socket
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Uninstall a skill through the broker
|
|
92
|
+
* Socket-only operation due to privileged file operations
|
|
93
|
+
*/
|
|
94
|
+
async skillUninstall(params, options) {
|
|
95
|
+
return this.request("skill_uninstall", params, {
|
|
96
|
+
...options,
|
|
97
|
+
channel: "socket"
|
|
98
|
+
// skill_uninstall only allowed via socket
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Check if the broker is available
|
|
103
|
+
*/
|
|
104
|
+
async isAvailable() {
|
|
105
|
+
try {
|
|
106
|
+
await this.ping();
|
|
107
|
+
return true;
|
|
108
|
+
} catch {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Make a request to the broker
|
|
114
|
+
*/
|
|
115
|
+
async request(method, params, options) {
|
|
116
|
+
const channel = options?.channel || (this.preferSocket ? "socket" : "http");
|
|
117
|
+
const timeout = options?.timeout || this.timeout;
|
|
118
|
+
if (channel === "socket") {
|
|
119
|
+
try {
|
|
120
|
+
return await this.socketRequest(method, params, timeout);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (!options?.channel) {
|
|
123
|
+
return await this.httpRequest_internal(method, params, timeout);
|
|
124
|
+
}
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
return await this.httpRequest_internal(method, params, timeout);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Make a request via Unix socket
|
|
133
|
+
*/
|
|
134
|
+
async socketRequest(method, params, timeout) {
|
|
135
|
+
return new Promise((resolve, reject) => {
|
|
136
|
+
const socket = net.createConnection(this.socketPath);
|
|
137
|
+
const id = randomUUID();
|
|
138
|
+
let responseData = "";
|
|
139
|
+
let timeoutId;
|
|
140
|
+
socket.on("connect", () => {
|
|
141
|
+
const request = {
|
|
142
|
+
jsonrpc: "2.0",
|
|
143
|
+
id,
|
|
144
|
+
method,
|
|
145
|
+
params
|
|
146
|
+
};
|
|
147
|
+
socket.write(JSON.stringify(request) + "\n");
|
|
148
|
+
timeoutId = setTimeout(() => {
|
|
149
|
+
socket.destroy();
|
|
150
|
+
reject(new Error("Request timeout"));
|
|
151
|
+
}, timeout);
|
|
152
|
+
});
|
|
153
|
+
socket.on("data", (data) => {
|
|
154
|
+
responseData += data.toString();
|
|
155
|
+
const newlineIndex = responseData.indexOf("\n");
|
|
156
|
+
if (newlineIndex !== -1) {
|
|
157
|
+
clearTimeout(timeoutId);
|
|
158
|
+
socket.end();
|
|
159
|
+
try {
|
|
160
|
+
const response = JSON.parse(
|
|
161
|
+
responseData.slice(0, newlineIndex)
|
|
162
|
+
);
|
|
163
|
+
if (response.error) {
|
|
164
|
+
const error = new Error(response.error.message);
|
|
165
|
+
error.code = response.error.code;
|
|
166
|
+
reject(error);
|
|
167
|
+
} else {
|
|
168
|
+
resolve(response.result);
|
|
169
|
+
}
|
|
170
|
+
} catch (error) {
|
|
171
|
+
reject(new Error("Invalid response from broker"));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
socket.on("error", (error) => {
|
|
176
|
+
clearTimeout(timeoutId);
|
|
177
|
+
reject(error);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Make a request via HTTP
|
|
183
|
+
*/
|
|
184
|
+
async httpRequest_internal(method, params, timeout) {
|
|
185
|
+
const url = `http://${this.httpHost}:${this.httpPort}/rpc`;
|
|
186
|
+
const id = randomUUID();
|
|
187
|
+
const request = {
|
|
188
|
+
jsonrpc: "2.0",
|
|
189
|
+
id,
|
|
190
|
+
method,
|
|
191
|
+
params
|
|
192
|
+
};
|
|
193
|
+
const controller = new AbortController();
|
|
194
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
195
|
+
try {
|
|
196
|
+
const response = await fetch(url, {
|
|
197
|
+
method: "POST",
|
|
198
|
+
headers: { "Content-Type": "application/json" },
|
|
199
|
+
body: JSON.stringify(request),
|
|
200
|
+
signal: controller.signal
|
|
201
|
+
});
|
|
202
|
+
clearTimeout(timeoutId);
|
|
203
|
+
if (!response.ok) {
|
|
204
|
+
throw new Error(`HTTP error: ${response.status}`);
|
|
205
|
+
}
|
|
206
|
+
const jsonResponse = await response.json();
|
|
207
|
+
if (jsonResponse.error) {
|
|
208
|
+
const error = new Error(jsonResponse.error.message);
|
|
209
|
+
error.code = jsonResponse.error.code;
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
return jsonResponse.result;
|
|
213
|
+
} catch (error) {
|
|
214
|
+
clearTimeout(timeoutId);
|
|
215
|
+
if (error.name === "AbortError") {
|
|
216
|
+
throw new Error("Request timeout");
|
|
217
|
+
}
|
|
218
|
+
throw error;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
// libs/shield-broker/src/client/shield-client.ts
|
|
224
|
+
var client = new BrokerClient({
|
|
225
|
+
socketPath: process.env["AGENSHIELD_SOCKET"] || "/var/run/agenshield/agenshield.sock",
|
|
226
|
+
httpHost: process.env["AGENSHIELD_HTTP_HOST"] || "localhost",
|
|
227
|
+
httpPort: parseInt(process.env["AGENSHIELD_HTTP_PORT"] || "5201", 10)
|
|
228
|
+
});
|
|
229
|
+
async function main() {
|
|
230
|
+
const args = process.argv.slice(2);
|
|
231
|
+
const command = args[0];
|
|
232
|
+
if (!command || command === "help" || command === "--help" || command === "-h") {
|
|
233
|
+
printHelp();
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
switch (command) {
|
|
238
|
+
case "ping":
|
|
239
|
+
await handlePing(args.slice(1));
|
|
240
|
+
break;
|
|
241
|
+
case "http":
|
|
242
|
+
await handleHttp(args.slice(1));
|
|
243
|
+
break;
|
|
244
|
+
case "file":
|
|
245
|
+
await handleFile(args.slice(1));
|
|
246
|
+
break;
|
|
247
|
+
case "exec":
|
|
248
|
+
await handleExec(args.slice(1));
|
|
249
|
+
break;
|
|
250
|
+
case "open":
|
|
251
|
+
await handleOpen(args.slice(1));
|
|
252
|
+
break;
|
|
253
|
+
case "secret":
|
|
254
|
+
await handleSecret(args.slice(1));
|
|
255
|
+
break;
|
|
256
|
+
default:
|
|
257
|
+
console.error(`Unknown command: ${command}`);
|
|
258
|
+
printHelp();
|
|
259
|
+
process.exit(1);
|
|
260
|
+
}
|
|
261
|
+
} catch (error) {
|
|
262
|
+
console.error("Error:", error.message);
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function printHelp() {
|
|
267
|
+
console.log(`
|
|
268
|
+
Shield Client - AgenShield Broker CLI
|
|
269
|
+
|
|
270
|
+
Usage: shield-client <command> [options]
|
|
271
|
+
|
|
272
|
+
Commands:
|
|
273
|
+
ping [message] Ping the broker
|
|
274
|
+
http <method> <url> [body] Make an HTTP request
|
|
275
|
+
file read <path> Read a file
|
|
276
|
+
file write <path> <content> Write a file
|
|
277
|
+
file list <path> [--recursive] List directory contents
|
|
278
|
+
exec <command> [args...] Execute a command
|
|
279
|
+
open <url> Open a URL in the browser
|
|
280
|
+
secret get <name> Get a secret value
|
|
281
|
+
|
|
282
|
+
Environment:
|
|
283
|
+
AGENSHIELD_SOCKET Unix socket path (default: /var/run/agenshield/agenshield.sock)
|
|
284
|
+
AGENSHIELD_HTTP_HOST HTTP fallback host (default: localhost)
|
|
285
|
+
AGENSHIELD_HTTP_PORT HTTP fallback port (default: 5201)
|
|
286
|
+
|
|
287
|
+
Examples:
|
|
288
|
+
shield-client ping
|
|
289
|
+
shield-client http GET https://api.example.com/data
|
|
290
|
+
shield-client file read /path/to/file.txt
|
|
291
|
+
shield-client exec ls -la
|
|
292
|
+
shield-client open https://example.com
|
|
293
|
+
`);
|
|
294
|
+
}
|
|
295
|
+
async function handlePing(args) {
|
|
296
|
+
const echo = args[0];
|
|
297
|
+
const result = await client.ping(echo);
|
|
298
|
+
console.log("Pong!");
|
|
299
|
+
console.log(` Version: ${result.version}`);
|
|
300
|
+
console.log(` Timestamp: ${result.timestamp}`);
|
|
301
|
+
if (result.echo) {
|
|
302
|
+
console.log(` Echo: ${result.echo}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
async function handleHttp(args) {
|
|
306
|
+
const method = args[0]?.toUpperCase();
|
|
307
|
+
const url = args[1];
|
|
308
|
+
const body = args[2];
|
|
309
|
+
if (!method || !url) {
|
|
310
|
+
console.error("Usage: shield-client http <method> <url> [body]");
|
|
311
|
+
process.exit(1);
|
|
312
|
+
}
|
|
313
|
+
const result = await client.httpRequest({
|
|
314
|
+
url,
|
|
315
|
+
method,
|
|
316
|
+
body
|
|
317
|
+
});
|
|
318
|
+
console.log(`Status: ${result.status} ${result.statusText}`);
|
|
319
|
+
console.log("Headers:");
|
|
320
|
+
for (const [key, value] of Object.entries(result.headers)) {
|
|
321
|
+
console.log(` ${key}: ${value}`);
|
|
322
|
+
}
|
|
323
|
+
console.log("\nBody:");
|
|
324
|
+
console.log(result.body);
|
|
325
|
+
}
|
|
326
|
+
async function handleFile(args) {
|
|
327
|
+
const subcommand = args[0];
|
|
328
|
+
switch (subcommand) {
|
|
329
|
+
case "read": {
|
|
330
|
+
const path = args[1];
|
|
331
|
+
if (!path) {
|
|
332
|
+
console.error("Usage: shield-client file read <path>");
|
|
333
|
+
process.exit(1);
|
|
334
|
+
}
|
|
335
|
+
const result = await client.fileRead({ path });
|
|
336
|
+
console.log(result.content);
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
case "write": {
|
|
340
|
+
const path = args[1];
|
|
341
|
+
const content = args.slice(2).join(" ");
|
|
342
|
+
if (!path || !content) {
|
|
343
|
+
console.error("Usage: shield-client file write <path> <content>");
|
|
344
|
+
process.exit(1);
|
|
345
|
+
}
|
|
346
|
+
const result = await client.fileWrite({ path, content });
|
|
347
|
+
console.log(`Wrote ${result.bytesWritten} bytes to ${result.path}`);
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
case "list": {
|
|
351
|
+
const path = args[1] || ".";
|
|
352
|
+
const recursive = args.includes("--recursive") || args.includes("-r");
|
|
353
|
+
const result = await client.fileList({ path, recursive });
|
|
354
|
+
for (const entry of result.entries) {
|
|
355
|
+
const typeChar = entry.type === "directory" ? "d" : entry.type === "symlink" ? "l" : "-";
|
|
356
|
+
console.log(`${typeChar} ${entry.size.toString().padStart(10)} ${entry.name}`);
|
|
357
|
+
}
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
default:
|
|
361
|
+
console.error("Usage: shield-client file <read|write|list> [options]");
|
|
362
|
+
process.exit(1);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
async function handleExec(args) {
|
|
366
|
+
const command = args[0];
|
|
367
|
+
const commandArgs = args.slice(1);
|
|
368
|
+
if (!command) {
|
|
369
|
+
console.error("Usage: shield-client exec <command> [args...]");
|
|
370
|
+
process.exit(1);
|
|
371
|
+
}
|
|
372
|
+
const result = await client.exec({
|
|
373
|
+
command,
|
|
374
|
+
args: commandArgs
|
|
375
|
+
});
|
|
376
|
+
if (result.stdout) {
|
|
377
|
+
process.stdout.write(result.stdout);
|
|
378
|
+
}
|
|
379
|
+
if (result.stderr) {
|
|
380
|
+
process.stderr.write(result.stderr);
|
|
381
|
+
}
|
|
382
|
+
process.exit(result.exitCode);
|
|
383
|
+
}
|
|
384
|
+
async function handleOpen(args) {
|
|
385
|
+
const url = args[0];
|
|
386
|
+
if (!url) {
|
|
387
|
+
console.error("Usage: shield-client open <url>");
|
|
388
|
+
process.exit(1);
|
|
389
|
+
}
|
|
390
|
+
const result = await client.openUrl({ url });
|
|
391
|
+
console.log(result.opened ? "URL opened successfully" : "Failed to open URL");
|
|
392
|
+
}
|
|
393
|
+
async function handleSecret(args) {
|
|
394
|
+
const subcommand = args[0];
|
|
395
|
+
if (subcommand !== "get") {
|
|
396
|
+
console.error("Usage: shield-client secret get <name>");
|
|
397
|
+
process.exit(1);
|
|
398
|
+
}
|
|
399
|
+
const name = args[1];
|
|
400
|
+
if (!name) {
|
|
401
|
+
console.error("Usage: shield-client secret get <name>");
|
|
402
|
+
process.exit(1);
|
|
403
|
+
}
|
|
404
|
+
const result = await client.secretInject({ name });
|
|
405
|
+
console.log(result.value);
|
|
406
|
+
}
|
|
407
|
+
main().catch((error) => {
|
|
408
|
+
console.error("Fatal error:", error);
|
|
409
|
+
process.exit(1);
|
|
410
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exec Handler
|
|
3
|
+
*
|
|
4
|
+
* Handles command execution operations with:
|
|
5
|
+
* - Command allowlist validation (static + dynamic via CommandAllowlist)
|
|
6
|
+
* - Workspace path enforcement for FS commands
|
|
7
|
+
* - URL policy validation for curl/wget
|
|
8
|
+
* - Exec monitoring via SSE events
|
|
9
|
+
*/
|
|
10
|
+
import type { HandlerContext, HandlerResult, ExecResult } from '../types.js';
|
|
11
|
+
import type { HandlerDependencies } from './types.js';
|
|
12
|
+
export declare function handleExec(params: Record<string, unknown>, context: HandlerContext, deps: HandlerDependencies): Promise<HandlerResult<ExecResult>>;
|
|
13
|
+
//# sourceMappingURL=exec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/handlers/exec.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAc,UAAU,EAAE,MAAM,aAAa,CAAC;AACzF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AA+FtD,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CA0GpC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Operation Handlers
|
|
3
|
+
*
|
|
4
|
+
* Handles file read, write, and list operations.
|
|
5
|
+
*/
|
|
6
|
+
import type { HandlerContext, HandlerResult, FileReadResult, FileWriteResult, FileListResult } from '../types.js';
|
|
7
|
+
import type { HandlerDependencies } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Handle file read operation
|
|
10
|
+
*/
|
|
11
|
+
export declare function handleFileRead(params: Record<string, unknown>, context: HandlerContext, deps: HandlerDependencies): Promise<HandlerResult<FileReadResult>>;
|
|
12
|
+
/**
|
|
13
|
+
* Handle file write operation
|
|
14
|
+
*/
|
|
15
|
+
export declare function handleFileWrite(params: Record<string, unknown>, context: HandlerContext, deps: HandlerDependencies): Promise<HandlerResult<FileWriteResult>>;
|
|
16
|
+
/**
|
|
17
|
+
* Handle file list operation
|
|
18
|
+
*/
|
|
19
|
+
export declare function handleFileList(params: Record<string, unknown>, context: HandlerContext, deps: HandlerDependencies): Promise<HandlerResult<FileListResult>>;
|
|
20
|
+
//# sourceMappingURL=file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/handlers/file.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAEb,cAAc,EAEd,eAAe,EAEf,cAAc,EACf,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAyDxC;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAqDzC;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAkDxC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Request Handler
|
|
3
|
+
*
|
|
4
|
+
* Proxies HTTP requests through the broker.
|
|
5
|
+
*/
|
|
6
|
+
import type { HandlerContext, HandlerResult, HttpRequestResult } from '../types.js';
|
|
7
|
+
import type { HandlerDependencies } from './types.js';
|
|
8
|
+
export declare function handleHttpRequest(params: Record<string, unknown>, context: HandlerContext, deps: HandlerDependencies): Promise<HandlerResult<HttpRequestResult>>;
|
|
9
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/handlers/http.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAqB,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACvG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAyF3C"}
|