@agentsh/secure-sandbox 0.1.5 → 0.1.7
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/README.md +45 -11
- package/dist/adapters/blaxel.d.ts +1 -1
- package/dist/adapters/cloudflare.d.ts +1 -1
- package/dist/adapters/daytona.d.ts +1 -1
- package/dist/adapters/e2b.d.ts +1 -1
- package/dist/adapters/index.d.ts +2 -1
- package/dist/adapters/index.js +11 -1
- package/dist/adapters/vercel.d.ts +1 -1
- package/dist/chunk-4FJHYLAB.js +251 -0
- package/dist/chunk-4FJHYLAB.js.map +1 -0
- package/dist/chunk-5IG6ABIZ.js +268 -0
- package/dist/chunk-5IG6ABIZ.js.map +1 -0
- package/dist/{chunk-GFPHTJLU.js → chunk-LNDICGZU.js} +3 -243
- package/dist/chunk-LNDICGZU.js.map +1 -0
- package/dist/index-TyzWAIUD.d.ts +60 -0
- package/dist/index.d.ts +5 -11
- package/dist/index.js +209 -43
- package/dist/index.js.map +1 -1
- package/dist/policies/index.d.ts +1 -1
- package/dist/policies/index.js +5 -3
- package/dist/testing/index.d.ts +1 -1
- package/dist/{types-CUqsllMs.d.ts → types-DFMGk2GV.d.ts} +127 -2
- package/package.json +19 -1
- package/dist/chunk-GFPHTJLU.js.map +0 -1
- package/dist/chunk-L4KFLVNU.js +0 -33
- package/dist/chunk-L4KFLVNU.js.map +0 -1
- package/dist/index-aQ1TVPtG.d.ts +0 -16
- package/dist/{index-Nmlhw9oj.d.ts → index-CedRtlB6.d.ts} +22 -22
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { vercel } from './adapters/vercel.js';
|
|
2
|
+
import { e2b } from './adapters/e2b.js';
|
|
3
|
+
import { daytona } from './adapters/daytona.js';
|
|
4
|
+
import { cloudflare } from './adapters/cloudflare.js';
|
|
5
|
+
import { blaxel } from './adapters/blaxel.js';
|
|
6
|
+
import { S as SandboxAdapter, a as SecureConfig } from './types-DFMGk2GV.js';
|
|
7
|
+
|
|
8
|
+
declare function sprites(sprite: any): SandboxAdapter;
|
|
9
|
+
/**
|
|
10
|
+
* Returns Sprites-optimized defaults for SecureConfig.
|
|
11
|
+
* Spread into your secureSandbox() call:
|
|
12
|
+
*
|
|
13
|
+
* secureSandbox(sprites(s), { ...spritesDefaults(), ...yourOverrides })
|
|
14
|
+
*/
|
|
15
|
+
declare function spritesDefaults(): Partial<SecureConfig>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Wraps a Modal Sandbox object into a SandboxAdapter.
|
|
19
|
+
*
|
|
20
|
+
* Modal sandboxes run on gVisor which lacks seccomp user-notify and
|
|
21
|
+
* full FUSE support. Use `modalDefaults()` to get ptrace-optimized
|
|
22
|
+
* configuration that works on gVisor.
|
|
23
|
+
*
|
|
24
|
+
* The `sandbox` parameter is typed as `any` to avoid a hard dependency
|
|
25
|
+
* on the Modal SDK — pass any object whose `.exec()` accepts variadic
|
|
26
|
+
* string arguments and returns a process with `.stdout.read()`,
|
|
27
|
+
* `.stderr.read()`, `.returncode`, and `.wait()`.
|
|
28
|
+
*/
|
|
29
|
+
declare function modal(sandbox: any): SandboxAdapter;
|
|
30
|
+
/**
|
|
31
|
+
* Returns Modal-optimized defaults for SecureConfig.
|
|
32
|
+
*
|
|
33
|
+
* Key differences from other providers:
|
|
34
|
+
* - ptrace enabled (gVisor blocks seccomp user-notify)
|
|
35
|
+
* - seccomp_prefilter disabled (gVisor blocks BPF injection)
|
|
36
|
+
* - FUSE deferred (may not be available on gVisor)
|
|
37
|
+
* - unix_sockets disabled (mutually exclusive with ptrace)
|
|
38
|
+
* - cgroups disabled (Modal handles resource limits)
|
|
39
|
+
* - allow_degraded enabled (graceful fallback for FUSE/seccomp)
|
|
40
|
+
*
|
|
41
|
+
* Spread into your secureSandbox() call:
|
|
42
|
+
*
|
|
43
|
+
* secureSandbox(modal(sb), { ...modalDefaults(), ...yourOverrides })
|
|
44
|
+
*/
|
|
45
|
+
declare function modalDefaults(): Partial<SecureConfig>;
|
|
46
|
+
|
|
47
|
+
declare const index_blaxel: typeof blaxel;
|
|
48
|
+
declare const index_cloudflare: typeof cloudflare;
|
|
49
|
+
declare const index_daytona: typeof daytona;
|
|
50
|
+
declare const index_e2b: typeof e2b;
|
|
51
|
+
declare const index_modal: typeof modal;
|
|
52
|
+
declare const index_modalDefaults: typeof modalDefaults;
|
|
53
|
+
declare const index_sprites: typeof sprites;
|
|
54
|
+
declare const index_spritesDefaults: typeof spritesDefaults;
|
|
55
|
+
declare const index_vercel: typeof vercel;
|
|
56
|
+
declare namespace index {
|
|
57
|
+
export { index_blaxel as blaxel, index_cloudflare as cloudflare, index_daytona as daytona, index_e2b as e2b, index_modal as modal, index_modalDefaults as modalDefaults, index_sprites as sprites, index_spritesDefaults as spritesDefaults, index_vercel as vercel };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { modalDefaults as a, spritesDefaults as b, index as i, modal as m, sprites as s };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { S as SandboxAdapter, a as SecureConfig, b as SecuredSandbox
|
|
2
|
-
export { E as ExecResult, I as InstallStrategy, L as LicenseSpdxMatch, P as PackageChecksConfig, c as PackageMatch, d as PackageRule, e as ProviderConfig, R as ReadFileResult, f as SecurityMode,
|
|
3
|
-
export { P as PolicyDefinition, i as policies } from './index-
|
|
1
|
+
import { S as SandboxAdapter, a as SecureConfig, b as SecuredSandbox } from './types-DFMGk2GV.js';
|
|
2
|
+
export { E as ExecResult, I as InstallStrategy, L as LicenseSpdxMatch, P as PackageChecksConfig, c as PackageMatch, d as PackageRule, e as ProviderConfig, R as ReadFileResult, f as SecurityMode, T as ThreatFeed, g as ThreatFeedsConfig, W as WriteFileResult, h as defaultThreatFeeds } from './types-DFMGk2GV.js';
|
|
3
|
+
export { P as PolicyDefinition, i as policies } from './index-CedRtlB6.js';
|
|
4
4
|
import { ZodIssue } from 'zod';
|
|
5
|
-
export { i as adapters } from './index-
|
|
5
|
+
export { i as adapters } from './index-TyzWAIUD.js';
|
|
6
6
|
import './adapters/vercel.js';
|
|
7
7
|
import './adapters/e2b.js';
|
|
8
8
|
import './adapters/daytona.js';
|
|
@@ -11,12 +11,6 @@ import './adapters/blaxel.js';
|
|
|
11
11
|
|
|
12
12
|
declare function secureSandbox(adapter: SandboxAdapter, config?: SecureConfig): Promise<SecuredSandbox>;
|
|
13
13
|
|
|
14
|
-
/**
|
|
15
|
-
* Default threat feeds: URLhaus (malware) + Phishing.Database (phishing).
|
|
16
|
-
* Both are free, open source, and updated frequently.
|
|
17
|
-
*/
|
|
18
|
-
declare const defaultThreatFeeds: ThreatFeedsConfig;
|
|
19
|
-
|
|
20
14
|
declare class AgentSHError extends Error {
|
|
21
15
|
constructor(message: string);
|
|
22
16
|
}
|
|
@@ -74,4 +68,4 @@ declare class RuntimeError extends AgentSHError {
|
|
|
74
68
|
});
|
|
75
69
|
}
|
|
76
70
|
|
|
77
|
-
export { AgentSHError, IncompatibleProviderVersionError, IntegrityError, MissingPeerDependencyError, PolicyValidationError, ProvisioningError, RuntimeError, SandboxAdapter, SecureConfig, SecuredSandbox,
|
|
71
|
+
export { AgentSHError, IncompatibleProviderVersionError, IntegrityError, MissingPeerDependencyError, PolicyValidationError, ProvisioningError, RuntimeError, SandboxAdapter, SecureConfig, SecuredSandbox, secureSandbox };
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
adapters_exports
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-5IG6ABIZ.js";
|
|
4
4
|
import "./chunk-UYEAO27E.js";
|
|
5
5
|
import "./chunk-LMN3KM53.js";
|
|
6
6
|
import "./chunk-45FKFVMC.js";
|
|
7
7
|
import "./chunk-2P37YGN7.js";
|
|
8
8
|
import "./chunk-OANLKSOD.js";
|
|
9
9
|
import "./chunk-JY5ERJTX.js";
|
|
10
|
+
import {
|
|
11
|
+
policies_exports,
|
|
12
|
+
serializePolicy,
|
|
13
|
+
systemPolicyYaml
|
|
14
|
+
} from "./chunk-4FJHYLAB.js";
|
|
10
15
|
import {
|
|
11
16
|
AgentSHError,
|
|
12
17
|
IncompatibleProviderVersionError,
|
|
@@ -16,23 +21,20 @@ import {
|
|
|
16
21
|
ProvisioningError,
|
|
17
22
|
RuntimeError,
|
|
18
23
|
agentDefault,
|
|
19
|
-
policies_exports,
|
|
20
|
-
serializePolicy,
|
|
21
|
-
systemPolicyYaml,
|
|
22
24
|
validatePolicy
|
|
23
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-LNDICGZU.js";
|
|
24
26
|
import "./chunk-PZ5AY32C.js";
|
|
25
27
|
|
|
26
28
|
// src/core/integrity.ts
|
|
27
|
-
var PINNED_VERSION = "0.
|
|
29
|
+
var PINNED_VERSION = "0.16.2";
|
|
28
30
|
var CHECKSUMS = {
|
|
31
|
+
"0.16.2": {
|
|
32
|
+
linux_amd64: "7ff357066a61694626d4c19afa92fdf368318bced9be90391cc2f3808976f995",
|
|
33
|
+
linux_arm64: "a48b3e4a60804cca98326619a68409e8ee83556d69ee2cf5d574e4361e0c19c6"
|
|
34
|
+
},
|
|
29
35
|
"0.15.0": {
|
|
30
36
|
linux_amd64: "89f7ebbfd75ffd961245ec62b2602fd0cc387740502ac858dbc39c367c5699c5",
|
|
31
37
|
linux_arm64: "3fabbd749f9e98fb9f96ddfc94c389a6868cda7ed3668daa8440c39ceec85f3b"
|
|
32
|
-
},
|
|
33
|
-
"0.14.0": {
|
|
34
|
-
linux_amd64: "2ab8ba0d6637fe1a5badf840c3db197161a6f9865d721ed216029d229b1b9bbc",
|
|
35
|
-
linux_arm64: "929d18dd9fe36e9b2fa830d7ae64b4fb481853e743ade8674fcfcdc73470ed53"
|
|
36
38
|
}
|
|
37
39
|
};
|
|
38
40
|
function getChecksum(version, arch, override) {
|
|
@@ -128,14 +130,151 @@ function generateServerConfig(opts) {
|
|
|
128
130
|
},
|
|
129
131
|
sandbox: {
|
|
130
132
|
enabled: true,
|
|
131
|
-
allow_degraded: true,
|
|
132
|
-
|
|
133
|
+
allow_degraded: opts.allowDegraded ?? true,
|
|
134
|
+
// FUSE disabled by default: when agentsh server runs as root and exec
|
|
135
|
+
// users are non-root (e.g. E2B, Daytona), the FUSE workspace-mnt is
|
|
136
|
+
// inaccessible to non-root users causing exec to fail with exit code 2.
|
|
137
|
+
// File policy is still enforced via landlock. Enable FUSE
|
|
138
|
+
// explicitly via serverConfig: { fuse: { enabled: true } } if needed.
|
|
139
|
+
fuse: { enabled: false },
|
|
133
140
|
network: { enabled: true },
|
|
134
|
-
|
|
141
|
+
// Seccomp NOTIFY disabled by default: many container environments
|
|
142
|
+
// (Daytona, E2B custom images) restrict the seccomp() syscall via their
|
|
143
|
+
// container seccomp profile, causing "install seccomp filter: operation
|
|
144
|
+
// canceled" on every exec. Policy is still enforced via landlock and
|
|
145
|
+
// network rules. When ptrace is enabled, seccomp is also incompatible.
|
|
146
|
+
seccomp: { enabled: false }
|
|
135
147
|
}
|
|
136
148
|
};
|
|
137
149
|
if (opts.watchtower) config.watchtower = opts.watchtower;
|
|
138
|
-
if (opts.
|
|
150
|
+
if (opts.grpc) {
|
|
151
|
+
config.server.grpc = { enabled: true, addr: opts.grpc.addr };
|
|
152
|
+
}
|
|
153
|
+
if (opts.serverTimeouts) {
|
|
154
|
+
const http = config.server.http;
|
|
155
|
+
if (opts.serverTimeouts.readTimeout) http.read_timeout = opts.serverTimeouts.readTimeout;
|
|
156
|
+
if (opts.serverTimeouts.writeTimeout) http.write_timeout = opts.serverTimeouts.writeTimeout;
|
|
157
|
+
if (opts.serverTimeouts.maxRequestSize) http.max_request_size = opts.serverTimeouts.maxRequestSize;
|
|
158
|
+
}
|
|
159
|
+
if (opts.logging) config.logging = { ...opts.logging };
|
|
160
|
+
const sessionsObj = {
|
|
161
|
+
// Default sessions to a writable location outside /etc/agentsh (which is
|
|
162
|
+
// locked to 555/444 during provisioning). v0.16.2+ resolves workspace mount
|
|
163
|
+
// symlinks inside the sessions dir, which requires write access.
|
|
164
|
+
base_dir: "/var/lib/agentsh/sessions"
|
|
165
|
+
};
|
|
166
|
+
if (opts.realPaths) sessionsObj.real_paths = true;
|
|
167
|
+
if (opts.sessions) {
|
|
168
|
+
if (opts.sessions.baseDir) sessionsObj.base_dir = opts.sessions.baseDir;
|
|
169
|
+
if (opts.sessions.maxSessions !== void 0) sessionsObj.max_sessions = opts.sessions.maxSessions;
|
|
170
|
+
if (opts.sessions.defaultTimeout) sessionsObj.default_timeout = opts.sessions.defaultTimeout;
|
|
171
|
+
if (opts.sessions.idleTimeout) sessionsObj.idle_timeout = opts.sessions.idleTimeout;
|
|
172
|
+
if (opts.sessions.cleanupInterval) sessionsObj.cleanup_interval = opts.sessions.cleanupInterval;
|
|
173
|
+
}
|
|
174
|
+
if (Object.keys(sessionsObj).length > 0) config.sessions = sessionsObj;
|
|
175
|
+
if (opts.audit) {
|
|
176
|
+
const auditObj = {};
|
|
177
|
+
if (opts.audit.enabled !== void 0) auditObj.enabled = opts.audit.enabled;
|
|
178
|
+
if (opts.audit.sqlitePath) auditObj.sqlite_path = opts.audit.sqlitePath;
|
|
179
|
+
config.audit = auditObj;
|
|
180
|
+
}
|
|
181
|
+
if (opts.sandboxLimits) {
|
|
182
|
+
config.sandbox.limits = {
|
|
183
|
+
...opts.sandboxLimits.maxMemoryMb !== void 0 && { max_memory_mb: opts.sandboxLimits.maxMemoryMb },
|
|
184
|
+
...opts.sandboxLimits.maxCpuPercent !== void 0 && { max_cpu_percent: opts.sandboxLimits.maxCpuPercent },
|
|
185
|
+
...opts.sandboxLimits.maxProcesses !== void 0 && { max_processes: opts.sandboxLimits.maxProcesses }
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
if (opts.fuse) {
|
|
189
|
+
const fuseObj = config.sandbox.fuse;
|
|
190
|
+
if (opts.fuse.deferred !== void 0) fuseObj.deferred = opts.fuse.deferred;
|
|
191
|
+
if (opts.fuse.deferredMarkerFile) fuseObj.deferred_marker_file = opts.fuse.deferredMarkerFile;
|
|
192
|
+
if (opts.fuse.deferredEnableCommand) fuseObj.deferred_enable_command = opts.fuse.deferredEnableCommand;
|
|
193
|
+
}
|
|
194
|
+
if (opts.networkIntercept) {
|
|
195
|
+
const net = config.sandbox.network;
|
|
196
|
+
if (opts.networkIntercept.interceptMode) net.intercept_mode = opts.networkIntercept.interceptMode;
|
|
197
|
+
if (opts.networkIntercept.proxyListenAddr) net.proxy_listen_addr = opts.networkIntercept.proxyListenAddr;
|
|
198
|
+
}
|
|
199
|
+
if (opts.seccompDetails) {
|
|
200
|
+
const sec = config.sandbox.seccomp;
|
|
201
|
+
if (!opts.ptrace?.enabled) sec.enabled = true;
|
|
202
|
+
if (opts.seccompDetails.execve !== void 0) sec.execve = opts.seccompDetails.execve;
|
|
203
|
+
if (opts.seccompDetails.fileMonitor) {
|
|
204
|
+
sec.file_monitor = {
|
|
205
|
+
...opts.seccompDetails.fileMonitor.enabled !== void 0 && { enabled: opts.seccompDetails.fileMonitor.enabled },
|
|
206
|
+
...opts.seccompDetails.fileMonitor.enforceWithoutFuse !== void 0 && { enforce_without_fuse: opts.seccompDetails.fileMonitor.enforceWithoutFuse }
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (opts.cgroups) {
|
|
211
|
+
config.sandbox.cgroups = { ...opts.cgroups };
|
|
212
|
+
}
|
|
213
|
+
if (opts.unixSockets) {
|
|
214
|
+
config.sandbox.unix_sockets = { ...opts.unixSockets };
|
|
215
|
+
}
|
|
216
|
+
if (opts.ptrace) {
|
|
217
|
+
const ptraceObj = {};
|
|
218
|
+
if (opts.ptrace.enabled !== void 0) ptraceObj.enabled = opts.ptrace.enabled;
|
|
219
|
+
if (opts.ptrace.attachMode) ptraceObj.attach_mode = opts.ptrace.attachMode;
|
|
220
|
+
if (opts.ptrace.maskTracerPid) ptraceObj.mask_tracer_pid = opts.ptrace.maskTracerPid;
|
|
221
|
+
if (opts.ptrace.trace) {
|
|
222
|
+
const traceObj = {};
|
|
223
|
+
if (opts.ptrace.trace.execve !== void 0) traceObj.execve = opts.ptrace.trace.execve;
|
|
224
|
+
if (opts.ptrace.trace.file !== void 0) traceObj.file = opts.ptrace.trace.file;
|
|
225
|
+
if (opts.ptrace.trace.network !== void 0) traceObj.network = opts.ptrace.trace.network;
|
|
226
|
+
if (opts.ptrace.trace.signal !== void 0) traceObj.signal = opts.ptrace.trace.signal;
|
|
227
|
+
ptraceObj.trace = traceObj;
|
|
228
|
+
}
|
|
229
|
+
if (opts.ptrace.performance) {
|
|
230
|
+
const perfObj = {};
|
|
231
|
+
if (opts.ptrace.performance.seccompPrefilter !== void 0) perfObj.seccomp_prefilter = opts.ptrace.performance.seccompPrefilter;
|
|
232
|
+
if (opts.ptrace.performance.maxTracees !== void 0) perfObj.max_tracees = opts.ptrace.performance.maxTracees;
|
|
233
|
+
if (opts.ptrace.performance.maxHoldMs !== void 0) perfObj.max_hold_ms = opts.ptrace.performance.maxHoldMs;
|
|
234
|
+
ptraceObj.performance = perfObj;
|
|
235
|
+
}
|
|
236
|
+
if (opts.ptrace.onAttachFailure) ptraceObj.on_attach_failure = opts.ptrace.onAttachFailure;
|
|
237
|
+
config.sandbox.ptrace = ptraceObj;
|
|
238
|
+
}
|
|
239
|
+
if (opts.envInject) {
|
|
240
|
+
config.sandbox.env_inject = { ...opts.envInject };
|
|
241
|
+
}
|
|
242
|
+
if (opts.proxy) {
|
|
243
|
+
config.proxy = { ...opts.proxy };
|
|
244
|
+
}
|
|
245
|
+
if (opts.dlp) {
|
|
246
|
+
const dlpObj = {};
|
|
247
|
+
if (opts.dlp.mode) dlpObj.mode = opts.dlp.mode;
|
|
248
|
+
if (opts.dlp.patterns) dlpObj.patterns = opts.dlp.patterns;
|
|
249
|
+
if (opts.dlp.customPatterns) {
|
|
250
|
+
dlpObj.custom_patterns = opts.dlp.customPatterns.map((p) => ({
|
|
251
|
+
name: p.name,
|
|
252
|
+
display: p.display,
|
|
253
|
+
regex: p.regex
|
|
254
|
+
}));
|
|
255
|
+
}
|
|
256
|
+
config.dlp = dlpObj;
|
|
257
|
+
}
|
|
258
|
+
if (opts.policiesOverride) {
|
|
259
|
+
config.policies = {
|
|
260
|
+
...opts.policiesOverride.dir && { dir: opts.policiesOverride.dir },
|
|
261
|
+
...opts.policiesOverride.defaultPolicy && { default: opts.policiesOverride.defaultPolicy }
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
if (opts.approvals) config.approvals = { ...opts.approvals };
|
|
265
|
+
if (opts.metrics) config.metrics = { ...opts.metrics };
|
|
266
|
+
if (opts.health) {
|
|
267
|
+
const healthObj = {};
|
|
268
|
+
if (opts.health.path) healthObj.path = opts.health.path;
|
|
269
|
+
if (opts.health.readinessPath) healthObj.readiness_path = opts.health.readinessPath;
|
|
270
|
+
config.health = healthObj;
|
|
271
|
+
}
|
|
272
|
+
if (opts.development) {
|
|
273
|
+
const devObj = {};
|
|
274
|
+
if (opts.development.disableAuth !== void 0) devObj.disable_auth = opts.development.disableAuth;
|
|
275
|
+
if (opts.development.verboseErrors !== void 0) devObj.verbose_errors = opts.development.verboseErrors;
|
|
276
|
+
config.development = devObj;
|
|
277
|
+
}
|
|
139
278
|
const feeds = opts.threatFeeds === false ? void 0 : opts.threatFeeds ?? defaultThreatFeeds;
|
|
140
279
|
if (feeds) {
|
|
141
280
|
config.threat_feeds = {
|
|
@@ -195,7 +334,8 @@ async function getTraceparent() {
|
|
|
195
334
|
|
|
196
335
|
// src/core/provision.ts
|
|
197
336
|
var SECURITY_MODE_RANK = {
|
|
198
|
-
full:
|
|
337
|
+
full: 5,
|
|
338
|
+
ptrace: 4,
|
|
199
339
|
landlock: 3,
|
|
200
340
|
"landlock-only": 2,
|
|
201
341
|
minimal: 1
|
|
@@ -240,13 +380,23 @@ async function provision(adapter, config = {}) {
|
|
|
240
380
|
traceParent,
|
|
241
381
|
policyName = "policy",
|
|
242
382
|
threatFeeds,
|
|
243
|
-
packageChecks
|
|
383
|
+
packageChecks,
|
|
384
|
+
skipShim = false,
|
|
385
|
+
serverConfig: extendedConfig
|
|
244
386
|
} = config;
|
|
245
387
|
const policy = rawPolicy ? validatePolicy(rawPolicy) : agentDefault();
|
|
246
388
|
let securityMode = "full";
|
|
247
389
|
if (installStrategy === "running") {
|
|
248
390
|
await healthCheck(adapter);
|
|
249
|
-
|
|
391
|
+
if (config.securityMode) {
|
|
392
|
+
securityMode = config.securityMode;
|
|
393
|
+
} else if (minimumSecurityMode) {
|
|
394
|
+
throw new ProvisioningError({
|
|
395
|
+
phase: "install",
|
|
396
|
+
command: "securityMode check",
|
|
397
|
+
stderr: `Cannot verify security mode in 'running' strategy \u2014 set securityMode explicitly when using minimumSecurityMode`
|
|
398
|
+
});
|
|
399
|
+
}
|
|
250
400
|
if (minimumSecurityMode && isWeakerThan(securityMode, minimumSecurityMode)) {
|
|
251
401
|
throw new ProvisioningError({
|
|
252
402
|
phase: "install",
|
|
@@ -278,7 +428,15 @@ async function provision(adapter, config = {}) {
|
|
|
278
428
|
});
|
|
279
429
|
}
|
|
280
430
|
} else if (installStrategy === "download" || installStrategy === "upload") {
|
|
281
|
-
|
|
431
|
+
let needsInstall = !exists;
|
|
432
|
+
if (exists && agentshVersion !== "skip-version-check") {
|
|
433
|
+
const versionResult = await adapter.exec("agentsh", ["--version"]);
|
|
434
|
+
const installedVersion = versionResult.stdout.trim().replace(/^v/, "");
|
|
435
|
+
if (!installedVersion.startsWith(agentshVersion)) {
|
|
436
|
+
needsInstall = true;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
if (needsInstall) {
|
|
282
440
|
const arch = archOverride ?? await detectArch(adapter);
|
|
283
441
|
if (installStrategy === "download") {
|
|
284
442
|
await downloadBinary(adapter, agentshVersion, arch, agentshBinaryUrl);
|
|
@@ -323,28 +481,29 @@ async function provision(adapter, config = {}) {
|
|
|
323
481
|
stderr: `Detected security mode '${securityMode}' is weaker than required '${minimumSecurityMode}'`
|
|
324
482
|
});
|
|
325
483
|
}
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
484
|
+
const realPaths = realPathsOverride ?? false;
|
|
485
|
+
if (!skipShim) {
|
|
486
|
+
const shimResult = await adapter.exec(
|
|
487
|
+
"agentsh",
|
|
488
|
+
[
|
|
489
|
+
"shim",
|
|
490
|
+
"install-shell",
|
|
491
|
+
"--root",
|
|
492
|
+
"/",
|
|
493
|
+
"--shim",
|
|
494
|
+
"/usr/bin/agentsh-shell-shim",
|
|
495
|
+
"--bash",
|
|
496
|
+
"--i-understand-this-modifies-the-host"
|
|
497
|
+
],
|
|
498
|
+
{ sudo: true }
|
|
499
|
+
);
|
|
500
|
+
if (shimResult.exitCode !== 0) {
|
|
501
|
+
throw new ProvisioningError({
|
|
502
|
+
phase: "install",
|
|
503
|
+
command: "agentsh shim install-shell",
|
|
504
|
+
stderr: shimResult.stderr
|
|
505
|
+
});
|
|
506
|
+
}
|
|
348
507
|
}
|
|
349
508
|
const mkdirResult = await adapter.exec(
|
|
350
509
|
"mkdir",
|
|
@@ -373,7 +532,8 @@ async function provision(adapter, config = {}) {
|
|
|
373
532
|
watchtower,
|
|
374
533
|
realPaths,
|
|
375
534
|
threatFeeds,
|
|
376
|
-
packageChecks
|
|
535
|
+
packageChecks,
|
|
536
|
+
...extendedConfig
|
|
377
537
|
});
|
|
378
538
|
await adapter.writeFile("/etc/agentsh/config.yml", serverConfig, {
|
|
379
539
|
sudo: true
|
|
@@ -414,7 +574,12 @@ async function provision(adapter, config = {}) {
|
|
|
414
574
|
stderr: chownResult.stderr
|
|
415
575
|
});
|
|
416
576
|
}
|
|
417
|
-
await adapter.exec("mkdir", ["-p", workspace], { sudo: true });
|
|
577
|
+
await adapter.exec("mkdir", ["-p", workspace, "/var/lib/agentsh/sessions"], { sudo: true });
|
|
578
|
+
await adapter.exec("chmod", ["755", "/var/lib/agentsh", "/var/lib/agentsh/sessions"], { sudo: true });
|
|
579
|
+
await adapter.exec("sh", [
|
|
580
|
+
"-c",
|
|
581
|
+
'grep -q user_allow_other /etc/fuse.conf 2>/dev/null || echo "user_allow_other" >> /etc/fuse.conf'
|
|
582
|
+
], { sudo: true });
|
|
418
583
|
const serverResult = await adapter.exec(
|
|
419
584
|
"agentsh",
|
|
420
585
|
["server", "--config", "/etc/agentsh/config.yml"],
|
|
@@ -459,6 +624,7 @@ async function provision(adapter, config = {}) {
|
|
|
459
624
|
});
|
|
460
625
|
}
|
|
461
626
|
}
|
|
627
|
+
await adapter.exec("chmod", ["-R", "755", "/var/lib/agentsh/sessions/"], { sudo: true });
|
|
462
628
|
const effectiveTraceParent = traceParent ?? await getTraceparent();
|
|
463
629
|
if (effectiveTraceParent) {
|
|
464
630
|
await adapter.exec("curl", [
|
|
@@ -605,7 +771,7 @@ async function detectSecurityMode(adapter) {
|
|
|
605
771
|
});
|
|
606
772
|
}
|
|
607
773
|
const mode = parsed.security_mode;
|
|
608
|
-
const validModes = ["full", "landlock", "landlock-only", "minimal"];
|
|
774
|
+
const validModes = ["full", "ptrace", "landlock", "landlock-only", "minimal"];
|
|
609
775
|
if (!validModes.includes(mode)) {
|
|
610
776
|
throw new ProvisioningError({
|
|
611
777
|
phase: "install",
|