@integrity-labs/agt-cli 0.28.95 → 0.28.96

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/dist/bin/agt.js CHANGED
@@ -37,7 +37,7 @@ import {
37
37
  success,
38
38
  table,
39
39
  warn
40
- } from "../chunk-QQYVNV5N.js";
40
+ } from "../chunk-LFTKXQEA.js";
41
41
  import {
42
42
  CHANNEL_REGISTRY,
43
43
  DEPLOYMENT_TEMPLATES,
@@ -4777,7 +4777,7 @@ import { execFileSync, execSync } from "child_process";
4777
4777
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4778
4778
  import chalk18 from "chalk";
4779
4779
  import ora16 from "ora";
4780
- var cliVersion = true ? "0.28.95" : "dev";
4780
+ var cliVersion = true ? "0.28.96" : "dev";
4781
4781
  async function fetchLatestVersion() {
4782
4782
  const host2 = getHost();
4783
4783
  if (!host2) return null;
@@ -5791,7 +5791,7 @@ function handleError(err) {
5791
5791
  }
5792
5792
 
5793
5793
  // src/bin/agt.ts
5794
- var cliVersion2 = true ? "0.28.95" : "dev";
5794
+ var cliVersion2 = true ? "0.28.96" : "dev";
5795
5795
  var program = new Command();
5796
5796
  program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
5797
5797
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -582,6 +582,150 @@ function resolveClaudeBinary() {
582
582
  }
583
583
  return "claude";
584
584
  }
585
+ function isolationMode(codeName) {
586
+ if (process.env.AGT_ISOLATION !== "docker") return "none";
587
+ const allow = (process.env.AGT_ISOLATION_AGENTS ?? "").split(",").map((s) => s.trim()).filter(Boolean);
588
+ if (allow.length > 0 && (!codeName || !allow.includes(codeName))) return "none";
589
+ return "docker";
590
+ }
591
+ var EGRESS_BASELINE_DOMAINS = [
592
+ ".anthropic.com",
593
+ // claude API
594
+ "claude.ai",
595
+ // subscription auth
596
+ ".augmented.team",
597
+ // the host/control-plane API
598
+ ".slack.com",
599
+ // channels (incl. wss)
600
+ ".composio.dev"
601
+ // composio MCP
602
+ ];
603
+ function egressMode(codeName) {
604
+ if (process.env.AGT_EGRESS !== "allowlist") return "none";
605
+ if (isolationMode(codeName) !== "docker") return "none";
606
+ return "allowlist";
607
+ }
608
+ var VALID_EGRESS_DOMAIN = /^\.?([a-z0-9-]+\.)+[a-z0-9-]+$/;
609
+ function buildEgressAllowlist(toolsFrontmatter) {
610
+ const domains = new Set(EGRESS_BASELINE_DOMAINS);
611
+ for (const tool of toolsFrontmatter?.tools ?? []) {
612
+ for (const d of tool.network?.allowlist_domains ?? []) {
613
+ if (typeof d !== "string") continue;
614
+ const norm = d.trim().toLowerCase();
615
+ if (VALID_EGRESS_DOMAIN.test(norm)) domains.add(norm);
616
+ }
617
+ }
618
+ return [...domains].sort();
619
+ }
620
+ function egressAllowlistHostPath(codeName, homeDir) {
621
+ const home = homeDir ?? (process.env.HOME?.trim() || homedir2());
622
+ return join2(home, ".augmented", "_egress", `${codeName}.txt`);
623
+ }
624
+ function writeEgressAllowlist(codeName, domains, homeDir) {
625
+ const p = egressAllowlistHostPath(codeName, homeDir);
626
+ mkdirSync2(dirname(p), { recursive: true });
627
+ writeFileSync3(p, domains.join("\n") + "\n", { mode: 420 });
628
+ return p;
629
+ }
630
+ var EGRESS_DOCKER_TIMEOUT_MS = 1e4;
631
+ function isNoSuchContainer(err) {
632
+ const e = err;
633
+ const text = `${e?.stderr?.toString() ?? ""}${e?.message ?? ""}`;
634
+ return /no such container|is not running/i.test(text);
635
+ }
636
+ function reloadEgressSidecar(codeName) {
637
+ try {
638
+ execFileSync3("docker", ["kill", "--signal=HUP", `agt-squid-${codeName}`], {
639
+ stdio: "pipe",
640
+ timeout: EGRESS_DOCKER_TIMEOUT_MS
641
+ });
642
+ return true;
643
+ } catch (err) {
644
+ if (!isNoSuchContainer(err)) throw err;
645
+ return false;
646
+ }
647
+ }
648
+ function restartEgressSidecar(codeName) {
649
+ try {
650
+ execFileSync3("docker", ["restart", `agt-squid-${codeName}`], {
651
+ stdio: "pipe",
652
+ timeout: EGRESS_DOCKER_TIMEOUT_MS
653
+ });
654
+ return true;
655
+ } catch (err) {
656
+ if (!isNoSuchContainer(err)) throw err;
657
+ return false;
658
+ }
659
+ }
660
+ function buildDockerRunCommand(args) {
661
+ const { codeName, agentId, wrapperPath, projectDir, homeDir, runId, passApiKey, egress } = args;
662
+ const q = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
663
+ const agentDir = join2(homeDir, ".augmented", codeName);
664
+ const agentIdDir = join2(homeDir, ".augmented", agentId);
665
+ const mcpDir = join2(homeDir, ".augmented", "_mcp");
666
+ const claudeHome = join2(homeDir, ".claude");
667
+ const claudeJson = join2(homeDir, ".claude.json");
668
+ const mounts = [
669
+ `-v ${q(`${agentDir}:${agentDir}`)}`,
670
+ `-v ${q(`${agentIdDir}:${agentIdDir}`)}`,
671
+ `-v ${q(`${mcpDir}:${mcpDir}:ro`)}`,
672
+ `-v ${q(`${claudeHome}:${claudeHome}`)}`,
673
+ `-v ${q(`${claudeJson}:${claudeJson}`)}`
674
+ ];
675
+ const image = process.env.AGT_ISOLATION_IMAGE || "agt-runtime:latest";
676
+ const memory = process.env.AGT_ISOLATION_MEMORY || "512m";
677
+ const cpus = process.env.AGT_ISOLATION_CPUS || "1.0";
678
+ const pids = process.env.AGT_ISOLATION_PIDS || "512";
679
+ const envArgs = [`-e ${q(`HOME=${homeDir}`)}`];
680
+ if (passApiKey) envArgs.push("-e ANTHROPIC_API_KEY");
681
+ if (runId) envArgs.push(`-e ${q(`AGT_RUN_ID=${runId}`)}`);
682
+ const egressImage = process.env.AGT_EGRESS_IMAGE || "agt-squid:latest";
683
+ const internalNet = `agt-net-${codeName}`;
684
+ const squidName = `agt-squid-${codeName}`;
685
+ const networkArgs = [];
686
+ let egressSetup = "";
687
+ if (egress) {
688
+ networkArgs.push(`--network ${internalNet}`);
689
+ const proxyUrl = `http://${squidName}:3128`;
690
+ envArgs.push(`-e ${q(`HTTPS_PROXY=${proxyUrl}`)}`);
691
+ envArgs.push(`-e ${q(`HTTP_PROXY=${proxyUrl}`)}`);
692
+ envArgs.push(`-e ${q(`NO_PROXY=${squidName},localhost,127.0.0.1`)}`);
693
+ egressSetup = [
694
+ `docker rm -f ${squidName} agt-${codeName} >/dev/null 2>&1 || true`,
695
+ `docker network create agt-egress >/dev/null 2>&1 || true`,
696
+ // FAIL-CLOSED: a stale or hand-created `agt-net-<codeName>` that is NOT
697
+ // internal would give the agent a route off-net, bypassing the proxy.
698
+ // Don't trust create-if-absent - verify the Internal flag and rebuild the
699
+ // network when it's missing or wrong.
700
+ `{ [ "$(docker network inspect -f '{{.Internal}}' ${internalNet} 2>/dev/null)" = "true" ] || { docker network rm ${internalNet} >/dev/null 2>&1 || true; docker network create --internal ${internalNet} >/dev/null; }; }`,
701
+ // squid processes untrusted agent traffic - give it the same hardening as
702
+ // the agent container (drop all caps, block privilege escalation). squid
703
+ // binds 3128 (>1024) and needs no capabilities; verified it still boots.
704
+ `docker run -d --name ${squidName} --network ${internalNet} --restart unless-stopped --memory 128m --cap-drop ALL --security-opt no-new-privileges -v ${q(`${egress.allowlistHostPath}:/etc/squid/allowlist.txt:ro`)} ${q(egressImage)} >/dev/null`,
705
+ `docker network connect agt-egress ${squidName} >/dev/null 2>&1`
706
+ ].join(" && ");
707
+ }
708
+ const runCmd = [
709
+ "exec docker run --rm -it",
710
+ `--name agt-${codeName}`,
711
+ `--memory ${memory}`,
712
+ `--cpus ${cpus}`,
713
+ `--pids-limit ${pids}`,
714
+ // Defence in depth (red-team 2026-06-16): drop all Linux capabilities and
715
+ // block privilege escalation. claude + node MCP servers need none - verified
716
+ // booting clean under these. The mount namespace is the primary boundary;
717
+ // these shrink what a container-escape CVE could reach if it ever landed.
718
+ "--cap-drop ALL",
719
+ "--security-opt no-new-privileges",
720
+ ...networkArgs,
721
+ ...mounts,
722
+ `-w ${q(projectDir)}`,
723
+ ...envArgs,
724
+ q(image),
725
+ q(wrapperPath)
726
+ ].join(" ");
727
+ return egress ? `${egressSetup} && ${runCmd}` : `docker rm -f agt-${codeName} >/dev/null 2>&1; ${runCmd}`;
728
+ }
585
729
  function writePersistentClaudeWrapper(args) {
586
730
  const { projectDir, claudeBin, initPrompt, claudeArgsJoined } = args;
587
731
  const envIntegrationsPath = join2(projectDir, ".env.integrations");
@@ -840,7 +984,24 @@ function spawnSession(config, session) {
840
984
  if (claudeAuthMode === "api_key" && config.anthropicApiKey) {
841
985
  tmuxSessionEnvArgs.push("-e", `ANTHROPIC_API_KEY=${config.anthropicApiKey}`);
842
986
  }
843
- const claudeCmd = JSON.stringify(wrapperPath);
987
+ const sessionHomeDir = process.env.HOME?.trim() || homedir2();
988
+ let egress;
989
+ if (egressMode(codeName) === "allowlist") {
990
+ const allowlist = config.egressAllowlist ?? buildEgressAllowlist(null);
991
+ const allowlistHostPath = writeEgressAllowlist(codeName, allowlist, sessionHomeDir);
992
+ egress = { allowlistHostPath };
993
+ log(`[persistent-session] egress allowlist for '${codeName}': ${allowlist.length} domains (deny-by-default)`);
994
+ }
995
+ const claudeCmd = isolationMode(codeName) === "docker" ? buildDockerRunCommand({
996
+ codeName,
997
+ agentId: config.agentId,
998
+ wrapperPath,
999
+ projectDir,
1000
+ homeDir: sessionHomeDir,
1001
+ runId: config.runId ?? void 0,
1002
+ passApiKey: claudeAuthMode === "api_key" && !!config.anthropicApiKey,
1003
+ egress
1004
+ }) : JSON.stringify(wrapperPath);
844
1005
  const tmuxEnv = {
845
1006
  ...process.env,
846
1007
  // Treat empty-string as missing too — `HOME=""` makes ~ resolve
@@ -1369,6 +1530,15 @@ export {
1369
1530
  takeWatchdogGiveUpCount,
1370
1531
  creditWatchdogGiveUpCount,
1371
1532
  resolveClaudeBinary,
1533
+ isolationMode,
1534
+ EGRESS_BASELINE_DOMAINS,
1535
+ egressMode,
1536
+ buildEgressAllowlist,
1537
+ egressAllowlistHostPath,
1538
+ writeEgressAllowlist,
1539
+ reloadEgressSidecar,
1540
+ restartEgressSidecar,
1541
+ buildDockerRunCommand,
1372
1542
  writePersistentClaudeWrapper,
1373
1543
  paneLogPath,
1374
1544
  readPaneLogTail,
@@ -1395,4 +1565,4 @@ export {
1395
1565
  stopAllSessionsAndWait,
1396
1566
  getProjectDir
1397
1567
  };
1398
- //# sourceMappingURL=chunk-JYSWJMXU.js.map
1568
+ //# sourceMappingURL=chunk-5NQ652SP.js.map