@theokit/sdk 4.19.4 → 4.21.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.
@@ -1,10 +1,242 @@
1
1
  'use strict';
2
2
 
3
3
  var child_process = require('child_process');
4
- var promises = require('fs/promises');
4
+ var fs = require('fs');
5
5
  var path = require('path');
6
+ var os = require('os');
7
+ var promises = require('fs/promises');
6
8
 
7
- // src/sandbox/local-sandbox.ts
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ var path__default = /*#__PURE__*/_interopDefault(path);
12
+
13
+ // src/sandbox/bwrap.ts
14
+ function buildBwrapArgv(mode, opts) {
15
+ if (mode === "danger-full-access") return null;
16
+ const cwd = path__default.default.resolve(opts.cwd);
17
+ const gitDir = path__default.default.join(cwd, ".git");
18
+ const hasGit = opts.gitDirExists ?? fs.existsSync(gitDir);
19
+ const argv = [
20
+ // core, always (bwrap.rs:318-332; user+pid namespaces explicit so it works as root in containers)
21
+ "--new-session",
22
+ "--die-with-parent",
23
+ "--unshare-user",
24
+ "--unshare-pid",
25
+ // full-read filesystem base (bwrap.rs:446-452)
26
+ "--ro-bind",
27
+ "/",
28
+ "/",
29
+ "--dev",
30
+ "/dev",
31
+ "--proc",
32
+ "/proc"
33
+ ];
34
+ if (!opts.network) argv.push("--unshare-net");
35
+ if (opts.env) argv.push("--clearenv");
36
+ const setenv = {
37
+ ...opts.env ?? {},
38
+ // the flag signals the child that network is unshared (spawn.rs:20,79)
39
+ ...opts.network ? {} : { CODEX_SANDBOX_NETWORK_DISABLED: "1" }
40
+ };
41
+ for (const [k, v] of Object.entries(setenv)) argv.push("--setenv", k, v);
42
+ if (mode === "workspace-write") {
43
+ argv.push("--bind", cwd, cwd, "--bind", "/tmp", "/tmp");
44
+ if (hasGit) argv.push("--ro-bind", gitDir, gitDir);
45
+ }
46
+ argv.push("--chdir", cwd, "--");
47
+ return argv;
48
+ }
49
+ function detectBwrap(probes = realProbes) {
50
+ try {
51
+ const bin = probes.which();
52
+ if (!bin) return { ok: false, reason: "bwrap not found in PATH" };
53
+ const help = probes.helpText(bin);
54
+ if (!help?.includes("--perms")) {
55
+ return { ok: false, reason: `bwrap at ${bin} lacks --perms support (too old)` };
56
+ }
57
+ if (!probes.userns(bin)) {
58
+ return { ok: false, reason: "user namespaces unavailable (container/kernel restriction)" };
59
+ }
60
+ return { ok: true, bin };
61
+ } catch (err) {
62
+ return {
63
+ ok: false,
64
+ reason: `bwrap probe failed: ${err instanceof Error ? err.message : String(err)}`
65
+ };
66
+ }
67
+ }
68
+ var sondagensReais = 0;
69
+ function realProbeCount() {
70
+ return sondagensReais;
71
+ }
72
+ var realProbes = {
73
+ which: () => {
74
+ sondagensReais++;
75
+ try {
76
+ const out = child_process.execFileSync("which", ["bwrap"], { encoding: "utf8", timeout: 2e3 }).trim();
77
+ if (!out || out.startsWith(process.cwd() + path__default.default.sep)) return null;
78
+ return out;
79
+ } catch {
80
+ return null;
81
+ }
82
+ },
83
+ helpText: (bin) => {
84
+ try {
85
+ return child_process.execFileSync(bin, ["--help"], { encoding: "utf8", timeout: 2e3 });
86
+ } catch (err) {
87
+ const e = err;
88
+ return [e.stdout, e.stderr].filter(Boolean).join("\n") || null;
89
+ }
90
+ },
91
+ userns: (bin) => {
92
+ try {
93
+ child_process.execFileSync(bin, ["--unshare-user", "--unshare-net", "--ro-bind", "/", "/", "/bin/true"], {
94
+ timeout: 500,
95
+ stdio: "ignore"
96
+ });
97
+ return true;
98
+ } catch {
99
+ return false;
100
+ }
101
+ }
102
+ };
103
+ var memo;
104
+ function detectBwrapMemoizado(probes = realProbes) {
105
+ memo ??= detectBwrap(probes);
106
+ if (memo.ok && !fs.existsSync(memo.bin)) {
107
+ memo = { ok: false, reason: `bwrap disappeared from ${memo.bin} after detection` };
108
+ }
109
+ return memo;
110
+ }
111
+ function resetBwrapMemo() {
112
+ memo = void 0;
113
+ }
114
+
115
+ // src/internal/security/redact.ts
116
+ var REDACT_ENABLED = readEnvOnce();
117
+ function readEnvOnce() {
118
+ const raw = process.env.THEOKIT_REDACT_SECRETS;
119
+ if (raw === void 0) return true;
120
+ return ["1", "true", "yes", "on"].includes(raw.toLowerCase());
121
+ }
122
+ var warnedOptOut = false;
123
+ if (!REDACT_ENABLED && !warnedOptOut) {
124
+ process.stderr.write(
125
+ "[theokit-sdk] Secret redaction is DISABLED via THEOKIT_REDACT_SECRETS. Credentials may leak into errors, telemetry, logs, transcripts.\n"
126
+ );
127
+ warnedOptOut = true;
128
+ }
129
+ var BUILTIN_PATTERNS = [
130
+ // T5.4: 30+ vendor prefixes (was 12 pre-T5.4). Order matters — more
131
+ // specific prefixes precede generic ones (e.g., sk-ant-admin01 before
132
+ // sk-ant-, sk-proj- before sk-). PEM block deliberately first so its
133
+ // multi-line span runs before any per-line patterns can fire.
134
+ /-----BEGIN[ ]+(?:RSA |EC |DSA |OPENSSH |ENCRYPTED |)PRIVATE KEY-----[\s\S]+?-----END[ ]+(?:RSA |EC |DSA |OPENSSH |ENCRYPTED |)PRIVATE KEY-----/g,
135
+ // JWT — exact 3-segment base64url. Dotted; the body floor of 4 chars per
136
+ // segment matches the minimum legal payload while skipping `a.b.c` noise.
137
+ /eyJ[A-Za-z0-9_-]{4,}\.eyJ[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{4,}/g,
138
+ // Azure Storage SAS — match the sig= component (URL-encoded base64).
139
+ /(?<=[?&]sig=)[A-Za-z0-9%+/]{20,}/g,
140
+ // Anthropic
141
+ /sk-ant-admin01-[A-Za-z0-9_-]{10,}/g,
142
+ // Anthropic admin keys (must precede sk-ant-)
143
+ /sk-ant-[A-Za-z0-9_-]{10,}/g,
144
+ // Anthropic regular
145
+ // OpenAI family + clones (sk- generic must come AFTER all sk-foo- variants)
146
+ /sk-proj-[A-Za-z0-9_-]{10,}/g,
147
+ // OpenAI project key (must precede sk- generic)
148
+ /sk-[A-Za-z0-9_-]{10,}/g,
149
+ // OpenAI / OpenRouter / DeepInfra / Together / DeepSeek
150
+ // Provider prefixes (alphabetized for maintainability)
151
+ /AIza[A-Za-z0-9_-]{35}/g,
152
+ // Google API key
153
+ /AKIA[A-Z0-9]{16}/g,
154
+ // AWS access key
155
+ /fw_[A-Za-z0-9]{20,}/g,
156
+ // Fireworks
157
+ /glpat-[A-Za-z0-9_-]{20}/g,
158
+ // GitLab PAT
159
+ /ghp_[A-Za-z0-9]{36}/g,
160
+ // GitHub PAT classic
161
+ /github_pat_[A-Za-z0-9_]{82}/g,
162
+ // GitHub PAT fine-grained
163
+ /gsk_[A-Za-z0-9]{20,}/g,
164
+ // Groq
165
+ /hf_[A-Za-z0-9]{20,}/g,
166
+ // HuggingFace
167
+ /\bpa-[A-Za-z0-9_-]{20,}/g,
168
+ // Voyage AI (word-boundary to skip CSS / kebab IDs)
169
+ /pcsk_[A-Za-z0-9_-]{20,}/g,
170
+ // Pinecone
171
+ /pplx-[A-Za-z0-9_-]{20,}/g,
172
+ // Perplexity
173
+ /r8_[A-Za-z0-9_-]{20,}/g,
174
+ // Replicate
175
+ /rk_live_[A-Za-z0-9]{20,}/g,
176
+ // Stripe restricted
177
+ /sk_live_[A-Za-z0-9]{20,}/g,
178
+ // Stripe secret
179
+ /sntrys_[A-Za-z0-9]{40,}/g,
180
+ // Sentry user auth
181
+ /xai-[A-Za-z0-9_-]{20,}/g,
182
+ // xAI (Grok)
183
+ /xox[bpasr]-[A-Za-z0-9-]{10,}/g,
184
+ //Slack tokens
185
+ // Additional unique-prefix tokens with low false-positive risk
186
+ /npm_[A-Za-z0-9]{36}/g,
187
+ // npm access token
188
+ /SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43}/g,
189
+ // SendGrid
190
+ /\bSK[A-Za-z0-9]{32}\b/g,
191
+ // Twilio API SID (word-boundary to skip CSS class noise)
192
+ /\bkey-[a-f0-9]{32}\b/g,
193
+ // Mailgun (hex-only narrows false positives)
194
+ /MT[A-Za-z0-9_-]{23}\.[A-Za-z0-9_-]{6}\.[A-Za-z0-9_-]{27}/g,
195
+ // Discord bot
196
+ /\b(?:sdk|mob)-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\b/g
197
+ // LaunchDarkly
198
+ ];
199
+ var BEARER_PATTERN = /\b(Bearer\s+)([A-Za-z0-9_\-.+/=]{8,})/g;
200
+ var PARAM_PATTERN = /(\b(?:access_token|api_key|api-key|client_secret|credential|credentials|id_token|jwt|password|private_key|refresh_token|secret|service_account|session_token|token|x-api-key)\b["']?\s*[:=]\s*["']?)([A-Za-z0-9_\-.+/]+)/gi;
201
+ var _extraPatterns = [];
202
+ function maskToken(token) {
203
+ if (token.length < 18) return "***";
204
+ return `${token.slice(0, 6)}...${token.slice(-4)}`;
205
+ }
206
+ var MASK_SHAPE = /^.{6}\.\.\..{4}$/s;
207
+ function coerceToString(value) {
208
+ if (typeof value === "string") return value;
209
+ if (value === null || value === void 0) return null;
210
+ if (typeof value === "object") {
211
+ try {
212
+ const s = JSON.stringify(value);
213
+ return s === void 0 ? null : s;
214
+ } catch {
215
+ return "[unredactable: circular]";
216
+ }
217
+ }
218
+ return String(value);
219
+ }
220
+ function redactSecrets(text, opts) {
221
+ const coerced = coerceToString(text);
222
+ if (coerced === null) return "";
223
+ if (!REDACT_ENABLED) return coerced;
224
+ let s = coerced;
225
+ for (const re of BUILTIN_PATTERNS) {
226
+ s = s.replace(re, (m) => maskToken(m));
227
+ }
228
+ for (const re of _extraPatterns) {
229
+ s = s.replace(re, (m) => maskToken(m));
230
+ }
231
+ {
232
+ s = s.replace(BEARER_PATTERN, (_, prefix) => `${prefix}***`);
233
+ s = s.replace(PARAM_PATTERN, (whole, prefix, value) => {
234
+ if (MASK_SHAPE.test(value)) return whole;
235
+ return `${prefix}***`;
236
+ });
237
+ }
238
+ return s;
239
+ }
8
240
 
9
241
  // src/internal/runtime/lifecycle/env-policy.ts
10
242
  var SECRET_PATTERNS = [
@@ -91,15 +323,15 @@ var SandboxBackend = class {
91
323
  env: config.env ?? "inherit-scrubbed"
92
324
  };
93
325
  }
94
- async readFile(path) {
95
- const result = await this.execute(`cat ${this.shellEscape(path)}`);
326
+ async readFile(path2) {
327
+ const result = await this.execute(`cat ${this.shellEscape(path2)}`);
96
328
  if (result.exitCode !== 0) {
97
329
  throw new Error(`readFile failed: ${result.stderr}`);
98
330
  }
99
331
  return result.stdout;
100
332
  }
101
- async writeFile(path, content) {
102
- await this.uploadFile(path, content);
333
+ async writeFile(path2, content) {
334
+ await this.uploadFile(path2, content);
103
335
  }
104
336
  async glob(pattern, cwd) {
105
337
  const dir = cwd ?? this.config.workDir ?? ".";
@@ -109,16 +341,16 @@ var SandboxBackend = class {
109
341
  if (result.exitCode !== 0) return [];
110
342
  return result.stdout.trim().split("\n").filter(Boolean);
111
343
  }
112
- async grep(pattern, path) {
113
- const target = path ?? ".";
344
+ async grep(pattern, path2) {
345
+ const target = path2 ?? ".";
114
346
  const result = await this.execute(
115
347
  `grep -rn ${this.shellEscape(pattern)} ${this.shellEscape(target)} 2>/dev/null`
116
348
  );
117
349
  if (result.exitCode !== 0) return [];
118
350
  return result.stdout.trim().split("\n").filter(Boolean);
119
351
  }
120
- async listDir(path) {
121
- const result = await this.execute(`ls -1 ${this.shellEscape(path)}`);
352
+ async listDir(path2) {
353
+ const result = await this.execute(`ls -1 ${this.shellEscape(path2)}`);
122
354
  if (result.exitCode !== 0) return [];
123
355
  return result.stdout.trim().split("\n").filter(Boolean);
124
356
  }
@@ -176,13 +408,258 @@ var LocalSandbox = class extends SandboxBackend {
176
408
  timedOut
177
409
  };
178
410
  }
179
- async uploadFile(path$1, content) {
180
- const fullPath = path$1.startsWith("/") ? path$1 : `${this.config.workDir}/${path$1}`;
411
+ async uploadFile(path2, content) {
412
+ const fullPath = path2.startsWith("/") ? path2 : `${this.config.workDir}/${path2}`;
181
413
  await promises.mkdir(path.dirname(fullPath), { recursive: true });
182
414
  await promises.writeFile(fullPath, content, "utf-8");
183
415
  }
184
416
  };
185
417
 
418
+ // src/sandbox/seccomp.ts
419
+ var BPF_LD = 0;
420
+ var BPF_W = 0;
421
+ var BPF_ABS = 32;
422
+ var BPF_JMP = 5;
423
+ var BPF_JEQ = 16;
424
+ var BPF_JGE = 48;
425
+ var BPF_K = 0;
426
+ var BPF_RET = 6;
427
+ var LD_ABS_W = BPF_LD | BPF_W | BPF_ABS;
428
+ var JEQ_K = BPF_JMP | BPF_JEQ | BPF_K;
429
+ var JGE_K = BPF_JMP | BPF_JGE | BPF_K;
430
+ var RET_K = BPF_RET | BPF_K;
431
+ var OFF_NR = 0;
432
+ var OFF_ARCH = 4;
433
+ var OFF_ARG0 = 16;
434
+ var AUDIT_ARCH_X86_64 = 3221225534;
435
+ var X32_BIT = 1073741824;
436
+ var SECCOMP_RET_ALLOW = 2147418112;
437
+ var SECCOMP_RET_ERRNO = 327680;
438
+ var EPERM = 1;
439
+ var RET_EPERM = SECCOMP_RET_ERRNO | EPERM & 65535;
440
+ var SECCOMP_RET_KILL_PROCESS = 2147483648;
441
+ var AF_UNIX = 1;
442
+ var ALWAYS_DENIED = [101, 310, 311, 425, 426, 427];
443
+ var NETWORK_DENIED = [42, 43, 288, 49, 50, 52, 51, 48, 44, 307, 299, 55, 54];
444
+ var SOCKET_SYSCALLS = [41, 53];
445
+ var stmt = (code, k) => ({ code, jt: 0, jf: 0, k });
446
+ var jmp = (code, k, jt, jf) => ({ code, jt, jf, k });
447
+ function buildSeccompFilter(opts) {
448
+ const insns = [];
449
+ const ALLOW = /* @__PURE__ */ Symbol("ALLOW");
450
+ const DENY = /* @__PURE__ */ Symbol("DENY");
451
+ const KILL = /* @__PURE__ */ Symbol("KILL");
452
+ const body = [];
453
+ const push = (code, k, jt = 0, jf = 0) => {
454
+ body.push({ code, k, jt, jf });
455
+ };
456
+ push(LD_ABS_W, OFF_ARCH);
457
+ push(JEQ_K, AUDIT_ARCH_X86_64, 0, KILL);
458
+ push(LD_ABS_W, OFF_NR);
459
+ push(JGE_K, X32_BIT, KILL, 0);
460
+ const denied = opts.networkRestricted ? [...ALWAYS_DENIED, ...NETWORK_DENIED] : [...ALWAYS_DENIED];
461
+ for (const nr of denied) push(JEQ_K, nr, DENY, 0);
462
+ if (opts.networkRestricted) {
463
+ for (const sysno of SOCKET_SYSCALLS) {
464
+ push(JEQ_K, sysno, 0, 2);
465
+ push(LD_ABS_W, OFF_ARG0);
466
+ push(JEQ_K, AF_UNIX, ALLOW, DENY);
467
+ }
468
+ }
469
+ push(RET_K, SECCOMP_RET_ALLOW);
470
+ const allowIdx = body.length - 1;
471
+ push(RET_K, RET_EPERM);
472
+ const denyIdx = body.length - 1;
473
+ push(RET_K, SECCOMP_RET_KILL_PROCESS);
474
+ const killIdx = body.length - 1;
475
+ const resolve = (i, t) => {
476
+ const abs = t === ALLOW ? allowIdx : t === DENY ? denyIdx : t === KILL ? killIdx : i + 1 + t;
477
+ const off = abs - (i + 1);
478
+ if (off < 0 || off > 255) throw new RangeError(`seccomp jump out of range at ${i}: ${off}`);
479
+ return off;
480
+ };
481
+ for (const [i, b] of body.entries()) {
482
+ if (b.code === JEQ_K || b.code === JGE_K) {
483
+ insns.push(jmp(b.code, b.k, resolve(i, b.jt), resolve(i, b.jf)));
484
+ } else {
485
+ insns.push(stmt(b.code, b.k));
486
+ }
487
+ }
488
+ const buf = Buffer.alloc(insns.length * 8);
489
+ insns.forEach((ins, i) => {
490
+ buf.writeUInt16LE(ins.code, i * 8);
491
+ buf.writeUInt8(ins.jt, i * 8 + 2);
492
+ buf.writeUInt8(ins.jf, i * 8 + 3);
493
+ buf.writeUInt32LE(ins.k >>> 0, i * 8 + 4);
494
+ });
495
+ return buf;
496
+ }
497
+
498
+ // src/sandbox/linux-sandbox.ts
499
+ function shellQuote(s) {
500
+ return `'${s.replaceAll("'", `'\\''`)}'`;
501
+ }
502
+ function wrapCommandForSandbox(mode, opts, command) {
503
+ const argv = buildBwrapArgv(mode, { cwd: opts.cwd, network: opts.network, env: opts.env });
504
+ if (argv === null) return null;
505
+ const bin = opts.bin ?? "bwrap";
506
+ const seccompArgv = opts.seccompPath !== void 0 ? ["--seccomp", "3"] : [];
507
+ const base = `${shellQuote(bin)} ${[...argv.slice(0, -1), ...seccompArgv, "--"].map(shellQuote).join(" ")} /bin/sh -c ${shellQuote(command)}`;
508
+ return opts.seccompPath !== void 0 ? `${base} 3< ${shellQuote(opts.seccompPath)}` : base;
509
+ }
510
+ var ENV_ALLOWLIST = [
511
+ "PATH",
512
+ "HOME",
513
+ "LANG",
514
+ "LC_ALL",
515
+ "LC_CTYPE",
516
+ "TERM",
517
+ "USER",
518
+ "TMPDIR",
519
+ "SHELL"
520
+ ];
521
+ function allowlistedEnv(source = process.env) {
522
+ const out = {};
523
+ for (const k of ENV_ALLOWLIST) {
524
+ const v = source[k];
525
+ if (v !== void 0) out[k] = v;
526
+ }
527
+ return out;
528
+ }
529
+ var LinuxSandbox = class extends LocalSandbox {
530
+ mode;
531
+ network;
532
+ cwd;
533
+ bin;
534
+ env;
535
+ /** M63 — path to the cBPF seccomp program written host-side; passed to `bwrap --seccomp 3` via a
536
+ * shell redirect. `undefined` when the network is unrestricted OR generation failed (honest fallback). */
537
+ seccompPath;
538
+ constructor(config, opts) {
539
+ super(config);
540
+ this.mode = opts.mode;
541
+ this.network = opts.network ?? false;
542
+ this.cwd = config.workDir ?? process.cwd();
543
+ this.bin = opts.bin ?? "bwrap";
544
+ this.env = opts.env ?? allowlistedEnv();
545
+ this.seccompPath = this.network ? void 0 : restrictedSeccompPath();
546
+ }
547
+ /** Extracted for test visibility — delegates to the pure `wrapCommandForSandbox` (M57, single wrap SoT). */
548
+ wrapCommand(command) {
549
+ return wrapCommandForSandbox(
550
+ this.mode,
551
+ {
552
+ cwd: this.cwd,
553
+ network: this.network,
554
+ env: this.env,
555
+ bin: this.bin,
556
+ seccompPath: this.seccompPath
557
+ },
558
+ command
559
+ );
560
+ }
561
+ execute(command, opts) {
562
+ const wrapped = this.wrapCommand(command);
563
+ if (wrapped === null) return super.execute(command, opts);
564
+ return super.execute(wrapped, opts);
565
+ }
566
+ };
567
+ var warnedNonX64 = false;
568
+ function seccompPathForArch(arch, warn) {
569
+ if (arch !== "x64") {
570
+ if (!warnedNonX64) {
571
+ warnedNonX64 = true;
572
+ warn(
573
+ `[sandbox] seccomp syscall filter unsupported on ${arch} (x86_64 only in v1) \u2014 running without the filter; bwrap FS/network confinement still applies.`
574
+ );
575
+ }
576
+ return void 0;
577
+ }
578
+ try {
579
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "ab-seccomp-"));
580
+ const path2 = path.join(dir, "filter.bpf");
581
+ fs.writeFileSync(path2, buildSeccompFilter({ networkRestricted: true }));
582
+ const cleanup = () => fs.rmSync(dir, { recursive: true, force: true });
583
+ process.once("exit", cleanup);
584
+ process.once("SIGINT", cleanup);
585
+ process.once("SIGTERM", cleanup);
586
+ return path2;
587
+ } catch (err) {
588
+ warn(
589
+ `[sandbox] seccomp filter unavailable (${err instanceof Error ? err.message : String(err)}) \u2014 running without syscall filter (bwrap FS/network confinement still applies).`
590
+ );
591
+ return void 0;
592
+ }
593
+ }
594
+ var seccompFilterPath;
595
+ function restrictedSeccompPath() {
596
+ if (seccompFilterPath !== void 0) return seccompFilterPath ?? void 0;
597
+ const path2 = seccompPathForArch(process.arch, (m) => console.warn(redactSecrets(m)));
598
+ seccompFilterPath = path2 ?? null;
599
+ return path2;
600
+ }
601
+ var warnedUnavailable = false;
602
+ function resetSandboxWarnLatch() {
603
+ warnedUnavailable = false;
604
+ }
605
+ function resolveSandboxPosture(opts) {
606
+ if (opts.mode === "danger-full-access") {
607
+ return { mode: opts.mode, enforced: false, detail: "no confinement (danger-full-access)" };
608
+ }
609
+ const detection = (opts.detect ?? detectBwrapMemoizado)();
610
+ if (!detection.ok) {
611
+ return { mode: opts.mode, enforced: false, detail: `tool-gating only \u2014 ${detection.reason}` };
612
+ }
613
+ return { mode: opts.mode, enforced: true, detail: "kernel (bwrap)" };
614
+ }
615
+ function createSandboxBackend(opts) {
616
+ const config = { workDir: opts.workDir, timeoutMs: opts.timeoutMs };
617
+ if (opts.mode === "danger-full-access") return new LocalSandbox(config);
618
+ const detection = (opts.detect ?? detectBwrapMemoizado)();
619
+ if (!detection.ok) {
620
+ if (!warnedUnavailable) {
621
+ warnedUnavailable = true;
622
+ const warn = opts.warn ?? ((m) => console.warn(redactSecrets(m)));
623
+ warn(
624
+ `[sandbox] OS-level enforcement unavailable (${detection.reason}) \u2014 falling back to tool-level gating only (sandbox_mode=${opts.mode}).`
625
+ );
626
+ }
627
+ return new LocalSandbox(config);
628
+ }
629
+ return new LinuxSandbox(config, { mode: opts.mode, network: opts.network, bin: detection.bin });
630
+ }
631
+ var avisouInterativo = false;
632
+ function resetInteractiveWarnLatch() {
633
+ avisouInterativo = false;
634
+ }
635
+ function interactiveWrapCommand(opts) {
636
+ return (command, cwd) => {
637
+ if (opts.mode === "danger-full-access") return null;
638
+ const detection = (opts.detect ?? detectBwrapMemoizado)();
639
+ if (!detection.ok) {
640
+ if (!avisouInterativo) {
641
+ avisouInterativo = true;
642
+ const warn = opts.warn ?? ((m) => console.warn(redactSecrets(m)));
643
+ warn(
644
+ `[sandbox] OS-level enforcement unavailable (${detection.reason}) \u2014 interactive session runs WITHOUT kernel confinement (sandbox_mode=${opts.mode}).`
645
+ );
646
+ }
647
+ return null;
648
+ }
649
+ return wrapCommandForSandbox(
650
+ opts.mode,
651
+ {
652
+ cwd,
653
+ network: opts.network ?? false,
654
+ env: allowlistedEnv(),
655
+ bin: detection.bin,
656
+ seccompPath: restrictedSeccompPath()
657
+ },
658
+ command
659
+ );
660
+ };
661
+ }
662
+
186
663
  // src/errors.ts
187
664
  var TheokitAgentError = class extends Error {
188
665
  name = "TheokitAgentError";
@@ -248,12 +725,29 @@ async function provisionRepo(sandboxOrOpts, maybeOpts) {
248
725
  return { repoDir };
249
726
  }
250
727
 
728
+ exports.LinuxSandbox = LinuxSandbox;
251
729
  exports.LocalSandbox = LocalSandbox;
252
730
  exports.RepoProvisionError = RepoProvisionError;
253
731
  exports.SandboxBackend = SandboxBackend;
254
732
  exports.SandboxNotAvailableError = SandboxNotAvailableError;
255
733
  exports.SandboxSecurityError = SandboxSecurityError;
734
+ exports.allowlistedEnv = allowlistedEnv;
735
+ exports.buildBwrapArgv = buildBwrapArgv;
736
+ exports.buildSeccompFilter = buildSeccompFilter;
737
+ exports.createSandboxBackend = createSandboxBackend;
738
+ exports.detectBwrap = detectBwrap;
739
+ exports.detectBwrapMemoizado = detectBwrapMemoizado;
740
+ exports.interactiveWrapCommand = interactiveWrapCommand;
256
741
  exports.provisionRepo = provisionRepo;
742
+ exports.realProbeCount = realProbeCount;
743
+ exports.realProbes = realProbes;
744
+ exports.resetBwrapMemo = resetBwrapMemo;
745
+ exports.resetInteractiveWarnLatch = resetInteractiveWarnLatch;
746
+ exports.resetSandboxWarnLatch = resetSandboxWarnLatch;
257
747
  exports.resolveSandbox = resolveSandbox;
748
+ exports.resolveSandboxPosture = resolveSandboxPosture;
749
+ exports.restrictedSeccompPath = restrictedSeccompPath;
750
+ exports.seccompPathForArch = seccompPathForArch;
751
+ exports.wrapCommandForSandbox = wrapCommandForSandbox;
258
752
  //# sourceMappingURL=index.cjs.map
259
753
  //# sourceMappingURL=index.cjs.map