@finalai/final-agent-provider 0.4.2 → 0.4.4
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.
|
@@ -836,6 +836,7 @@ def apply(request):
|
|
|
836
836
|
raise RuntimeError('Workspace egress lease is expired or exceeds fifteen minutes')
|
|
837
837
|
config['bootId'] = BOOT_ID
|
|
838
838
|
config['deadlineMonotonic'] = time.monotonic() + min(remaining, 15 * 60 * 1000) / 1000
|
|
839
|
+
# The sandbox user can replace staging files; validate and install the same bytes.
|
|
839
840
|
staged = pathlib.Path(request['helperPath'])
|
|
840
841
|
try: fd = os.open(staged, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)
|
|
841
842
|
except FileNotFoundError as failure:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/sandboxes/egress-bootstrap.ts"],
|
|
4
|
-
"sourcesContent": ["// The same controller runs in ordinary Linux provider namespaces; no VM platform API is used.\nexport const workspaceEgressBootstrap = String.raw`import collections, errno, fcntl, hashlib, ipaddress, json, os, pathlib, platform, re, shutil, signal, shlex, socket, stat, struct, subprocess, sys, tempfile, threading, time, urllib.parse, uuid\n\nROOT = pathlib.Path('/run/final-workspace-egress')\nPERSISTENT = pathlib.Path('/var/lib/final-workspace-egress')\nRESOLVER = pathlib.Path('/etc/resolv.conf')\nHOSTS = pathlib.Path('/etc/hosts')\nCHAIN = 'FINAL-EGRESS'\nREPLY = 'FINAL-EGRESS-REPLY'\nFORWARD = 'FINAL-EGRESS-FWD'\nNAT = 'FINAL-EGRESS-NAT'\nMARK = '0x80000/0xff0000'\nos.environ['PATH'] = '/usr/sbin:/usr/bin:/sbin:/bin'\nos.environ.pop('SSL_CERT_FILE', None)\nos.environ.pop('SSL_CERT_DIR', None)\n# Prime autoload before choosing families; later kernel enablement requires reinitialization.\ntry: socket.socket(socket.AF_INET6, socket.SOCK_DGRAM).close()\nexcept OSError as failure:\n if failure.errno not in (errno.EAFNOSUPPORT, errno.EPROTONOSUPPORT, errno.EPERM, errno.EACCES): raise\nFAMILIES = ('iptables', 'ip6tables') if pathlib.Path('/proc/net/if_inet6').exists() else ('iptables',)\n\nclass WorkspaceConflictError(RuntimeError):\n pass\n\nclass PrerequisiteError(RuntimeError):\n pass\n\nclass DenialUnavailableError(RuntimeError):\n pass\n\nclass EnrollmentLostError(RuntimeError):\n pass\n\n\ndef command(*args, check=True, timeout=25):\n if args[0] in ('iptables', 'ip6tables') and '--version' not in args: args = (args[0], '-w', '5', *args[1:])\n result = subprocess.run(args, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout)\n if check and result.returncode != 0:\n raise RuntimeError('Workspace networking command failed: ' + ' '.join(args[:4]))\n return result\n\ndef atomic(path, value, binary=False, mode=0o600):\n staged = None\n try:\n with tempfile.NamedTemporaryFile(dir=path.parent, delete=False) as out:\n staged = pathlib.Path(out.name)\n out.write(value if binary else json.dumps(value).encode())\n out.flush(); os.fsync(out.fileno())\n os.chmod(staged, mode)\n os.replace(staged, path)\n directory = os.open(path.parent, os.O_RDONLY | os.O_DIRECTORY)\n try: os.fsync(directory)\n finally: os.close(directory)\n finally:\n if staged is not None: staged.unlink(missing_ok=True)\n\ndef managed_text(path, content):\n data = content.encode()\n try: atomic(path, data, binary=True, mode=0o644)\n except OSError as failure:\n if failure.errno != errno.EBUSY: raise\n # Docker bind-mounted files cannot be replaced; never follow a raced-in symlink.\n pending = PERSISTENT / 'resolver-write-pending.json' if path == RESOLVER else None\n if pending is not None: atomic(pending, True)\n fd = os.open(path, os.O_WRONLY | os.O_NOFOLLOW | os.O_NONBLOCK)\n with os.fdopen(fd, 'wb') as out:\n if not stat.S_ISREG(os.fstat(out.fileno()).st_mode): raise RuntimeError('Managed network file must be regular')\n os.ftruncate(out.fileno(), 0)\n out.write(data); out.flush(); os.fsync(out.fileno())\n if pending is not None: pending.unlink(missing_ok=True)\n\ndef load(path, default=None):\n try:\n return json.loads(path.read_text())\n except FileNotFoundError:\n return default\n\ndef prerequisite(action):\n if sys.version_info < (3, 8):\n raise PrerequisiteError('Device egress requires Python 3.8 or newer')\n if sys.platform != 'linux' or os.geteuid() != 0:\n raise PrerequisiteError('Device egress requires an isolated Linux workspace with privileged networking access')\n ROOT.mkdir(mode=0o700, exist_ok=True)\n if ROOT.is_symlink() or ROOT.stat().st_uid != 0:\n raise RuntimeError('Workspace egress state must be a root-owned directory')\n ROOT.chmod(0o700)\n direct = not load(ROOT / 'config.json') or (load(ROOT / 'config.json', {}).get('mode') == 'direct' and load(ROOT / 'status.json', {}).get('mode') == 'direct')\n if action in ('status', 'artifact', 'claim', 'unlock') or (action == 'disable' and (direct or load(ROOT / 'config.json', {}).get('noNetworkChanges') is True)): return\n if action in ('configure', 'renew') and not pathlib.Path('/dev/net/tun').exists():\n raise PrerequisiteError('This sandbox provider does not expose /dev/net/tun')\n command('ip', '-V')\n for family in FAMILIES:\n command(family, '--version'); command(family + '-restore', '--version')\n\nBOOT_ID = pathlib.Path('/proc/sys/kernel/random/boot_id').read_text().strip()\n\ndef existing_control_replies():\n saved = load(ROOT / 'control-replies.json')\n sockets = []\n for table in ('tcp', 'tcp6'):\n def address(value):\n host, port = value.split(':')\n raw = bytes.fromhex(host)\n raw = b''.join(raw[i:i+4][::-1] for i in range(0, len(raw), 4))\n ip = ipaddress.ip_address(raw)\n if isinstance(ip, ipaddress.IPv6Address) and ip.ipv4_mapped is not None: ip = ip.ipv4_mapped\n return str(ip), int(port, 16)\n source = pathlib.Path('/proc/net/' + table)\n if not source.exists(): continue\n for line in source.read_text().splitlines()[1:]:\n columns = line.split()\n if columns[3] in ('01', '0A'): sockets.append((address(columns[1]), address(columns[2]), columns[3], int(columns[7])))\n addresses = json.loads(command('ip', '-j', 'addr', 'show').stdout)\n local_addresses = {ipaddress.ip_address(address['local']) for interface in addresses for address in interface.get('addr_info', [])}\n bridge_networks = [ipaddress.ip_network(network) for _, network in local_bridges()]\n listeners = [local for local, remote, state, uid in sockets if state == '0A' and not ipaddress.ip_address(local[0]).is_loopback]\n replies = []\n for local, remote, state, uid in sockets:\n # Only privileged provider sockets may use the pre-conntrack compatibility exception.\n remote_ip = ipaddress.ip_address(remote[0])\n if uid != 0 or state != '01' or remote_ip.is_loopback or remote_ip in local_addresses: continue\n if any(remote_ip.version == network.version and remote_ip in network for network in bridge_networks): continue\n if any(port == local[1] and (ipaddress.ip_address(host).is_unspecified or host == local[0]) for host, port in listeners):\n replies.append({'source': local[0], 'sourcePort': local[1], 'destination': remote[0], 'destinationPort': remote[1], 'uid': 0})\n if saved is not None and any(reply.get('uid') != 0 for reply in saved): saved = None\n capture_overflow = saved is None and len(replies) > 128\n if saved is not None: replies = saved\n server_ports = [{'source': host, 'sourcePort': port} for host, port in listeners]\n for prior in load(ROOT / 'control-listeners.json', []):\n if any(local[1] == prior['sourcePort'] and state == '01' for local, remote, state, uid in sockets): server_ports.append(prior)\n # A dual-stack listener appears in tcp6 even when the accepted transport uses IPv4.\n server_ports += [{'source': reply['source'], 'sourcePort': reply['sourcePort']} for reply in replies]\n server_ports = [dict(source=host, sourcePort=port) for host, port in sorted({(item['source'], item['sourcePort']) for item in server_ports})]\n prior = load(ROOT / 'control-listeners.json', [])\n privileged = {local for local, remote, state, uid in sockets if state == '0A' and uid == 0}\n server_ports.sort(key=lambda item: (item not in prior, (item['source'], item['sourcePort']) not in privileged))\n atomic(ROOT / 'control-listeners.json', server_ports[:256])\n if len(server_ports) > 256:\n atomic(ROOT / 'listener-limit.json', {'limit': 256, 'observed': len(server_ports)})\n else: (ROOT / 'listener-limit.json').unlink(missing_ok=True)\n if capture_overflow: raise RuntimeError('Too many existing inbound control connections')\n atomic(ROOT / 'control-replies.json', replies)\n return replies\n\ndef local_bridges():\n result = []\n # Minimal VM kernels can reject a type-filtered dump; ordinary link dumps remain portable.\n links = json.loads(command('ip', '-j', '-d', 'link', 'show').stdout)\n by_name = {link['ifname']: link for link in links}\n uplinks = set()\n for route in json.loads(command('ip', '-j', '-4', 'route', 'show', 'table', 'all').stdout):\n if route.get('dst') == 'default' or route.get('gateway') is not None or route.get('nexthops'):\n uplinks.add(route.get('dev'))\n uplinks.update(hop.get('dev') for hop in route.get('nexthops', []))\n for link in links:\n if link.get('linkinfo', {}).get('info_kind') != 'bridge': continue\n try: members = list((pathlib.Path('/sys/class/net') / link['ifname'] / 'brif').iterdir())\n except FileNotFoundError: continue\n if link['ifname'] in uplinks or any(member.name in uplinks or by_name.get(member.name, {}).get('linkinfo', {}).get('info_kind') != 'veth' for member in members): continue\n name = link['ifname']\n if not re.fullmatch(r'[A-Za-z0-9_.-]{1,15}', name): raise RuntimeError('Unsupported local bridge name')\n for interface in json.loads(command('ip', '-j', '-4', 'addr', 'show', 'dev', name).stdout):\n for address in interface.get('addr_info', []):\n if address.get('family') == 'inet': result.append((name, str(ipaddress.ip_network(address['local'] + '/' + str(address['prefixlen']), strict=False))))\n return sorted(result)\n\ndef install_guard(allow_tunnel=False, closed=False):\n if closed: allow_tunnel = False\n replies = [reply for reply in load(ROOT / 'control-replies.json', []) if reply.get('uid') == 0] if closed else existing_control_replies()\n bridges = [] if closed else local_bridges()\n try: listeners = load(ROOT / 'control-listeners.json', [])\n except Exception:\n if not closed: raise\n listeners = []\n if closed: tunnel_addresses = load(ROOT / 'tunnel-addresses.json', [])\n else:\n tunnel = command('ip', '-j', 'addr', 'show', 'dev', 'final-egress0', check=False)\n tunnel_addresses = [str(ipaddress.ip_address(address['local'])) for interface in json.loads(tunnel.stdout or b'[]') for address in interface.get('addr_info', [])]\n atomic(ROOT / 'tunnel-addresses.json', tunnel_addresses)\n for family in FAMILIES:\n rules = ['*filter', ':' + CHAIN + ' - [0:0]', '-F ' + CHAIN]\n # Block namespace-local DNS stubs that would otherwise resolve on the provider's network.\n for proto in ('tcp', 'udp'):\n rules.append('-A ' + CHAIN + ' -o lo -p ' + proto + ' --dport 53 -j REJECT')\n if family == 'iptables':\n rules.append('-A ' + CHAIN + ' -d 127.0.0.11 -j REJECT')\n rules.append('-A ' + CHAIN + ' -d 100.100.100.100 -j REJECT')\n rules += ['-A ' + CHAIN + ' -o lo -j ACCEPT', '-A ' + CHAIN + ' -m mark --mark ' + MARK + ' -m owner --uid-owner 0 -j ACCEPT', '-A ' + CHAIN + ' -m mark --mark ' + MARK + ' -m conntrack --ctdir REPLY -j ACCEPT']\n if family == 'ip6tables':\n for kind in (133, 134, 135, 136):\n rules += ['-A ' + CHAIN + ' -p ipv6-icmp --icmpv6-type ' + str(kind) + ' -m owner --uid-owner 1-4294967294 -j REJECT',\n '-A ' + CHAIN + ' -p ipv6-icmp --icmpv6-type ' + str(kind) + ' -j ACCEPT']\n if family == 'iptables':\n for name, network in bridges: rules.append('-A ' + CHAIN + ' -o ' + name + ' -d ' + network + ' -j ACCEPT')\n if family == 'iptables' and allow_tunnel:\n rules.append('-A ' + CHAIN + ' -o final-egress0 -j ACCEPT')\n if closed:\n for reply in replies:\n if (':' in reply['source']) != (family == 'ip6tables'): continue\n rules.append('-A ' + CHAIN + ' -p tcp -s ' + reply['source'] + ' --sport ' + str(reply['sourcePort']) + ' -d ' + reply['destination'] + ' --dport ' + str(reply['destinationPort']) + ' --tcp-flags SYN,RST,ACK ACK -j ACCEPT')\n rules += ['-A ' + CHAIN + ' -j REJECT', 'COMMIT', '*mangle', ':' + REPLY + ' - [0:0]', '-F ' + REPLY,\n # Docker rewrites its DNS stub's port in nat/OUTPUT; block before that translation.\n '-A ' + REPLY + ' -o lo -p tcp --dport 53 -j DROP',\n '-A ' + REPLY + ' -o lo -p udp --dport 53 -j DROP',\n ]\n if family == 'iptables': rules.append('-A ' + REPLY + ' -d 127.0.0.11 -j DROP')\n # mangle/OUTPUT sees the initial exit route even for physical provider replies.\n # Exclude only the actual tunnel source addresses before marking server replies.\n for address in tunnel_addresses:\n if (':' in address) == (family == 'ip6tables'):\n rules.append('-A ' + REPLY + ' -s ' + address + ' -j RETURN')\n # Minimal provider kernels omit connmark. Reserve the existing server ports for TCP replies;\n # an untracked outgoing client's ephemeral port cannot obtain this exception.\n for listener in listeners:\n host = listener['source']\n address = ipaddress.ip_address(host)\n if (':' in host) != (family == 'ip6tables') and not (family == 'iptables' and address.version == 6 and address.is_unspecified): continue\n source = '' if ipaddress.ip_address(host).is_unspecified else ' -s ' + host\n rules.append('-A ' + REPLY + ' -p tcp' + source + ' --sport ' + str(listener['sourcePort']) +\n ' -m conntrack --ctdir REPLY --ctorigdstport ' + str(listener['sourcePort']) + ' -j MARK --set-xmark ' + MARK)\n # Conntrack can load after a provider's long-lived inbound RPC already opened (E2B envd).\n # Preserve only ACKs on those accepted server sockets, never a new outbound SYN.\n for reply in replies:\n if (':' in reply['source']) != (family == 'ip6tables'): continue\n rules.append('-A ' + REPLY + ' -p tcp -s ' + reply['source'] + ' --sport ' + str(reply['sourcePort']) +\n ' -d ' + reply['destination'] + ' --dport ' + str(reply['destinationPort']) +\n ' --tcp-flags SYN,RST,ACK ACK -j MARK --set-xmark ' + MARK)\n rules.append('COMMIT')\n # Docker can prepend filter/FORWARD accepts; mangle runs before that table.\n rules += ['*mangle', ':' + FORWARD + ' - [0:0]', '-F ' + FORWARD]\n if family == 'iptables': rules.append('-A ' + FORWARD + ' -d 100.100.100.100 -j DROP')\n if family == 'iptables':\n for name, network in bridges:\n for ingress, _ in bridges: rules.append('-A ' + FORWARD + ' -i ' + ingress + ' -o ' + name + ' -d ' + network + ' -j RETURN')\n if family == 'iptables' and allow_tunnel:\n for name, network in bridges:\n rules += ['-A ' + FORWARD + ' -i ' + name + ' -s ' + network + ' -o final-egress0 -j RETURN',\n '-A ' + FORWARD + ' -i final-egress0 -o ' + name + ' -d ' + network + ' -m conntrack --ctstate ESTABLISHED,RELATED -j RETURN']\n rules += ['-A ' + FORWARD + ' -j DROP', 'COMMIT']\n rules += ['*filter', ':' + FORWARD + ' - [0:0]', '-F ' + FORWARD]\n if family == 'iptables': rules.append('-A ' + FORWARD + ' -d 100.100.100.100 -j DROP')\n if family == 'iptables':\n for name, network in bridges:\n for ingress, _ in bridges: rules.append('-A ' + FORWARD + ' -i ' + ingress + ' -o ' + name + ' -d ' + network + ' -j RETURN')\n if family == 'iptables' and allow_tunnel:\n for name, network in bridges:\n rules += ['-A ' + FORWARD + ' -i ' + name + ' -s ' + network + ' -o final-egress0 -j ACCEPT',\n '-A ' + FORWARD + ' -i final-egress0 -o ' + name + ' -d ' + network + ' -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT']\n rules += ['-A ' + FORWARD + ' -j REJECT', 'COMMIT']\n if family == 'iptables':\n rules += ['*nat', ':' + NAT + ' - [0:0]', '-F ' + NAT]\n for name, network in bridges:\n rules.append('-A ' + NAT + ' -s ' + network + ' -o final-egress0 -j MASQUERADE')\n rules.append('COMMIT')\n installed = subprocess.run([family + '-restore', '-w', '5', '--noflush'], timeout=25, input=('\\n'.join(rules) + '\\n').encode(), stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)\n if installed.returncode: raise RuntimeError(family + ' firewall installation failed: ' + installed.stderr.decode(errors='replace')[:800])\n hooks = [('mangle', 'OUTPUT', REPLY), ('mangle', 'FORWARD', FORWARD), ('filter', 'OUTPUT', CHAIN), ('filter', 'FORWARD', FORWARD)]\n if family == 'iptables': hooks.append(('nat', 'POSTROUTING', NAT))\n for table, hook, chain in hooks:\n if command(family, '-t', table, '-C', hook, '-j', chain, check=False).returncode != 0:\n command(family, '-t', table, '-I', hook, '1', '-j', chain)\n # Reverse-NAT replies from TUN must return to a nested bridge rather than the exit default route.\n if allow_tunnel:\n while command('ip', '-4', 'rule', 'del', 'pref', '5210', 'iif', 'final-egress0', 'lookup', 'main', 'protocol', '242', check=False).returncode == 0: pass\n existing = command('ip', '-4', 'rule', 'show').stdout.decode()\n for name, network in bridges:\n if not any('to ' + value + ' iif final-egress0 lookup main' in existing for value in (network, network[:-3] if network.endswith('/32') else network)):\n command('ip', '-4', 'rule', 'add', 'pref', '5210', 'iif', 'final-egress0', 'to', network, 'lookup', 'main', 'protocol', '242')\n existing_rules = command('ip', '-4', 'rule', 'show').stdout.decode() if bridges else ''\n for name, network in bridges:\n if not any('to ' + value + ' lookup main' in existing_rules for value in (network, network[:-3] if network.endswith('/32') else network)):\n command('ip', '-4', 'rule', 'add', 'pref', '5210', 'to', network, 'lookup', 'main', 'protocol', '242')\n\ndef chain_hooked(family, table, hook, chain):\n result = command(family, '-t', table, '-S', check=False)\n if result.returncode != 0:\n if table != 'filter' and result.returncode == 3 and b'Table does not exist' in result.stderr: return False\n raise RuntimeError('Cannot inspect namespace firewall hooks')\n return ('-A ' + hook + ' -j ' + chain) in result.stdout.decode().splitlines()\n\ndef denial_present():\n for family in FAMILIES:\n for hook, chain in [('OUTPUT', CHAIN), ('FORWARD', FORWARD)]:\n if not chain_hooked(family, 'filter', hook, chain): return False\n rules = command(family, '-t', 'filter', '-S', chain, check=False)\n if rules.returncode or not any(shlex.split(line)[:4] in (['-A', chain, '-j', 'DROP'], ['-A', chain, '-j', 'REJECT']) for line in rules.stdout.decode().splitlines()): return False\n return True\n\ndef restoration_pending():\n if load(ROOT / 'config.json', {}).get('mode') == 'error' or load(ROOT / 'status.json', {}).get('mode') == 'error': return True\n if (PERSISTENT / 'hosts.original').exists() or (PERSISTENT / 'resolver.original').exists() or (not HOSTS.is_symlink() and HOSTS.exists() and '# final-workspace-egress' in HOSTS.read_text()): return True\n if RESOLVER.exists() and RESOLVER.read_bytes().startswith(b'# Final workspace egress\\n'): return True\n if not all(shutil.which(family) for family in FAMILIES):\n return (PERSISTENT / 'identity.json').exists() or load(ROOT / 'config.json', {}).get('mode', 'direct') != 'direct'\n try:\n return any(chain_hooked(family, table, hook, chain)\n for family in FAMILIES\n for table, hook, chain in [('filter', 'OUTPUT', CHAIN), ('filter', 'FORWARD', FORWARD), ('mangle', 'OUTPUT', REPLY), ('mangle', 'FORWARD', FORWARD)] + ([('nat', 'POSTROUTING', NAT)] if family == 'iptables' else []))\n except RuntimeError:\n # Never-managed images need no repair when their provider denies firewall inspection.\n if not (PERSISTENT / 'identity.json').exists() and load(ROOT / 'config.json', {}).get('mode', 'direct') == 'direct': return False\n raise\n\ndef restore():\n transport_hosts({})\n original = PERSISTENT / 'resolver.original'\n if not original.exists() and (load(PERSISTENT / 'resolver-write-pending.json', False) or (RESOLVER.exists() and RESOLVER.read_bytes().startswith(b'# Final workspace egress\\n'))):\n raise RuntimeError('Original workspace resolver backup is missing; repair the provider resolver before Disable')\n if original.exists():\n current = RESOLVER\n if load(PERSISTENT / 'resolver-write-pending.json', False) or not current.exists() or current.read_text().startswith('# Final workspace egress\\n'):\n link = load(PERSISTENT / 'resolver-link.json')\n if link is None:\n if load(PERSISTENT / 'resolver-absent.json', False): current.unlink(missing_ok=True)\n else:\n if current.is_symlink(): current.unlink()\n managed_text(current, original.read_text())\n else:\n staged = current.parent / ('.final-egress-resolver-' + uuid.uuid4().hex)\n try:\n os.symlink(link['target'], staged); os.replace(staged, current)\n finally: staged.unlink(missing_ok=True)\n (PERSISTENT / 'resolver-write-pending.json').unlink(missing_ok=True)\n original.unlink()\n (PERSISTENT / 'resolver-link.json').unlink(missing_ok=True)\n (PERSISTENT / 'resolver-absent.json').unlink(missing_ok=True)\n for family in FAMILIES:\n hooks = [('filter', 'OUTPUT', CHAIN), ('mangle', 'OUTPUT', REPLY), ('mangle', 'FORWARD', FORWARD), ('filter', 'FORWARD', FORWARD)]\n if family == 'iptables': hooks.append(('nat', 'POSTROUTING', NAT))\n for table, hook, chain in hooks:\n while chain_hooked(family, table, hook, chain):\n command(family, '-t', table, '-D', hook, '-j', chain)\n command(family, '-t', table, '-F', chain, check=False)\n command(family, '-t', table, '-X', chain, check=False)\n while command('ip', '-4', 'rule', 'del', 'pref', '5210', 'protocol', '242', 'lookup', 'main', check=False).returncode == 0: pass\n for saved in ('control-replies.json', 'control-listeners.json', 'listener-limit.json', 'tunnel-addresses.json'):\n (ROOT / saved).unlink(missing_ok=True)\n (PERSISTENT / 'identity.json').unlink(missing_ok=True)\n (PERSISTENT / 'intent.json').unlink(missing_ok=True)\n\ndef validated_resolvers(addresses):\n if not isinstance(addresses, list) or not addresses or len(addresses) > 3:\n raise RuntimeError('One to three IPv4 DNS resolvers are required')\n addresses = [str(ipaddress.IPv4Address(address)) for address in addresses]\n if len(set(addresses)) != len(addresses) or any(int(address.split('.')[0]) in (0, 127) or int(address.split('.')[0]) >= 224 or address == '100.100.100.100' for address in addresses):\n raise RuntimeError('Device DNS resolvers must be unique reachable unicast addresses')\n return addresses\n\ndef resolver(addresses):\n addresses = validated_resolvers(addresses)\n source = RESOLVER\n if not (PERSISTENT / 'resolver.original').exists():\n if source.exists() and source.read_bytes().startswith(b'# Final workspace egress\\n'):\n raise RuntimeError('Original workspace resolver backup is missing; repair the provider resolver')\n absent = not source.exists() and not source.is_symlink()\n try: original = source.read_bytes()\n except FileNotFoundError: original = b''\n atomic(PERSISTENT / 'resolver-absent.json', absent)\n if source.is_symlink(): atomic(PERSISTENT / 'resolver-link.json', {'target': os.readlink(source)})\n else: (PERSISTENT / 'resolver-link.json').unlink(missing_ok=True)\n atomic(PERSISTENT / 'resolver.original', original, binary=True)\n content = '# Final workspace egress\\n' + ''.join('nameserver ' + address + '\\n' for address in addresses) + 'options timeout:2 attempts:2\\n'\n if not source.is_symlink() and source.exists() and source.read_bytes() == content.encode(): return\n managed_text(source, content)\n\ndef transport_hosts(hosts):\n original = PERSISTENT / 'hosts.original'\n absent = PERSISTENT / 'hosts-absent.json'\n if HOSTS.is_symlink():\n if hosts: raise PrerequisiteError('Workspace egress requires a regular /etc/hosts file')\n if original.exists():\n if load(absent, False): HOSTS.unlink()\n else: atomic(HOSTS, original.read_bytes(), binary=True, mode=0o644)\n original.unlink(); absent.unlink(missing_ok=True)\n return\n if hosts and not original.exists():\n atomic(absent, not HOSTS.exists())\n atomic(original, HOSTS.read_bytes() if HOSTS.exists() else b'', binary=True)\n if not HOSTS.exists() and not hosts:\n if original.exists() and not load(absent, False): atomic(HOSTS, original.read_bytes(), binary=True, mode=0o644)\n original.unlink(missing_ok=True); absent.unlink(missing_ok=True)\n return\n lines = HOSTS.read_text().splitlines() if HOSTS.exists() else []\n lines = [line for line in lines if not line.endswith('# final-workspace-egress')]\n for host, address in hosts.items():\n if not host or any(c not in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-' for c in host):\n raise RuntimeError('Invalid egress transport hostname')\n lines.append(str(ipaddress.IPv4Address(address)) + ' ' + host + ' # final-workspace-egress')\n content = '\\n'.join(lines) + '\\n'\n if not hosts and load(absent, False) and not lines: HOSTS.unlink(missing_ok=True)\n elif not HOSTS.exists() or HOSTS.read_text() != content: managed_text(HOSTS, content)\n if not hosts:\n original.unlink(missing_ok=True); absent.unlink(missing_ok=True)\n\ndef status(mode, config, **extra):\n try: policy_routing = command('ip', '-4', 'rule', 'show', check=False).returncode == 0\n except FileNotFoundError: policy_routing = False\n result = {'mode': mode, 'leaseId': config.get('leaseId'), 'ownerUserId': config.get('ownerUserId'),\n 'workspaceId': config.get('workspaceId'), 'architecture': platform.machine(), 'policyRouting': policy_routing, 'expiresAtMs': config.get('expiresAtMs'), 'deviceId': None, 'path': None, **extra}\n atomic(ROOT / 'status.json', result)\n return result\n\ndef controller_status(mode, config, **extra):\n # A writer may await daemon shutdown while holding this lock; skip stale/busy publication.\n with open(ROOT / 'request.lock', 'a') as requests:\n try: fcntl.flock(requests, fcntl.LOCK_EX | fcntl.LOCK_NB)\n except BlockingIOError: return\n saved = load(ROOT / 'config.json', {})\n fields = ('mode', 'revision', 'leaseId', 'workspaceId', 'ownerUserId', 'expiresAtMs', 'state')\n if any(saved.get(field) != config.get(field) for field in fields): return\n return status(mode, config, **extra)\n\ndef lease_id(value):\n if not isinstance(value, str) or not value: raise RuntimeError('Missing workspace lease identifier')\n return value\n\ndef lease_state_name(value):\n value = lease_id(value)\n try: return str(uuid.UUID(value))\n except ValueError: return 'opaque-' + hashlib.sha256(value.encode()).hexdigest()\n\ndef helper_environment():\n env = {'PATH': '/usr/sbin:/usr/bin:/sbin:/bin'}\n env.update(FINAL_TAILSCALE_MANAGED='1', FINAL_DEVICE_PARENT_PID=str(os.getpid()), TS_NO_LOGS_NO_SUPPORT='true', TS_DEBUG_ENV_FILE='/dev/null', TS_LOGS_DIR=str(ROOT / 'logs'))\n return env\n\ndef cli(helper, sock, *args):\n # CLI operations are managed children as well: closing their pipe stops them on controller death.\n env = helper_environment()\n errors = os.open(ROOT / 'last-control-error.log', os.O_WRONLY | os.O_CREAT | os.O_TRUNC | os.O_NOFOLLOW, 0o600)\n try:\n proc = subprocess.Popen([str(helper), 'final-cli', '--socket=' + str(sock), *args], stdin=subprocess.PIPE,\n stdout=subprocess.PIPE, stderr=errors, env=env)\n finally: os.close(errors)\n try:\n proc.stdin.write(b'final-device-start\\n'); proc.stdin.flush()\n deadline = time.monotonic() + 20\n output = bytearray()\n os.set_blocking(proc.stdout.fileno(), False)\n while proc.poll() is None:\n chunk = proc.stdout.read(65536)\n if chunk: output.extend(chunk)\n if len(output) > 1024 * 1024 or time.monotonic() > deadline:\n raise RuntimeError('Workspace egress control operation exceeded its limit: ' + args[0])\n time.sleep(.01)\n output.extend(proc.stdout.read() or b'')\n if proc.returncode != 0:\n detail = ': ' + bytes(output).decode(errors='replace')[:1000] if args[0] == 'ping' else ''\n raise RuntimeError('Workspace egress control operation failed (' + args[0] + ')' + detail)\n return bytes(output)\n finally:\n try: proc.stdin.close()\n except BrokenPipeError: pass\n if proc.poll() is None: proc.kill()\n proc.wait()\n\ndef stop(proc):\n if proc is not None:\n try: proc.stdin.close()\n except BrokenPipeError: pass\n try: proc.wait(timeout=2)\n except subprocess.TimeoutExpired: proc.kill(); proc.wait()\n\ndef minimal_guard():\n failures = []\n # Cached accepted sockets permit recovery even without conntrack or mangle.\n try: replies = [reply for reply in load(ROOT / 'control-replies.json', []) if reply.get('uid') == 0]\n except Exception: replies = []\n for family in FAMILIES:\n try:\n for hook, chain in [('OUTPUT', CHAIN), ('FORWARD', FORWARD)]:\n existing = command(family, '-t', 'filter', '-S', chain, check=False)\n hooked = command(family, '-t', 'filter', '-C', hook, '-j', chain, check=False)\n # Retain a successfully installed closed family and its control exceptions.\n if existing.returncode == 0 and hooked.returncode == 0 and b'-o final-egress0' not in existing.stdout and any(shlex.split(line)[:4] in (['-A', chain, '-j', 'DROP'], ['-A', chain, '-j', 'REJECT']) for line in existing.stdout.decode().splitlines()): continue\n rules = ['*filter', ':' + chain + ' - [0:0]', '-F ' + chain]\n if hook == 'OUTPUT':\n for proto in ('tcp', 'udp'):\n rules.append('-A ' + chain + ' -o lo -p ' + proto + ' --dport 53 -j DROP')\n if family == 'iptables':\n rules += ['-A ' + chain + ' -d 127.0.0.11 -j DROP', '-A ' + chain + ' -d 100.100.100.100 -j DROP']\n rules.append('-A ' + chain + ' -o lo -j ACCEPT')\n if family == 'ip6tables':\n for kind in (133, 134, 135, 136):\n rules += ['-A ' + chain + ' -p ipv6-icmp --icmpv6-type ' + str(kind) + ' -m owner --uid-owner 1-4294967294 -j REJECT',\n '-A ' + chain + ' -p ipv6-icmp --icmpv6-type ' + str(kind) + ' -j ACCEPT']\n for reply in replies:\n if (':' in reply['source']) != (family == 'ip6tables'): continue\n rules.append('-A ' + chain + ' -p tcp -s ' + reply['source'] + ' --sport ' + str(reply['sourcePort']) +\n ' -d ' + reply['destination'] + ' --dport ' + str(reply['destinationPort']) +\n ' --tcp-flags SYN,RST,ACK ACK -j ACCEPT')\n rules += ['-A ' + chain + ' -j DROP', 'COMMIT']\n result = subprocess.run([family + '-restore', '-w', '5', '--noflush'], input=('\\n'.join(rules) + '\\n').encode(), capture_output=True, timeout=25)\n if result.returncode and family == 'ip6tables':\n # Without owner matching, deny IPv6 neighbor traffic too rather than leaving the family open.\n fallback = [rule for rule in rules if '-p ipv6-icmp ' not in rule]\n result = subprocess.run([family + '-restore', '-w', '5', '--noflush'], input=('\\n'.join(fallback) + '\\n').encode(), capture_output=True, timeout=25)\n if result.returncode: raise RuntimeError('Atomic emergency denial failed for ' + family)\n if hooked.returncode != 0: command(family, '-t', 'filter', '-I', hook, '1', '-j', chain)\n except Exception as cause: failures.append(str(cause))\n if failures: raise RuntimeError('Cannot install minimal namespace denial: ' + '; '.join(failures))\n\ndef guard(allow_tunnel=False):\n try: install_guard(allow_tunnel)\n except Exception:\n try: install_guard(closed=True)\n except Exception:\n try: minimal_guard()\n except Exception as failure:\n raise DenialUnavailableError('Workspace network denial could not be installed') from failure\n raise\n\ndef clear_identity():\n for path in ROOT.glob('state-*'):\n if path.is_file(): path.unlink()\n (ROOT / 'enrollment.key').unlink(missing_ok=True)\n\ndef stop_controller():\n with open(ROOT / 'daemon.lock', 'a') as lock:\n deadline = time.monotonic() + 5\n signaled = None\n while True:\n pid = load(ROOT / 'controller.pid')\n if isinstance(pid, int) and pid != signaled:\n try:\n args = pathlib.Path('/proc/' + str(pid) + '/cmdline').read_bytes().split(bytes([0]))\n if str(ROOT / 'controller.py').encode() in args and b'run' in args:\n os.kill(pid, signal.SIGTERM); signaled = pid\n except ProcessLookupError: pass\n except FileNotFoundError: pass\n try:\n fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)\n clear_identity()\n return\n except BlockingIOError:\n if time.monotonic() >= deadline: raise RuntimeError('Workspace egress controller did not stop')\n time.sleep(.05)\n\ndef capture_errors(proc):\n tail = collections.deque(maxlen=128)\n while True:\n chunk = proc.stderr.read1(4096)\n if not chunk: return\n tail.append(chunk)\n atomic(ROOT / 'daemon.log', b''.join(tail), binary=True)\n\ndef select_exit(config, peers, selected, health_misses, helper, sock):\n candidates = sorted(config.get('devices', []), key=lambda item: item.get('tailscaleIp') != selected)\n for item in candidates:\n ip = item.get('tailscaleIp')\n if ip not in peers or not peers[ip].get('Online') or peers[ip].get('Expired'): continue\n try:\n # TSMP tests the encrypted peer path without opening a destination connection.\n cli(helper, sock, 'ping', '--tsmp', '--c=1', '--timeout=2s', str(ipaddress.IPv4Address(ip)))\n health_misses[ip] = 0\n return item\n except (RuntimeError, ValueError) as cause:\n atomic(ROOT / 'last-peer-error.json', {'deviceId': item['deviceId'], 'error': str(cause), 'atMs': int(time.time() * 1000)})\n health_misses[ip] = health_misses.get(ip, 0) + 1\n if ip == selected and health_misses[ip] < 3: break\n continue\n return None\n\ndef run():\n with open(ROOT / 'daemon.lock', 'a') as lock:\n deadline = time.monotonic() + 5\n while True:\n try:\n fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)\n break\n except BlockingIOError:\n pid = load(ROOT / 'controller.pid')\n alive = False\n try:\n alive = isinstance(pid, int) and str(ROOT / 'controller.py').encode() in pathlib.Path('/proc/' + str(pid) + '/cmdline').read_bytes().split(bytes([0]))\n except FileNotFoundError: pass\n if time.monotonic() >= deadline:\n if alive: return\n raise RuntimeError('Workspace controller startup lock is busy')\n time.sleep(.01)\n atomic(ROOT / 'controller.pid', os.getpid())\n proc = None\n current = None\n selected = None\n health_misses = {}\n bridges = None\n revision = None\n def terminate(signum, frame):\n raise SystemExit(0)\n signal.signal(signal.SIGTERM, terminate)\n signal.signal(signal.SIGINT, terminate)\n try:\n while True:\n config = load(ROOT / 'config.json', {})\n mode = config.get('mode', 'blocked')\n if mode != 'device' or config.get('bootId') != BOOT_ID or config.get('expiresAtMs', 0) <= time.time() * 1000 or config.get('deadlineMonotonic', 0) <= time.monotonic():\n # Coordinate relinquishing the daemon lock with writers so a renewal cannot lose its controller.\n with open(ROOT / 'request.lock', 'a') as requests:\n fcntl.flock(requests, fcntl.LOCK_EX)\n if load(ROOT / 'config.json', {}) != config: continue\n stop(proc); proc = None; current = None; selected = None\n clear_identity()\n if mode == 'direct':\n restore(); status('direct', config)\n else:\n guard(); status('blocked', config)\n fcntl.flock(lock, fcntl.LOCK_UN)\n return\n helper = ROOT / 'helper'\n sock = ROOT / 'control.sock'\n revision = config.get('revision', config['leaseId'])\n if revision != current or proc is None or proc.poll() is not None:\n stop(proc); proc = None\n with open(ROOT / 'request.lock', 'a') as requests:\n fcntl.flock(requests, fcntl.LOCK_EX)\n if load(ROOT / 'config.json', {}).get('revision', load(ROOT / 'config.json', {}).get('leaseId')) != revision: continue\n guard(); transport_hosts(config['transportHosts'])\n sock.unlink(missing_ok=True)\n state = ROOT / ('state-' + lease_state_name(config['leaseId']))\n for old in ROOT.glob('state-*'):\n if old != state and old.is_file(): old.unlink()\n env = helper_environment()\n proc = subprocess.Popen([str(helper), '--tun=final-egress0', '--port=0', '--socket=' + str(sock), '--state=' + str(state)],\n stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, env=env)\n threading.Thread(target=capture_errors, args=(proc,), daemon=True).start()\n proc.stdin.write(b'final-device-start\\n'); proc.stdin.flush()\n deadline = time.monotonic() + 5\n while not sock.exists():\n if proc.poll() is not None or time.monotonic() > deadline:\n raise RuntimeError('Workspace egress daemon did not become ready')\n time.sleep(.05)\n args = ['up', '--reset', '--login-server=' + config['controlUrl'], '--hostname=workspace-' + lease_state_name(config['leaseId'])[:40],\n '--accept-dns=false', '--accept-routes=false', '--shields-up', '--netfilter-mode=off']\n if config.get('authKey'):\n atomic(ROOT / 'enrollment.key', config['authKey'].encode(), binary=True)\n args.append('--auth-key=file:' + str(ROOT / 'enrollment.key'))\n args.append('--force-reauth')\n try: cli(helper, sock, *args)\n finally:\n (ROOT / 'enrollment.key').unlink(missing_ok=True)\n with open(ROOT / 'request.lock', 'a') as requests:\n # A writer may hold request.lock while awaiting our daemon.lock.\n try: fcntl.flock(requests, fcntl.LOCK_EX | fcntl.LOCK_NB)\n except BlockingIOError: pass\n else:\n pending = load(ROOT / 'config.json', {})\n if pending.get('revision', pending.get('leaseId')) == revision:\n pending.pop('authKey', None); atomic(ROOT / 'config.json', pending)\n with open(ROOT / 'request.lock', 'a') as requests:\n fcntl.flock(requests, fcntl.LOCK_EX)\n saved = load(ROOT / 'config.json', {})\n if saved.get('mode') != 'device' or saved.get('leaseId') != config.get('leaseId') or saved.get('revision', saved.get('leaseId')) != revision:\n stop(proc); proc = None; current = None; selected = None\n continue\n resolver(saved.get('dnsResolvers', ['1.1.1.1', '9.9.9.9']))\n saved.pop('authKey', None); atomic(ROOT / 'config.json', saved)\n current = revision; selected = None\n guard(allow_tunnel=True)\n if config.get('state') == 'provisioning':\n controller_status('enrolled', config)\n time.sleep(.2)\n continue\n actual_bridges = local_bridges()\n with open(ROOT / 'request.lock', 'a') as requests:\n fcntl.flock(requests, fcntl.LOCK_EX)\n latest = load(ROOT / 'config.json', {})\n if latest.get('mode') != 'device' or latest.get('revision', latest.get('leaseId')) != revision: continue\n resolver(latest.get('dnsResolvers', ['1.1.1.1', '9.9.9.9']))\n previous_listeners = load(ROOT / 'control-listeners.json', [])\n existing_control_replies()\n actual_tunnel = command('ip', '-j', 'addr', 'show', 'dev', 'final-egress0', check=False)\n actual_addresses = [str(ipaddress.ip_address(address['local'])) for interface in json.loads(actual_tunnel.stdout or b'[]') for address in interface.get('addr_info', [])]\n if bridges != actual_bridges or previous_listeners != load(ROOT / 'control-listeners.json', []) or actual_addresses != load(ROOT / 'tunnel-addresses.json', []):\n guard(allow_tunnel=True); bridges = actual_bridges\n try:\n raw = json.loads(cli(helper, sock, 'status', '--json'))\n peers = {ip: peer for peer in (raw.get('Peer') or {}).values() for ip in (peer.get('TailscaleIPs') or [])}\n candidates = config.get('devices', [])\n candidate = select_exit(config, peers, selected, health_misses, helper, sock)\n if candidate is None:\n last = next((item for item in candidates if item.get('tailscaleIp') == selected), None)\n # A health miss must not tear down an authorized route during control outage/rekey.\n # Keeping it can only use the approved exit; the namespace guard still forbids direct fallback.\n if last is not None and selected in peers and not peers[selected].get('Expired'):\n peer = peers[selected]\n controller_status('reconnecting', config, deviceId=last['deviceId'], path='direct' if peer.get('CurAddr') else 'relay')\n else:\n if selected is not None: cli(helper, sock, 'set', '--exit-node=')\n selected = None\n controller_status('blocked', config)\n else:\n ip = str(ipaddress.IPv4Address(candidate['tailscaleIp']))\n if selected != ip:\n cli(helper, sock, 'set', '--exit-node=' + ip, '--exit-node-allow-lan-access=false')\n selected = ip\n route = command('ip', '-4', 'route', 'get', '192.0.2.254').stdout\n if b'dev final-egress0' not in route:\n controller_status('configuring', config)\n time.sleep(.1)\n continue\n peer = peers[ip]\n controller_status('device', config, deviceId=candidate['deviceId'], path='direct' if peer.get('CurAddr') else 'relay')\n time.sleep(1)\n except (RuntimeError, subprocess.TimeoutExpired, json.JSONDecodeError) as failure:\n atomic(ROOT / 'last-peer-error.json', {'error': str(failure)[:1000], 'atMs': int(time.time() * 1000)})\n controller_status('reconnecting', config)\n time.sleep(1)\n except Exception as cause:\n atomic(ROOT / 'last-error.json', {'error': str(cause), 'atMs': int(time.time() * 1000)})\n controller_status('error', load(ROOT / 'config.json', {}), error='Workspace egress stopped; inspect the controller error')\n raise\n finally:\n stop(proc)\n if load(ROOT / 'controller.pid') == os.getpid(): (ROOT / 'controller.pid').unlink(missing_ok=True)\n # Writers can await daemon.lock while holding request.lock; finish secret cleanup after releasing it.\n fcntl.flock(lock, fcntl.LOCK_UN)\n with open(ROOT / 'request.lock', 'a') as requests:\n fcntl.flock(requests, fcntl.LOCK_EX)\n pending = load(ROOT / 'config.json', {})\n if revision is not None and pending.get('revision', pending.get('leaseId')) == revision and 'authKey' in pending:\n pending.pop('authKey', None); atomic(ROOT / 'config.json', pending)\n\ndef apply(request):\n prerequisite(request['action'])\n with open(ROOT / 'request.lock', 'a') as lock:\n fcntl.flock(lock, fcntl.LOCK_EX)\n action = request['action']\n source = pathlib.Path(__file__).read_bytes() if '__file__' in globals() else sys.argv[1].encode()\n cached_source = ROOT / 'controller.py'\n if not cached_source.exists() or cached_source.read_bytes() != source: atomic(cached_source, source, binary=True)\n existing = load(ROOT / 'config.json', {})\n capabilities = [int(line.split()[1], 16) for line in pathlib.Path('/proc/self/status').read_text().splitlines() if line.startswith(('CapInh:', 'CapPrm:', 'CapEff:', 'CapBnd:', 'CapAmb:'))]\n # A prior choice with lost volatile state is not proof of an untouched namespace.\n network_pristine = (existing.get('noNetworkChanges') is True or ((not existing or existing.get('mode') == 'direct') and not (PERSISTENT / 'intent.json').exists())) and bool(capabilities) and not any(mask & (1 << 12) for mask in capabilities) and not (PERSISTENT / 'resolver.original').exists() and not (PERSISTENT / 'hosts.original').exists() and not (ROOT / 'controller.pid').exists()\n workspace_id = request.get('workspaceId')\n if action != 'status' and existing.get('workspaceId') is not None and existing['workspaceId'] != workspace_id:\n raise RuntimeError('This network namespace belongs to a different workspace')\n operation = load(ROOT / 'operation.json', {})\n operation_live = operation.get('bootId') == BOOT_ID and operation.get('deadline', 0) > time.monotonic()\n token = str(uuid.UUID(request['configurationToken'])) if request.get('configurationToken') is not None else None\n if action == 'claim':\n if (request.get('refresh') or request.get('verifyOnly')) and (not operation_live or operation.get('token') != token):\n raise WorkspaceConflictError('Workspace configuration claim was superseded')\n if operation_live and operation.get('token') != token:\n return {**load(ROOT / 'status.json', {'mode': 'blocked', 'leaseId': None, 'expiresAtMs': None, 'deviceId': None, 'path': None}), 'busy': True}\n token = str(uuid.UUID(token))\n if not request.get('verifyOnly'):\n atomic(ROOT / 'operation.json', {'token': token, 'deadline': time.monotonic() + 300, 'bootId': BOOT_ID})\n return {**load(ROOT / 'status.json', {'mode': 'blocked', 'leaseId': None, 'expiresAtMs': None, 'deviceId': None, 'path': None}), 'busy': False}\n if action == 'unlock':\n if operation.get('token') == token: (ROOT / 'operation.json').unlink(missing_ok=True)\n return load(ROOT / 'status.json', {'mode': 'blocked', 'leaseId': None, 'expiresAtMs': None, 'deviceId': None, 'path': None})\n if action not in ('status', 'artifact'):\n if token is not None and (not operation_live or operation.get('token') != token):\n raise WorkspaceConflictError('Workspace egress configuration was superseded')\n if operation_live and token != operation.get('token'):\n raise WorkspaceConflictError('Another binding is configuring workspace egress')\n expected = lease_id(request['expectedLeaseId']) if request.get('expectedLeaseId') is not None else None\n if token is None and expected is not None and existing.get('leaseId') != expected:\n if action == 'block' and existing.get('leaseId') is None and existing.get('mode') == 'direct':\n return load(ROOT / 'status.json', {'mode': 'direct', 'leaseId': None, 'expiresAtMs': None, 'deviceId': None, 'path': None})\n if action == 'block' and existing.get('leaseId') is None and existing.get('mode') == 'blocked':\n try: guard()\n except Exception as failure:\n status('error' if isinstance(failure, DenialUnavailableError) else 'blocked', existing)\n raise\n return status('blocked', existing)\n if not (action == 'block' and existing.get('leaseId') is None and (not existing or existing.get('mode') == 'blocked')):\n raise WorkspaceConflictError('Workspace egress lease changed before cleanup')\n if action not in ('status', 'artifact'):\n PERSISTENT.mkdir(mode=0o700, exist_ok=True)\n if PERSISTENT.is_symlink() or PERSISTENT.stat().st_uid != 0:\n raise RuntimeError('Persistent workspace egress state must be root-owned')\n PERSISTENT.chmod(0o700)\n identity = load(PERSISTENT / 'identity.json', {})\n if identity.get('workspaceId') is not None and identity['workspaceId'] != workspace_id:\n raise RuntimeError('Persistent egress state belongs to a different workspace')\n if action != 'disable': atomic(PERSISTENT / 'identity.json', {'workspaceId': workspace_id})\n if action == 'block': atomic(PERSISTENT / 'intent.json', {'requiresChoice': not request.get('restoreDirect', False)})\n if action == 'disable' and existing.get('noNetworkChanges') is True:\n if (PERSISTENT / 'resolver.original').exists() or (PERSISTENT / 'hosts.original').exists() or (ROOT / 'controller.pid').exists():\n raise RuntimeError('Workspace contains restoration artifacts; privileged repair is required')\n (PERSISTENT / 'identity.json').unlink(missing_ok=True)\n (PERSISTENT / 'intent.json').unlink(missing_ok=True)\n config = {'mode': 'direct', 'workspaceId': workspace_id, 'ownerUserId': None}\n atomic(ROOT / 'config.json', config)\n return status('direct', config)\n if action == 'disable' and (not existing or (existing.get('mode') == 'direct' and load(ROOT / 'status.json', {}).get('mode') == 'direct')):\n if restoration_pending(): restore()\n (PERSISTENT / 'identity.json').unlink(missing_ok=True)\n (PERSISTENT / 'intent.json').unlink(missing_ok=True)\n config = {'mode': 'direct', 'workspaceId': workspace_id, 'ownerUserId': None}\n atomic(ROOT / 'config.json', config)\n return status('direct', config)\n if action == 'artifact':\n ready = False\n try: fd = os.open(ROOT / 'helper', os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)\n except FileNotFoundError: pass\n else:\n with os.fdopen(fd, 'rb') as source:\n info = os.fstat(source.fileno())\n if stat.S_ISREG(info.st_mode) and info.st_size <= 128 * 1024 * 1024:\n ready = hashlib.sha256(source.read(128 * 1024 * 1024 + 1)).hexdigest() == request['sha256']\n return {**load(ROOT / 'status.json', {'mode': 'blocked', 'leaseId': None, 'expiresAtMs': None, 'deviceId': None, 'path': None}), 'helperReady': ready}\n if action == 'status':\n result = load(ROOT / 'status.json', {'mode': 'direct', 'leaseId': None, 'expiresAtMs': None, 'deviceId': None, 'path': None, 'architecture': platform.machine()})\n alive = False\n with open(ROOT / 'daemon.lock', 'a') as daemon_lock:\n try:\n fcntl.flock(daemon_lock, fcntl.LOCK_EX | fcntl.LOCK_NB)\n if result.get('mode') != 'error' and existing.get('mode') not in ('direct', 'error') and existing:\n result = {**result, 'mode': 'blocked' if denial_present() else 'error', 'deviceId': None, 'path': None}\n except BlockingIOError: alive = True\n return {**result, 'networkPristine': existing.get('noNetworkChanges', False), 'controllerAlive': alive, 'configuring': operation_live, 'restorePending': restoration_pending(), 'choicePending': load(PERSISTENT / 'intent.json', {}).get('requiresChoice', existing.get('mode') == 'blocked')}\n if action in ('block', 'configure'):\n try: guard()\n except Exception as failure:\n mode = 'error' if isinstance(failure, DenialUnavailableError) else 'blocked'\n failed = {'mode': mode, 'workspaceId': workspace_id, 'ownerUserId': request.get('ownerUserId'), 'noNetworkChanges': network_pristine}\n atomic(ROOT / 'config.json', failed); status(mode, failed)\n raise\n if action == 'configure':\n # Validation failure must not leave an old direct/device status after guard installation.\n pending = {'mode': 'blocked', 'workspaceId': workspace_id, 'ownerUserId': request.get('ownerUserId')}\n atomic(ROOT / 'config.json', pending); status('blocked', pending)\n if request.get('config', {}).get('workspaceId') != workspace_id: raise RuntimeError('Enrollment belongs to a different workspace')\n if command('ip', '-4', 'rule', 'show', check=False).returncode != 0:\n raise PrerequisiteError('This workspace kernel does not support Linux policy routing')\n config = request['config']\n config['dnsResolvers'] = validated_resolvers(config.get('dnsResolvers', ['1.1.1.1', '9.9.9.9']))\n control = urllib.parse.urlsplit(config['controlUrl'])\n if control.scheme != 'https' or not control.hostname or control.username is not None or control.password is not None or control.query or control.fragment:\n raise RuntimeError('Workspace control URL must use HTTPS without credentials, query or fragment')\n config['leaseId'] = lease_id(config['leaseId'])\n remaining = config['expiresAtMs'] - time.time() * 1000\n if not 0 < remaining <= 16 * 60 * 1000:\n raise RuntimeError('Workspace egress lease is expired or exceeds fifteen minutes')\n config['bootId'] = BOOT_ID\n config['deadlineMonotonic'] = time.monotonic() + min(remaining, 15 * 60 * 1000) / 1000\n staged = pathlib.Path(request['helperPath'])\n try: fd = os.open(staged, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)\n except FileNotFoundError as failure:\n raise RuntimeError('Staged networking helper is missing; transfer the approved artifact again') from failure\n with os.fdopen(fd, 'rb') as source:\n if not stat.S_ISREG(os.fstat(source.fileno()).st_mode):\n raise RuntimeError('Workspace networking helper must be a regular file')\n content = source.read(128 * 1024 * 1024 + 1)\n if len(content) > 128 * 1024 * 1024 or hashlib.sha256(content).hexdigest() != config['helper']['sha256']:\n raise RuntimeError('Workspace networking helper failed integrity verification')\n machine = {'x86_64': 62, 'aarch64': 183}.get(platform.machine())\n if content[:6] != b'\\x7fELF\\x02\\x01' or len(content) < 20 or struct.unpack('<H', content[18:20])[0] != machine:\n raise RuntimeError('The pinned networking helper does not match this Linux workspace architecture')\n atomic(ROOT / 'helper', content, binary=True, mode=0o700)\n config = dict(config, mode='device')\n elif action == 'renew':\n request['lease']['leaseId'] = lease_id(request['lease']['leaseId'])\n if request.get('lease', {}).get('workspaceId') != workspace_id: raise RuntimeError('Renewal belongs to a different workspace')\n config = load(ROOT / 'config.json')\n if config is None or config.get('leaseId') != request['lease']['leaseId']:\n raise WorkspaceConflictError('Workspace egress lease changed')\n if config.get('bootId') != BOOT_ID or config.get('deadlineMonotonic', 0) <= time.monotonic() or config.get('expiresAtMs', 0) <= time.time() * 1000:\n raise EnrollmentLostError('Workspace enrollment expired locally; authorized reenrollment is required')\n lease = request['lease']\n lease['leaseId'] = lease_id(lease['leaseId'])\n remaining = lease['expiresAtMs'] - time.time() * 1000\n if not 0 < remaining <= 16 * 60 * 1000:\n raise RuntimeError('Workspace egress renewal is invalid')\n config.update(bootId=BOOT_ID, expiresAtMs=lease['expiresAtMs'], devices=lease['devices'], state=lease['state'], deadlineMonotonic=time.monotonic() + min(remaining, 15 * 60 * 1000) / 1000)\n elif action in ('block', 'disable'):\n config = {'mode': 'direct' if action == 'disable' else 'blocked', 'workspaceId': workspace_id, 'ownerUserId': None if action == 'disable' else request.get('ownerUserId')}\n else:\n raise RuntimeError('Unknown workspace egress action')\n atomic(ROOT / 'config.json', config)\n if action in ('block', 'disable'): stop_controller()\n if action == 'renew':\n with open(ROOT / 'daemon.lock', 'a') as daemon_lock:\n try: fcntl.flock(daemon_lock, fcntl.LOCK_EX | fcntl.LOCK_NB)\n except BlockingIOError:\n prior = load(ROOT / 'status.json', {})\n return {**prior, 'expiresAtMs': config['expiresAtMs']}\n # The controller uses a root-owned copy after this caller's temporary files are removed.\n source = pathlib.Path(__file__).read_bytes() if '__file__' in globals() else sys.argv[1].encode()\n atomic(ROOT / 'controller.py', source, binary=True)\n subprocess.Popen([sys.executable, '-I', str(ROOT / 'controller.py'), 'run'], stdin=subprocess.DEVNULL,\n stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=True)\n if action == 'block': return status('blocked', config)\n return status('configuring', config)\n\nif __name__ == '__main__':\n try:\n if len(sys.argv) > 1 and sys.argv[1] == 'run': run()\n else: print(json.dumps(apply(json.load(sys.stdin))))\n except Exception as cause:\n try:\n if ROOT.exists() and not ROOT.is_symlink() and ROOT.stat().st_uid == 0:\n atomic(ROOT / 'last-error.json', {'error': str(cause)[:1000], 'atMs': int(time.time() * 1000)})\n except OSError: pass\n code = 'egress_enrollment_lost' if isinstance(cause, EnrollmentLostError) else 'prerequisite' if isinstance(cause, (FileNotFoundError, PrerequisiteError)) else 'conflict' if isinstance(cause, WorkspaceConflictError) else 'configuration'\n print(json.dumps({'errorCode': code}))\n sys.exit(1)\n`;\n\n// Verify the owned source before executing it; a cache miss requests the full bootstrap once.\nexport const cachedWorkspaceEgressBootstrap = (sha256: string): string => {\n if (!/^[a-f0-9]{64}$/.test(sha256)) throw new Error('Invalid workspace controller SHA256');\n return String.raw`import hashlib, os, pathlib, stat\npath = pathlib.Path('/run/final-workspace-egress/controller.py')\ntry:\n fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)\n with os.fdopen(fd, 'rb') as file:\n info = os.fstat(file.fileno())\n source = file.read(128 * 1024 + 1)\n valid = stat.S_ISREG(info.st_mode) and info.st_uid == 0 and not info.st_mode & 0o022 and len(source) <= 128 * 1024 and hashlib.sha256(source).hexdigest() == '${sha256}'\nexcept OSError: valid = False\nif valid: exec(compile(source, str(path), 'exec'), {'__name__': '__main__', '__file__': str(path)})\nelse: print('{\"needsBootstrap\":true}')\n`;\n};\n\n// Keep provider command arguments small; credentials and trusted source travel on stdin.\nexport const workspaceEgressLauncher = String.raw`import io,json,sys\nrequest=json.load(sys.stdin)\nsource=request['source']\nsys.argv=['-c',source]\nsys.stdin=io.StringIO(request['input'])\nexec(compile(source,'<final-workspace-egress>','exec'),{'__name__':'__main__'})\n`;\n"],
|
|
5
|
-
"mappings": "AACO,MAAM,2BAA2B,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["// The same controller runs in ordinary Linux provider namespaces; no VM platform API is used.\nexport const workspaceEgressBootstrap = String.raw`import collections, errno, fcntl, hashlib, ipaddress, json, os, pathlib, platform, re, shutil, signal, shlex, socket, stat, struct, subprocess, sys, tempfile, threading, time, urllib.parse, uuid\n\nROOT = pathlib.Path('/run/final-workspace-egress')\nPERSISTENT = pathlib.Path('/var/lib/final-workspace-egress')\nRESOLVER = pathlib.Path('/etc/resolv.conf')\nHOSTS = pathlib.Path('/etc/hosts')\nCHAIN = 'FINAL-EGRESS'\nREPLY = 'FINAL-EGRESS-REPLY'\nFORWARD = 'FINAL-EGRESS-FWD'\nNAT = 'FINAL-EGRESS-NAT'\nMARK = '0x80000/0xff0000'\nos.environ['PATH'] = '/usr/sbin:/usr/bin:/sbin:/bin'\nos.environ.pop('SSL_CERT_FILE', None)\nos.environ.pop('SSL_CERT_DIR', None)\n# Prime autoload before choosing families; later kernel enablement requires reinitialization.\ntry: socket.socket(socket.AF_INET6, socket.SOCK_DGRAM).close()\nexcept OSError as failure:\n if failure.errno not in (errno.EAFNOSUPPORT, errno.EPROTONOSUPPORT, errno.EPERM, errno.EACCES): raise\nFAMILIES = ('iptables', 'ip6tables') if pathlib.Path('/proc/net/if_inet6').exists() else ('iptables',)\n\nclass WorkspaceConflictError(RuntimeError):\n pass\n\nclass PrerequisiteError(RuntimeError):\n pass\n\nclass DenialUnavailableError(RuntimeError):\n pass\n\nclass EnrollmentLostError(RuntimeError):\n pass\n\n\ndef command(*args, check=True, timeout=25):\n if args[0] in ('iptables', 'ip6tables') and '--version' not in args: args = (args[0], '-w', '5', *args[1:])\n result = subprocess.run(args, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout)\n if check and result.returncode != 0:\n raise RuntimeError('Workspace networking command failed: ' + ' '.join(args[:4]))\n return result\n\ndef atomic(path, value, binary=False, mode=0o600):\n staged = None\n try:\n with tempfile.NamedTemporaryFile(dir=path.parent, delete=False) as out:\n staged = pathlib.Path(out.name)\n out.write(value if binary else json.dumps(value).encode())\n out.flush(); os.fsync(out.fileno())\n os.chmod(staged, mode)\n os.replace(staged, path)\n directory = os.open(path.parent, os.O_RDONLY | os.O_DIRECTORY)\n try: os.fsync(directory)\n finally: os.close(directory)\n finally:\n if staged is not None: staged.unlink(missing_ok=True)\n\ndef managed_text(path, content):\n data = content.encode()\n try: atomic(path, data, binary=True, mode=0o644)\n except OSError as failure:\n if failure.errno != errno.EBUSY: raise\n # Docker bind-mounted files cannot be replaced; never follow a raced-in symlink.\n pending = PERSISTENT / 'resolver-write-pending.json' if path == RESOLVER else None\n if pending is not None: atomic(pending, True)\n fd = os.open(path, os.O_WRONLY | os.O_NOFOLLOW | os.O_NONBLOCK)\n with os.fdopen(fd, 'wb') as out:\n if not stat.S_ISREG(os.fstat(out.fileno()).st_mode): raise RuntimeError('Managed network file must be regular')\n os.ftruncate(out.fileno(), 0)\n out.write(data); out.flush(); os.fsync(out.fileno())\n if pending is not None: pending.unlink(missing_ok=True)\n\ndef load(path, default=None):\n try:\n return json.loads(path.read_text())\n except FileNotFoundError:\n return default\n\ndef prerequisite(action):\n if sys.version_info < (3, 8):\n raise PrerequisiteError('Device egress requires Python 3.8 or newer')\n if sys.platform != 'linux' or os.geteuid() != 0:\n raise PrerequisiteError('Device egress requires an isolated Linux workspace with privileged networking access')\n ROOT.mkdir(mode=0o700, exist_ok=True)\n if ROOT.is_symlink() or ROOT.stat().st_uid != 0:\n raise RuntimeError('Workspace egress state must be a root-owned directory')\n ROOT.chmod(0o700)\n direct = not load(ROOT / 'config.json') or (load(ROOT / 'config.json', {}).get('mode') == 'direct' and load(ROOT / 'status.json', {}).get('mode') == 'direct')\n if action in ('status', 'artifact', 'claim', 'unlock') or (action == 'disable' and (direct or load(ROOT / 'config.json', {}).get('noNetworkChanges') is True)): return\n if action in ('configure', 'renew') and not pathlib.Path('/dev/net/tun').exists():\n raise PrerequisiteError('This sandbox provider does not expose /dev/net/tun')\n command('ip', '-V')\n for family in FAMILIES:\n command(family, '--version'); command(family + '-restore', '--version')\n\nBOOT_ID = pathlib.Path('/proc/sys/kernel/random/boot_id').read_text().strip()\n\ndef existing_control_replies():\n saved = load(ROOT / 'control-replies.json')\n sockets = []\n for table in ('tcp', 'tcp6'):\n def address(value):\n host, port = value.split(':')\n raw = bytes.fromhex(host)\n raw = b''.join(raw[i:i+4][::-1] for i in range(0, len(raw), 4))\n ip = ipaddress.ip_address(raw)\n if isinstance(ip, ipaddress.IPv6Address) and ip.ipv4_mapped is not None: ip = ip.ipv4_mapped\n return str(ip), int(port, 16)\n source = pathlib.Path('/proc/net/' + table)\n if not source.exists(): continue\n for line in source.read_text().splitlines()[1:]:\n columns = line.split()\n if columns[3] in ('01', '0A'): sockets.append((address(columns[1]), address(columns[2]), columns[3], int(columns[7])))\n addresses = json.loads(command('ip', '-j', 'addr', 'show').stdout)\n local_addresses = {ipaddress.ip_address(address['local']) for interface in addresses for address in interface.get('addr_info', [])}\n bridge_networks = [ipaddress.ip_network(network) for _, network in local_bridges()]\n listeners = [local for local, remote, state, uid in sockets if state == '0A' and not ipaddress.ip_address(local[0]).is_loopback]\n replies = []\n for local, remote, state, uid in sockets:\n # Only privileged provider sockets may use the pre-conntrack compatibility exception.\n remote_ip = ipaddress.ip_address(remote[0])\n if uid != 0 or state != '01' or remote_ip.is_loopback or remote_ip in local_addresses: continue\n if any(remote_ip.version == network.version and remote_ip in network for network in bridge_networks): continue\n if any(port == local[1] and (ipaddress.ip_address(host).is_unspecified or host == local[0]) for host, port in listeners):\n replies.append({'source': local[0], 'sourcePort': local[1], 'destination': remote[0], 'destinationPort': remote[1], 'uid': 0})\n if saved is not None and any(reply.get('uid') != 0 for reply in saved): saved = None\n capture_overflow = saved is None and len(replies) > 128\n if saved is not None: replies = saved\n server_ports = [{'source': host, 'sourcePort': port} for host, port in listeners]\n for prior in load(ROOT / 'control-listeners.json', []):\n if any(local[1] == prior['sourcePort'] and state == '01' for local, remote, state, uid in sockets): server_ports.append(prior)\n # A dual-stack listener appears in tcp6 even when the accepted transport uses IPv4.\n server_ports += [{'source': reply['source'], 'sourcePort': reply['sourcePort']} for reply in replies]\n server_ports = [dict(source=host, sourcePort=port) for host, port in sorted({(item['source'], item['sourcePort']) for item in server_ports})]\n prior = load(ROOT / 'control-listeners.json', [])\n privileged = {local for local, remote, state, uid in sockets if state == '0A' and uid == 0}\n server_ports.sort(key=lambda item: (item not in prior, (item['source'], item['sourcePort']) not in privileged))\n atomic(ROOT / 'control-listeners.json', server_ports[:256])\n if len(server_ports) > 256:\n atomic(ROOT / 'listener-limit.json', {'limit': 256, 'observed': len(server_ports)})\n else: (ROOT / 'listener-limit.json').unlink(missing_ok=True)\n if capture_overflow: raise RuntimeError('Too many existing inbound control connections')\n atomic(ROOT / 'control-replies.json', replies)\n return replies\n\ndef local_bridges():\n result = []\n # Minimal VM kernels can reject a type-filtered dump; ordinary link dumps remain portable.\n links = json.loads(command('ip', '-j', '-d', 'link', 'show').stdout)\n by_name = {link['ifname']: link for link in links}\n uplinks = set()\n for route in json.loads(command('ip', '-j', '-4', 'route', 'show', 'table', 'all').stdout):\n if route.get('dst') == 'default' or route.get('gateway') is not None or route.get('nexthops'):\n uplinks.add(route.get('dev'))\n uplinks.update(hop.get('dev') for hop in route.get('nexthops', []))\n for link in links:\n if link.get('linkinfo', {}).get('info_kind') != 'bridge': continue\n try: members = list((pathlib.Path('/sys/class/net') / link['ifname'] / 'brif').iterdir())\n except FileNotFoundError: continue\n if link['ifname'] in uplinks or any(member.name in uplinks or by_name.get(member.name, {}).get('linkinfo', {}).get('info_kind') != 'veth' for member in members): continue\n name = link['ifname']\n if not re.fullmatch(r'[A-Za-z0-9_.-]{1,15}', name): raise RuntimeError('Unsupported local bridge name')\n for interface in json.loads(command('ip', '-j', '-4', 'addr', 'show', 'dev', name).stdout):\n for address in interface.get('addr_info', []):\n if address.get('family') == 'inet': result.append((name, str(ipaddress.ip_network(address['local'] + '/' + str(address['prefixlen']), strict=False))))\n return sorted(result)\n\ndef install_guard(allow_tunnel=False, closed=False):\n if closed: allow_tunnel = False\n replies = [reply for reply in load(ROOT / 'control-replies.json', []) if reply.get('uid') == 0] if closed else existing_control_replies()\n bridges = [] if closed else local_bridges()\n try: listeners = load(ROOT / 'control-listeners.json', [])\n except Exception:\n if not closed: raise\n listeners = []\n if closed: tunnel_addresses = load(ROOT / 'tunnel-addresses.json', [])\n else:\n tunnel = command('ip', '-j', 'addr', 'show', 'dev', 'final-egress0', check=False)\n tunnel_addresses = [str(ipaddress.ip_address(address['local'])) for interface in json.loads(tunnel.stdout or b'[]') for address in interface.get('addr_info', [])]\n atomic(ROOT / 'tunnel-addresses.json', tunnel_addresses)\n for family in FAMILIES:\n rules = ['*filter', ':' + CHAIN + ' - [0:0]', '-F ' + CHAIN]\n # Block namespace-local DNS stubs that would otherwise resolve on the provider's network.\n for proto in ('tcp', 'udp'):\n rules.append('-A ' + CHAIN + ' -o lo -p ' + proto + ' --dport 53 -j REJECT')\n if family == 'iptables':\n rules.append('-A ' + CHAIN + ' -d 127.0.0.11 -j REJECT')\n rules.append('-A ' + CHAIN + ' -d 100.100.100.100 -j REJECT')\n rules += ['-A ' + CHAIN + ' -o lo -j ACCEPT', '-A ' + CHAIN + ' -m mark --mark ' + MARK + ' -m owner --uid-owner 0 -j ACCEPT', '-A ' + CHAIN + ' -m mark --mark ' + MARK + ' -m conntrack --ctdir REPLY -j ACCEPT']\n if family == 'ip6tables':\n for kind in (133, 134, 135, 136):\n rules += ['-A ' + CHAIN + ' -p ipv6-icmp --icmpv6-type ' + str(kind) + ' -m owner --uid-owner 1-4294967294 -j REJECT',\n '-A ' + CHAIN + ' -p ipv6-icmp --icmpv6-type ' + str(kind) + ' -j ACCEPT']\n if family == 'iptables':\n for name, network in bridges: rules.append('-A ' + CHAIN + ' -o ' + name + ' -d ' + network + ' -j ACCEPT')\n if family == 'iptables' and allow_tunnel:\n rules.append('-A ' + CHAIN + ' -o final-egress0 -j ACCEPT')\n if closed:\n for reply in replies:\n if (':' in reply['source']) != (family == 'ip6tables'): continue\n rules.append('-A ' + CHAIN + ' -p tcp -s ' + reply['source'] + ' --sport ' + str(reply['sourcePort']) + ' -d ' + reply['destination'] + ' --dport ' + str(reply['destinationPort']) + ' --tcp-flags SYN,RST,ACK ACK -j ACCEPT')\n rules += ['-A ' + CHAIN + ' -j REJECT', 'COMMIT', '*mangle', ':' + REPLY + ' - [0:0]', '-F ' + REPLY,\n # Docker rewrites its DNS stub's port in nat/OUTPUT; block before that translation.\n '-A ' + REPLY + ' -o lo -p tcp --dport 53 -j DROP',\n '-A ' + REPLY + ' -o lo -p udp --dport 53 -j DROP',\n ]\n if family == 'iptables': rules.append('-A ' + REPLY + ' -d 127.0.0.11 -j DROP')\n # mangle/OUTPUT sees the initial exit route even for physical provider replies.\n # Exclude only the actual tunnel source addresses before marking server replies.\n for address in tunnel_addresses:\n if (':' in address) == (family == 'ip6tables'):\n rules.append('-A ' + REPLY + ' -s ' + address + ' -j RETURN')\n # Minimal provider kernels omit connmark. Reserve the existing server ports for TCP replies;\n # an untracked outgoing client's ephemeral port cannot obtain this exception.\n for listener in listeners:\n host = listener['source']\n address = ipaddress.ip_address(host)\n if (':' in host) != (family == 'ip6tables') and not (family == 'iptables' and address.version == 6 and address.is_unspecified): continue\n source = '' if ipaddress.ip_address(host).is_unspecified else ' -s ' + host\n rules.append('-A ' + REPLY + ' -p tcp' + source + ' --sport ' + str(listener['sourcePort']) +\n ' -m conntrack --ctdir REPLY --ctorigdstport ' + str(listener['sourcePort']) + ' -j MARK --set-xmark ' + MARK)\n # Conntrack can load after a provider's long-lived inbound RPC already opened (E2B envd).\n # Preserve only ACKs on those accepted server sockets, never a new outbound SYN.\n for reply in replies:\n if (':' in reply['source']) != (family == 'ip6tables'): continue\n rules.append('-A ' + REPLY + ' -p tcp -s ' + reply['source'] + ' --sport ' + str(reply['sourcePort']) +\n ' -d ' + reply['destination'] + ' --dport ' + str(reply['destinationPort']) +\n ' --tcp-flags SYN,RST,ACK ACK -j MARK --set-xmark ' + MARK)\n rules.append('COMMIT')\n # Docker can prepend filter/FORWARD accepts; mangle runs before that table.\n rules += ['*mangle', ':' + FORWARD + ' - [0:0]', '-F ' + FORWARD]\n if family == 'iptables': rules.append('-A ' + FORWARD + ' -d 100.100.100.100 -j DROP')\n if family == 'iptables':\n for name, network in bridges:\n for ingress, _ in bridges: rules.append('-A ' + FORWARD + ' -i ' + ingress + ' -o ' + name + ' -d ' + network + ' -j RETURN')\n if family == 'iptables' and allow_tunnel:\n for name, network in bridges:\n rules += ['-A ' + FORWARD + ' -i ' + name + ' -s ' + network + ' -o final-egress0 -j RETURN',\n '-A ' + FORWARD + ' -i final-egress0 -o ' + name + ' -d ' + network + ' -m conntrack --ctstate ESTABLISHED,RELATED -j RETURN']\n rules += ['-A ' + FORWARD + ' -j DROP', 'COMMIT']\n rules += ['*filter', ':' + FORWARD + ' - [0:0]', '-F ' + FORWARD]\n if family == 'iptables': rules.append('-A ' + FORWARD + ' -d 100.100.100.100 -j DROP')\n if family == 'iptables':\n for name, network in bridges:\n for ingress, _ in bridges: rules.append('-A ' + FORWARD + ' -i ' + ingress + ' -o ' + name + ' -d ' + network + ' -j RETURN')\n if family == 'iptables' and allow_tunnel:\n for name, network in bridges:\n rules += ['-A ' + FORWARD + ' -i ' + name + ' -s ' + network + ' -o final-egress0 -j ACCEPT',\n '-A ' + FORWARD + ' -i final-egress0 -o ' + name + ' -d ' + network + ' -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT']\n rules += ['-A ' + FORWARD + ' -j REJECT', 'COMMIT']\n if family == 'iptables':\n rules += ['*nat', ':' + NAT + ' - [0:0]', '-F ' + NAT]\n for name, network in bridges:\n rules.append('-A ' + NAT + ' -s ' + network + ' -o final-egress0 -j MASQUERADE')\n rules.append('COMMIT')\n installed = subprocess.run([family + '-restore', '-w', '5', '--noflush'], timeout=25, input=('\\n'.join(rules) + '\\n').encode(), stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)\n if installed.returncode: raise RuntimeError(family + ' firewall installation failed: ' + installed.stderr.decode(errors='replace')[:800])\n hooks = [('mangle', 'OUTPUT', REPLY), ('mangle', 'FORWARD', FORWARD), ('filter', 'OUTPUT', CHAIN), ('filter', 'FORWARD', FORWARD)]\n if family == 'iptables': hooks.append(('nat', 'POSTROUTING', NAT))\n for table, hook, chain in hooks:\n if command(family, '-t', table, '-C', hook, '-j', chain, check=False).returncode != 0:\n command(family, '-t', table, '-I', hook, '1', '-j', chain)\n # Reverse-NAT replies from TUN must return to a nested bridge rather than the exit default route.\n if allow_tunnel:\n while command('ip', '-4', 'rule', 'del', 'pref', '5210', 'iif', 'final-egress0', 'lookup', 'main', 'protocol', '242', check=False).returncode == 0: pass\n existing = command('ip', '-4', 'rule', 'show').stdout.decode()\n for name, network in bridges:\n if not any('to ' + value + ' iif final-egress0 lookup main' in existing for value in (network, network[:-3] if network.endswith('/32') else network)):\n command('ip', '-4', 'rule', 'add', 'pref', '5210', 'iif', 'final-egress0', 'to', network, 'lookup', 'main', 'protocol', '242')\n existing_rules = command('ip', '-4', 'rule', 'show').stdout.decode() if bridges else ''\n for name, network in bridges:\n if not any('to ' + value + ' lookup main' in existing_rules for value in (network, network[:-3] if network.endswith('/32') else network)):\n command('ip', '-4', 'rule', 'add', 'pref', '5210', 'to', network, 'lookup', 'main', 'protocol', '242')\n\ndef chain_hooked(family, table, hook, chain):\n result = command(family, '-t', table, '-S', check=False)\n if result.returncode != 0:\n if table != 'filter' and result.returncode == 3 and b'Table does not exist' in result.stderr: return False\n raise RuntimeError('Cannot inspect namespace firewall hooks')\n return ('-A ' + hook + ' -j ' + chain) in result.stdout.decode().splitlines()\n\ndef denial_present():\n for family in FAMILIES:\n for hook, chain in [('OUTPUT', CHAIN), ('FORWARD', FORWARD)]:\n if not chain_hooked(family, 'filter', hook, chain): return False\n rules = command(family, '-t', 'filter', '-S', chain, check=False)\n if rules.returncode or not any(shlex.split(line)[:4] in (['-A', chain, '-j', 'DROP'], ['-A', chain, '-j', 'REJECT']) for line in rules.stdout.decode().splitlines()): return False\n return True\n\ndef restoration_pending():\n if load(ROOT / 'config.json', {}).get('mode') == 'error' or load(ROOT / 'status.json', {}).get('mode') == 'error': return True\n if (PERSISTENT / 'hosts.original').exists() or (PERSISTENT / 'resolver.original').exists() or (not HOSTS.is_symlink() and HOSTS.exists() and '# final-workspace-egress' in HOSTS.read_text()): return True\n if RESOLVER.exists() and RESOLVER.read_bytes().startswith(b'# Final workspace egress\\n'): return True\n if not all(shutil.which(family) for family in FAMILIES):\n return (PERSISTENT / 'identity.json').exists() or load(ROOT / 'config.json', {}).get('mode', 'direct') != 'direct'\n try:\n return any(chain_hooked(family, table, hook, chain)\n for family in FAMILIES\n for table, hook, chain in [('filter', 'OUTPUT', CHAIN), ('filter', 'FORWARD', FORWARD), ('mangle', 'OUTPUT', REPLY), ('mangle', 'FORWARD', FORWARD)] + ([('nat', 'POSTROUTING', NAT)] if family == 'iptables' else []))\n except RuntimeError:\n # Never-managed images need no repair when their provider denies firewall inspection.\n if not (PERSISTENT / 'identity.json').exists() and load(ROOT / 'config.json', {}).get('mode', 'direct') == 'direct': return False\n raise\n\ndef restore():\n transport_hosts({})\n original = PERSISTENT / 'resolver.original'\n if not original.exists() and (load(PERSISTENT / 'resolver-write-pending.json', False) or (RESOLVER.exists() and RESOLVER.read_bytes().startswith(b'# Final workspace egress\\n'))):\n raise RuntimeError('Original workspace resolver backup is missing; repair the provider resolver before Disable')\n if original.exists():\n current = RESOLVER\n if load(PERSISTENT / 'resolver-write-pending.json', False) or not current.exists() or current.read_text().startswith('# Final workspace egress\\n'):\n link = load(PERSISTENT / 'resolver-link.json')\n if link is None:\n if load(PERSISTENT / 'resolver-absent.json', False): current.unlink(missing_ok=True)\n else:\n if current.is_symlink(): current.unlink()\n managed_text(current, original.read_text())\n else:\n staged = current.parent / ('.final-egress-resolver-' + uuid.uuid4().hex)\n try:\n os.symlink(link['target'], staged); os.replace(staged, current)\n finally: staged.unlink(missing_ok=True)\n (PERSISTENT / 'resolver-write-pending.json').unlink(missing_ok=True)\n original.unlink()\n (PERSISTENT / 'resolver-link.json').unlink(missing_ok=True)\n (PERSISTENT / 'resolver-absent.json').unlink(missing_ok=True)\n for family in FAMILIES:\n hooks = [('filter', 'OUTPUT', CHAIN), ('mangle', 'OUTPUT', REPLY), ('mangle', 'FORWARD', FORWARD), ('filter', 'FORWARD', FORWARD)]\n if family == 'iptables': hooks.append(('nat', 'POSTROUTING', NAT))\n for table, hook, chain in hooks:\n while chain_hooked(family, table, hook, chain):\n command(family, '-t', table, '-D', hook, '-j', chain)\n command(family, '-t', table, '-F', chain, check=False)\n command(family, '-t', table, '-X', chain, check=False)\n while command('ip', '-4', 'rule', 'del', 'pref', '5210', 'protocol', '242', 'lookup', 'main', check=False).returncode == 0: pass\n for saved in ('control-replies.json', 'control-listeners.json', 'listener-limit.json', 'tunnel-addresses.json'):\n (ROOT / saved).unlink(missing_ok=True)\n (PERSISTENT / 'identity.json').unlink(missing_ok=True)\n (PERSISTENT / 'intent.json').unlink(missing_ok=True)\n\ndef validated_resolvers(addresses):\n if not isinstance(addresses, list) or not addresses or len(addresses) > 3:\n raise RuntimeError('One to three IPv4 DNS resolvers are required')\n addresses = [str(ipaddress.IPv4Address(address)) for address in addresses]\n if len(set(addresses)) != len(addresses) or any(int(address.split('.')[0]) in (0, 127) or int(address.split('.')[0]) >= 224 or address == '100.100.100.100' for address in addresses):\n raise RuntimeError('Device DNS resolvers must be unique reachable unicast addresses')\n return addresses\n\ndef resolver(addresses):\n addresses = validated_resolvers(addresses)\n source = RESOLVER\n if not (PERSISTENT / 'resolver.original').exists():\n if source.exists() and source.read_bytes().startswith(b'# Final workspace egress\\n'):\n raise RuntimeError('Original workspace resolver backup is missing; repair the provider resolver')\n absent = not source.exists() and not source.is_symlink()\n try: original = source.read_bytes()\n except FileNotFoundError: original = b''\n atomic(PERSISTENT / 'resolver-absent.json', absent)\n if source.is_symlink(): atomic(PERSISTENT / 'resolver-link.json', {'target': os.readlink(source)})\n else: (PERSISTENT / 'resolver-link.json').unlink(missing_ok=True)\n atomic(PERSISTENT / 'resolver.original', original, binary=True)\n content = '# Final workspace egress\\n' + ''.join('nameserver ' + address + '\\n' for address in addresses) + 'options timeout:2 attempts:2\\n'\n if not source.is_symlink() and source.exists() and source.read_bytes() == content.encode(): return\n managed_text(source, content)\n\ndef transport_hosts(hosts):\n original = PERSISTENT / 'hosts.original'\n absent = PERSISTENT / 'hosts-absent.json'\n if HOSTS.is_symlink():\n if hosts: raise PrerequisiteError('Workspace egress requires a regular /etc/hosts file')\n if original.exists():\n if load(absent, False): HOSTS.unlink()\n else: atomic(HOSTS, original.read_bytes(), binary=True, mode=0o644)\n original.unlink(); absent.unlink(missing_ok=True)\n return\n if hosts and not original.exists():\n atomic(absent, not HOSTS.exists())\n atomic(original, HOSTS.read_bytes() if HOSTS.exists() else b'', binary=True)\n if not HOSTS.exists() and not hosts:\n if original.exists() and not load(absent, False): atomic(HOSTS, original.read_bytes(), binary=True, mode=0o644)\n original.unlink(missing_ok=True); absent.unlink(missing_ok=True)\n return\n lines = HOSTS.read_text().splitlines() if HOSTS.exists() else []\n lines = [line for line in lines if not line.endswith('# final-workspace-egress')]\n for host, address in hosts.items():\n if not host or any(c not in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-' for c in host):\n raise RuntimeError('Invalid egress transport hostname')\n lines.append(str(ipaddress.IPv4Address(address)) + ' ' + host + ' # final-workspace-egress')\n content = '\\n'.join(lines) + '\\n'\n if not hosts and load(absent, False) and not lines: HOSTS.unlink(missing_ok=True)\n elif not HOSTS.exists() or HOSTS.read_text() != content: managed_text(HOSTS, content)\n if not hosts:\n original.unlink(missing_ok=True); absent.unlink(missing_ok=True)\n\ndef status(mode, config, **extra):\n try: policy_routing = command('ip', '-4', 'rule', 'show', check=False).returncode == 0\n except FileNotFoundError: policy_routing = False\n result = {'mode': mode, 'leaseId': config.get('leaseId'), 'ownerUserId': config.get('ownerUserId'),\n 'workspaceId': config.get('workspaceId'), 'architecture': platform.machine(), 'policyRouting': policy_routing, 'expiresAtMs': config.get('expiresAtMs'), 'deviceId': None, 'path': None, **extra}\n atomic(ROOT / 'status.json', result)\n return result\n\ndef controller_status(mode, config, **extra):\n # A writer may await daemon shutdown while holding this lock; skip stale/busy publication.\n with open(ROOT / 'request.lock', 'a') as requests:\n try: fcntl.flock(requests, fcntl.LOCK_EX | fcntl.LOCK_NB)\n except BlockingIOError: return\n saved = load(ROOT / 'config.json', {})\n fields = ('mode', 'revision', 'leaseId', 'workspaceId', 'ownerUserId', 'expiresAtMs', 'state')\n if any(saved.get(field) != config.get(field) for field in fields): return\n return status(mode, config, **extra)\n\ndef lease_id(value):\n if not isinstance(value, str) or not value: raise RuntimeError('Missing workspace lease identifier')\n return value\n\ndef lease_state_name(value):\n value = lease_id(value)\n try: return str(uuid.UUID(value))\n except ValueError: return 'opaque-' + hashlib.sha256(value.encode()).hexdigest()\n\ndef helper_environment():\n env = {'PATH': '/usr/sbin:/usr/bin:/sbin:/bin'}\n env.update(FINAL_TAILSCALE_MANAGED='1', FINAL_DEVICE_PARENT_PID=str(os.getpid()), TS_NO_LOGS_NO_SUPPORT='true', TS_DEBUG_ENV_FILE='/dev/null', TS_LOGS_DIR=str(ROOT / 'logs'))\n return env\n\ndef cli(helper, sock, *args):\n # CLI operations are managed children as well: closing their pipe stops them on controller death.\n env = helper_environment()\n errors = os.open(ROOT / 'last-control-error.log', os.O_WRONLY | os.O_CREAT | os.O_TRUNC | os.O_NOFOLLOW, 0o600)\n try:\n proc = subprocess.Popen([str(helper), 'final-cli', '--socket=' + str(sock), *args], stdin=subprocess.PIPE,\n stdout=subprocess.PIPE, stderr=errors, env=env)\n finally: os.close(errors)\n try:\n proc.stdin.write(b'final-device-start\\n'); proc.stdin.flush()\n deadline = time.monotonic() + 20\n output = bytearray()\n os.set_blocking(proc.stdout.fileno(), False)\n while proc.poll() is None:\n chunk = proc.stdout.read(65536)\n if chunk: output.extend(chunk)\n if len(output) > 1024 * 1024 or time.monotonic() > deadline:\n raise RuntimeError('Workspace egress control operation exceeded its limit: ' + args[0])\n time.sleep(.01)\n output.extend(proc.stdout.read() or b'')\n if proc.returncode != 0:\n detail = ': ' + bytes(output).decode(errors='replace')[:1000] if args[0] == 'ping' else ''\n raise RuntimeError('Workspace egress control operation failed (' + args[0] + ')' + detail)\n return bytes(output)\n finally:\n try: proc.stdin.close()\n except BrokenPipeError: pass\n if proc.poll() is None: proc.kill()\n proc.wait()\n\ndef stop(proc):\n if proc is not None:\n try: proc.stdin.close()\n except BrokenPipeError: pass\n try: proc.wait(timeout=2)\n except subprocess.TimeoutExpired: proc.kill(); proc.wait()\n\ndef minimal_guard():\n failures = []\n # Cached accepted sockets permit recovery even without conntrack or mangle.\n try: replies = [reply for reply in load(ROOT / 'control-replies.json', []) if reply.get('uid') == 0]\n except Exception: replies = []\n for family in FAMILIES:\n try:\n for hook, chain in [('OUTPUT', CHAIN), ('FORWARD', FORWARD)]:\n existing = command(family, '-t', 'filter', '-S', chain, check=False)\n hooked = command(family, '-t', 'filter', '-C', hook, '-j', chain, check=False)\n # Retain a successfully installed closed family and its control exceptions.\n if existing.returncode == 0 and hooked.returncode == 0 and b'-o final-egress0' not in existing.stdout and any(shlex.split(line)[:4] in (['-A', chain, '-j', 'DROP'], ['-A', chain, '-j', 'REJECT']) for line in existing.stdout.decode().splitlines()): continue\n rules = ['*filter', ':' + chain + ' - [0:0]', '-F ' + chain]\n if hook == 'OUTPUT':\n for proto in ('tcp', 'udp'):\n rules.append('-A ' + chain + ' -o lo -p ' + proto + ' --dport 53 -j DROP')\n if family == 'iptables':\n rules += ['-A ' + chain + ' -d 127.0.0.11 -j DROP', '-A ' + chain + ' -d 100.100.100.100 -j DROP']\n rules.append('-A ' + chain + ' -o lo -j ACCEPT')\n if family == 'ip6tables':\n for kind in (133, 134, 135, 136):\n rules += ['-A ' + chain + ' -p ipv6-icmp --icmpv6-type ' + str(kind) + ' -m owner --uid-owner 1-4294967294 -j REJECT',\n '-A ' + chain + ' -p ipv6-icmp --icmpv6-type ' + str(kind) + ' -j ACCEPT']\n for reply in replies:\n if (':' in reply['source']) != (family == 'ip6tables'): continue\n rules.append('-A ' + chain + ' -p tcp -s ' + reply['source'] + ' --sport ' + str(reply['sourcePort']) +\n ' -d ' + reply['destination'] + ' --dport ' + str(reply['destinationPort']) +\n ' --tcp-flags SYN,RST,ACK ACK -j ACCEPT')\n rules += ['-A ' + chain + ' -j DROP', 'COMMIT']\n result = subprocess.run([family + '-restore', '-w', '5', '--noflush'], input=('\\n'.join(rules) + '\\n').encode(), capture_output=True, timeout=25)\n if result.returncode and family == 'ip6tables':\n # Without owner matching, deny IPv6 neighbor traffic too rather than leaving the family open.\n fallback = [rule for rule in rules if '-p ipv6-icmp ' not in rule]\n result = subprocess.run([family + '-restore', '-w', '5', '--noflush'], input=('\\n'.join(fallback) + '\\n').encode(), capture_output=True, timeout=25)\n if result.returncode: raise RuntimeError('Atomic emergency denial failed for ' + family)\n if hooked.returncode != 0: command(family, '-t', 'filter', '-I', hook, '1', '-j', chain)\n except Exception as cause: failures.append(str(cause))\n if failures: raise RuntimeError('Cannot install minimal namespace denial: ' + '; '.join(failures))\n\ndef guard(allow_tunnel=False):\n try: install_guard(allow_tunnel)\n except Exception:\n try: install_guard(closed=True)\n except Exception:\n try: minimal_guard()\n except Exception as failure:\n raise DenialUnavailableError('Workspace network denial could not be installed') from failure\n raise\n\ndef clear_identity():\n for path in ROOT.glob('state-*'):\n if path.is_file(): path.unlink()\n (ROOT / 'enrollment.key').unlink(missing_ok=True)\n\ndef stop_controller():\n with open(ROOT / 'daemon.lock', 'a') as lock:\n deadline = time.monotonic() + 5\n signaled = None\n while True:\n pid = load(ROOT / 'controller.pid')\n if isinstance(pid, int) and pid != signaled:\n try:\n args = pathlib.Path('/proc/' + str(pid) + '/cmdline').read_bytes().split(bytes([0]))\n if str(ROOT / 'controller.py').encode() in args and b'run' in args:\n os.kill(pid, signal.SIGTERM); signaled = pid\n except ProcessLookupError: pass\n except FileNotFoundError: pass\n try:\n fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)\n clear_identity()\n return\n except BlockingIOError:\n if time.monotonic() >= deadline: raise RuntimeError('Workspace egress controller did not stop')\n time.sleep(.05)\n\ndef capture_errors(proc):\n tail = collections.deque(maxlen=128)\n while True:\n chunk = proc.stderr.read1(4096)\n if not chunk: return\n tail.append(chunk)\n atomic(ROOT / 'daemon.log', b''.join(tail), binary=True)\n\ndef select_exit(config, peers, selected, health_misses, helper, sock):\n candidates = sorted(config.get('devices', []), key=lambda item: item.get('tailscaleIp') != selected)\n for item in candidates:\n ip = item.get('tailscaleIp')\n if ip not in peers or not peers[ip].get('Online') or peers[ip].get('Expired'): continue\n try:\n # TSMP tests the encrypted peer path without opening a destination connection.\n cli(helper, sock, 'ping', '--tsmp', '--c=1', '--timeout=2s', str(ipaddress.IPv4Address(ip)))\n health_misses[ip] = 0\n return item\n except (RuntimeError, ValueError) as cause:\n atomic(ROOT / 'last-peer-error.json', {'deviceId': item['deviceId'], 'error': str(cause), 'atMs': int(time.time() * 1000)})\n health_misses[ip] = health_misses.get(ip, 0) + 1\n if ip == selected and health_misses[ip] < 3: break\n continue\n return None\n\ndef run():\n with open(ROOT / 'daemon.lock', 'a') as lock:\n deadline = time.monotonic() + 5\n while True:\n try:\n fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)\n break\n except BlockingIOError:\n pid = load(ROOT / 'controller.pid')\n alive = False\n try:\n alive = isinstance(pid, int) and str(ROOT / 'controller.py').encode() in pathlib.Path('/proc/' + str(pid) + '/cmdline').read_bytes().split(bytes([0]))\n except FileNotFoundError: pass\n if time.monotonic() >= deadline:\n if alive: return\n raise RuntimeError('Workspace controller startup lock is busy')\n time.sleep(.01)\n atomic(ROOT / 'controller.pid', os.getpid())\n proc = None\n current = None\n selected = None\n health_misses = {}\n bridges = None\n revision = None\n def terminate(signum, frame):\n raise SystemExit(0)\n signal.signal(signal.SIGTERM, terminate)\n signal.signal(signal.SIGINT, terminate)\n try:\n while True:\n config = load(ROOT / 'config.json', {})\n mode = config.get('mode', 'blocked')\n if mode != 'device' or config.get('bootId') != BOOT_ID or config.get('expiresAtMs', 0) <= time.time() * 1000 or config.get('deadlineMonotonic', 0) <= time.monotonic():\n # Coordinate relinquishing the daemon lock with writers so a renewal cannot lose its controller.\n with open(ROOT / 'request.lock', 'a') as requests:\n fcntl.flock(requests, fcntl.LOCK_EX)\n if load(ROOT / 'config.json', {}) != config: continue\n stop(proc); proc = None; current = None; selected = None\n clear_identity()\n if mode == 'direct':\n restore(); status('direct', config)\n else:\n guard(); status('blocked', config)\n fcntl.flock(lock, fcntl.LOCK_UN)\n return\n helper = ROOT / 'helper'\n sock = ROOT / 'control.sock'\n revision = config.get('revision', config['leaseId'])\n if revision != current or proc is None or proc.poll() is not None:\n stop(proc); proc = None\n with open(ROOT / 'request.lock', 'a') as requests:\n fcntl.flock(requests, fcntl.LOCK_EX)\n if load(ROOT / 'config.json', {}).get('revision', load(ROOT / 'config.json', {}).get('leaseId')) != revision: continue\n guard(); transport_hosts(config['transportHosts'])\n sock.unlink(missing_ok=True)\n state = ROOT / ('state-' + lease_state_name(config['leaseId']))\n for old in ROOT.glob('state-*'):\n if old != state and old.is_file(): old.unlink()\n env = helper_environment()\n proc = subprocess.Popen([str(helper), '--tun=final-egress0', '--port=0', '--socket=' + str(sock), '--state=' + str(state)],\n stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, env=env)\n threading.Thread(target=capture_errors, args=(proc,), daemon=True).start()\n proc.stdin.write(b'final-device-start\\n'); proc.stdin.flush()\n deadline = time.monotonic() + 5\n while not sock.exists():\n if proc.poll() is not None or time.monotonic() > deadline:\n raise RuntimeError('Workspace egress daemon did not become ready')\n time.sleep(.05)\n args = ['up', '--reset', '--login-server=' + config['controlUrl'], '--hostname=workspace-' + lease_state_name(config['leaseId'])[:40],\n '--accept-dns=false', '--accept-routes=false', '--shields-up', '--netfilter-mode=off']\n if config.get('authKey'):\n atomic(ROOT / 'enrollment.key', config['authKey'].encode(), binary=True)\n args.append('--auth-key=file:' + str(ROOT / 'enrollment.key'))\n args.append('--force-reauth')\n try: cli(helper, sock, *args)\n finally:\n (ROOT / 'enrollment.key').unlink(missing_ok=True)\n with open(ROOT / 'request.lock', 'a') as requests:\n # A writer may hold request.lock while awaiting our daemon.lock.\n try: fcntl.flock(requests, fcntl.LOCK_EX | fcntl.LOCK_NB)\n except BlockingIOError: pass\n else:\n pending = load(ROOT / 'config.json', {})\n if pending.get('revision', pending.get('leaseId')) == revision:\n pending.pop('authKey', None); atomic(ROOT / 'config.json', pending)\n with open(ROOT / 'request.lock', 'a') as requests:\n fcntl.flock(requests, fcntl.LOCK_EX)\n saved = load(ROOT / 'config.json', {})\n if saved.get('mode') != 'device' or saved.get('leaseId') != config.get('leaseId') or saved.get('revision', saved.get('leaseId')) != revision:\n stop(proc); proc = None; current = None; selected = None\n continue\n resolver(saved.get('dnsResolvers', ['1.1.1.1', '9.9.9.9']))\n saved.pop('authKey', None); atomic(ROOT / 'config.json', saved)\n current = revision; selected = None\n guard(allow_tunnel=True)\n if config.get('state') == 'provisioning':\n controller_status('enrolled', config)\n time.sleep(.2)\n continue\n actual_bridges = local_bridges()\n with open(ROOT / 'request.lock', 'a') as requests:\n fcntl.flock(requests, fcntl.LOCK_EX)\n latest = load(ROOT / 'config.json', {})\n if latest.get('mode') != 'device' or latest.get('revision', latest.get('leaseId')) != revision: continue\n resolver(latest.get('dnsResolvers', ['1.1.1.1', '9.9.9.9']))\n previous_listeners = load(ROOT / 'control-listeners.json', [])\n existing_control_replies()\n actual_tunnel = command('ip', '-j', 'addr', 'show', 'dev', 'final-egress0', check=False)\n actual_addresses = [str(ipaddress.ip_address(address['local'])) for interface in json.loads(actual_tunnel.stdout or b'[]') for address in interface.get('addr_info', [])]\n if bridges != actual_bridges or previous_listeners != load(ROOT / 'control-listeners.json', []) or actual_addresses != load(ROOT / 'tunnel-addresses.json', []):\n guard(allow_tunnel=True); bridges = actual_bridges\n try:\n raw = json.loads(cli(helper, sock, 'status', '--json'))\n peers = {ip: peer for peer in (raw.get('Peer') or {}).values() for ip in (peer.get('TailscaleIPs') or [])}\n candidates = config.get('devices', [])\n candidate = select_exit(config, peers, selected, health_misses, helper, sock)\n if candidate is None:\n last = next((item for item in candidates if item.get('tailscaleIp') == selected), None)\n # A health miss must not tear down an authorized route during control outage/rekey.\n # Keeping it can only use the approved exit; the namespace guard still forbids direct fallback.\n if last is not None and selected in peers and not peers[selected].get('Expired'):\n peer = peers[selected]\n controller_status('reconnecting', config, deviceId=last['deviceId'], path='direct' if peer.get('CurAddr') else 'relay')\n else:\n if selected is not None: cli(helper, sock, 'set', '--exit-node=')\n selected = None\n controller_status('blocked', config)\n else:\n ip = str(ipaddress.IPv4Address(candidate['tailscaleIp']))\n if selected != ip:\n cli(helper, sock, 'set', '--exit-node=' + ip, '--exit-node-allow-lan-access=false')\n selected = ip\n route = command('ip', '-4', 'route', 'get', '192.0.2.254').stdout\n if b'dev final-egress0' not in route:\n controller_status('configuring', config)\n time.sleep(.1)\n continue\n peer = peers[ip]\n controller_status('device', config, deviceId=candidate['deviceId'], path='direct' if peer.get('CurAddr') else 'relay')\n time.sleep(1)\n except (RuntimeError, subprocess.TimeoutExpired, json.JSONDecodeError) as failure:\n atomic(ROOT / 'last-peer-error.json', {'error': str(failure)[:1000], 'atMs': int(time.time() * 1000)})\n controller_status('reconnecting', config)\n time.sleep(1)\n except Exception as cause:\n atomic(ROOT / 'last-error.json', {'error': str(cause), 'atMs': int(time.time() * 1000)})\n controller_status('error', load(ROOT / 'config.json', {}), error='Workspace egress stopped; inspect the controller error')\n raise\n finally:\n stop(proc)\n if load(ROOT / 'controller.pid') == os.getpid(): (ROOT / 'controller.pid').unlink(missing_ok=True)\n # Writers can await daemon.lock while holding request.lock; finish secret cleanup after releasing it.\n fcntl.flock(lock, fcntl.LOCK_UN)\n with open(ROOT / 'request.lock', 'a') as requests:\n fcntl.flock(requests, fcntl.LOCK_EX)\n pending = load(ROOT / 'config.json', {})\n if revision is not None and pending.get('revision', pending.get('leaseId')) == revision and 'authKey' in pending:\n pending.pop('authKey', None); atomic(ROOT / 'config.json', pending)\n\ndef apply(request):\n prerequisite(request['action'])\n with open(ROOT / 'request.lock', 'a') as lock:\n fcntl.flock(lock, fcntl.LOCK_EX)\n action = request['action']\n source = pathlib.Path(__file__).read_bytes() if '__file__' in globals() else sys.argv[1].encode()\n cached_source = ROOT / 'controller.py'\n if not cached_source.exists() or cached_source.read_bytes() != source: atomic(cached_source, source, binary=True)\n existing = load(ROOT / 'config.json', {})\n capabilities = [int(line.split()[1], 16) for line in pathlib.Path('/proc/self/status').read_text().splitlines() if line.startswith(('CapInh:', 'CapPrm:', 'CapEff:', 'CapBnd:', 'CapAmb:'))]\n # A prior choice with lost volatile state is not proof of an untouched namespace.\n network_pristine = (existing.get('noNetworkChanges') is True or ((not existing or existing.get('mode') == 'direct') and not (PERSISTENT / 'intent.json').exists())) and bool(capabilities) and not any(mask & (1 << 12) for mask in capabilities) and not (PERSISTENT / 'resolver.original').exists() and not (PERSISTENT / 'hosts.original').exists() and not (ROOT / 'controller.pid').exists()\n workspace_id = request.get('workspaceId')\n if action != 'status' and existing.get('workspaceId') is not None and existing['workspaceId'] != workspace_id:\n raise RuntimeError('This network namespace belongs to a different workspace')\n operation = load(ROOT / 'operation.json', {})\n operation_live = operation.get('bootId') == BOOT_ID and operation.get('deadline', 0) > time.monotonic()\n token = str(uuid.UUID(request['configurationToken'])) if request.get('configurationToken') is not None else None\n if action == 'claim':\n if (request.get('refresh') or request.get('verifyOnly')) and (not operation_live or operation.get('token') != token):\n raise WorkspaceConflictError('Workspace configuration claim was superseded')\n if operation_live and operation.get('token') != token:\n return {**load(ROOT / 'status.json', {'mode': 'blocked', 'leaseId': None, 'expiresAtMs': None, 'deviceId': None, 'path': None}), 'busy': True}\n token = str(uuid.UUID(token))\n if not request.get('verifyOnly'):\n atomic(ROOT / 'operation.json', {'token': token, 'deadline': time.monotonic() + 300, 'bootId': BOOT_ID})\n return {**load(ROOT / 'status.json', {'mode': 'blocked', 'leaseId': None, 'expiresAtMs': None, 'deviceId': None, 'path': None}), 'busy': False}\n if action == 'unlock':\n if operation.get('token') == token: (ROOT / 'operation.json').unlink(missing_ok=True)\n return load(ROOT / 'status.json', {'mode': 'blocked', 'leaseId': None, 'expiresAtMs': None, 'deviceId': None, 'path': None})\n if action not in ('status', 'artifact'):\n if token is not None and (not operation_live or operation.get('token') != token):\n raise WorkspaceConflictError('Workspace egress configuration was superseded')\n if operation_live and token != operation.get('token'):\n raise WorkspaceConflictError('Another binding is configuring workspace egress')\n expected = lease_id(request['expectedLeaseId']) if request.get('expectedLeaseId') is not None else None\n if token is None and expected is not None and existing.get('leaseId') != expected:\n if action == 'block' and existing.get('leaseId') is None and existing.get('mode') == 'direct':\n return load(ROOT / 'status.json', {'mode': 'direct', 'leaseId': None, 'expiresAtMs': None, 'deviceId': None, 'path': None})\n if action == 'block' and existing.get('leaseId') is None and existing.get('mode') == 'blocked':\n try: guard()\n except Exception as failure:\n status('error' if isinstance(failure, DenialUnavailableError) else 'blocked', existing)\n raise\n return status('blocked', existing)\n if not (action == 'block' and existing.get('leaseId') is None and (not existing or existing.get('mode') == 'blocked')):\n raise WorkspaceConflictError('Workspace egress lease changed before cleanup')\n if action not in ('status', 'artifact'):\n PERSISTENT.mkdir(mode=0o700, exist_ok=True)\n if PERSISTENT.is_symlink() or PERSISTENT.stat().st_uid != 0:\n raise RuntimeError('Persistent workspace egress state must be root-owned')\n PERSISTENT.chmod(0o700)\n identity = load(PERSISTENT / 'identity.json', {})\n if identity.get('workspaceId') is not None and identity['workspaceId'] != workspace_id:\n raise RuntimeError('Persistent egress state belongs to a different workspace')\n if action != 'disable': atomic(PERSISTENT / 'identity.json', {'workspaceId': workspace_id})\n if action == 'block': atomic(PERSISTENT / 'intent.json', {'requiresChoice': not request.get('restoreDirect', False)})\n if action == 'disable' and existing.get('noNetworkChanges') is True:\n if (PERSISTENT / 'resolver.original').exists() or (PERSISTENT / 'hosts.original').exists() or (ROOT / 'controller.pid').exists():\n raise RuntimeError('Workspace contains restoration artifacts; privileged repair is required')\n (PERSISTENT / 'identity.json').unlink(missing_ok=True)\n (PERSISTENT / 'intent.json').unlink(missing_ok=True)\n config = {'mode': 'direct', 'workspaceId': workspace_id, 'ownerUserId': None}\n atomic(ROOT / 'config.json', config)\n return status('direct', config)\n if action == 'disable' and (not existing or (existing.get('mode') == 'direct' and load(ROOT / 'status.json', {}).get('mode') == 'direct')):\n if restoration_pending(): restore()\n (PERSISTENT / 'identity.json').unlink(missing_ok=True)\n (PERSISTENT / 'intent.json').unlink(missing_ok=True)\n config = {'mode': 'direct', 'workspaceId': workspace_id, 'ownerUserId': None}\n atomic(ROOT / 'config.json', config)\n return status('direct', config)\n if action == 'artifact':\n ready = False\n try: fd = os.open(ROOT / 'helper', os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)\n except FileNotFoundError: pass\n else:\n with os.fdopen(fd, 'rb') as source:\n info = os.fstat(source.fileno())\n if stat.S_ISREG(info.st_mode) and info.st_size <= 128 * 1024 * 1024:\n ready = hashlib.sha256(source.read(128 * 1024 * 1024 + 1)).hexdigest() == request['sha256']\n return {**load(ROOT / 'status.json', {'mode': 'blocked', 'leaseId': None, 'expiresAtMs': None, 'deviceId': None, 'path': None}), 'helperReady': ready}\n if action == 'status':\n result = load(ROOT / 'status.json', {'mode': 'direct', 'leaseId': None, 'expiresAtMs': None, 'deviceId': None, 'path': None, 'architecture': platform.machine()})\n alive = False\n with open(ROOT / 'daemon.lock', 'a') as daemon_lock:\n try:\n fcntl.flock(daemon_lock, fcntl.LOCK_EX | fcntl.LOCK_NB)\n if result.get('mode') != 'error' and existing.get('mode') not in ('direct', 'error') and existing:\n result = {**result, 'mode': 'blocked' if denial_present() else 'error', 'deviceId': None, 'path': None}\n except BlockingIOError: alive = True\n return {**result, 'networkPristine': existing.get('noNetworkChanges', False), 'controllerAlive': alive, 'configuring': operation_live, 'restorePending': restoration_pending(), 'choicePending': load(PERSISTENT / 'intent.json', {}).get('requiresChoice', existing.get('mode') == 'blocked')}\n if action in ('block', 'configure'):\n try: guard()\n except Exception as failure:\n mode = 'error' if isinstance(failure, DenialUnavailableError) else 'blocked'\n failed = {'mode': mode, 'workspaceId': workspace_id, 'ownerUserId': request.get('ownerUserId'), 'noNetworkChanges': network_pristine}\n atomic(ROOT / 'config.json', failed); status(mode, failed)\n raise\n if action == 'configure':\n # Validation failure must not leave an old direct/device status after guard installation.\n pending = {'mode': 'blocked', 'workspaceId': workspace_id, 'ownerUserId': request.get('ownerUserId')}\n atomic(ROOT / 'config.json', pending); status('blocked', pending)\n if request.get('config', {}).get('workspaceId') != workspace_id: raise RuntimeError('Enrollment belongs to a different workspace')\n if command('ip', '-4', 'rule', 'show', check=False).returncode != 0:\n raise PrerequisiteError('This workspace kernel does not support Linux policy routing')\n config = request['config']\n config['dnsResolvers'] = validated_resolvers(config.get('dnsResolvers', ['1.1.1.1', '9.9.9.9']))\n control = urllib.parse.urlsplit(config['controlUrl'])\n if control.scheme != 'https' or not control.hostname or control.username is not None or control.password is not None or control.query or control.fragment:\n raise RuntimeError('Workspace control URL must use HTTPS without credentials, query or fragment')\n config['leaseId'] = lease_id(config['leaseId'])\n remaining = config['expiresAtMs'] - time.time() * 1000\n if not 0 < remaining <= 16 * 60 * 1000:\n raise RuntimeError('Workspace egress lease is expired or exceeds fifteen minutes')\n config['bootId'] = BOOT_ID\n config['deadlineMonotonic'] = time.monotonic() + min(remaining, 15 * 60 * 1000) / 1000\n # The sandbox user can replace staging files; validate and install the same bytes.\n staged = pathlib.Path(request['helperPath'])\n try: fd = os.open(staged, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)\n except FileNotFoundError as failure:\n raise RuntimeError('Staged networking helper is missing; transfer the approved artifact again') from failure\n with os.fdopen(fd, 'rb') as source:\n if not stat.S_ISREG(os.fstat(source.fileno()).st_mode):\n raise RuntimeError('Workspace networking helper must be a regular file')\n content = source.read(128 * 1024 * 1024 + 1)\n if len(content) > 128 * 1024 * 1024 or hashlib.sha256(content).hexdigest() != config['helper']['sha256']:\n raise RuntimeError('Workspace networking helper failed integrity verification')\n machine = {'x86_64': 62, 'aarch64': 183}.get(platform.machine())\n if content[:6] != b'\\x7fELF\\x02\\x01' or len(content) < 20 or struct.unpack('<H', content[18:20])[0] != machine:\n raise RuntimeError('The pinned networking helper does not match this Linux workspace architecture')\n atomic(ROOT / 'helper', content, binary=True, mode=0o700)\n config = dict(config, mode='device')\n elif action == 'renew':\n request['lease']['leaseId'] = lease_id(request['lease']['leaseId'])\n if request.get('lease', {}).get('workspaceId') != workspace_id: raise RuntimeError('Renewal belongs to a different workspace')\n config = load(ROOT / 'config.json')\n if config is None or config.get('leaseId') != request['lease']['leaseId']:\n raise WorkspaceConflictError('Workspace egress lease changed')\n if config.get('bootId') != BOOT_ID or config.get('deadlineMonotonic', 0) <= time.monotonic() or config.get('expiresAtMs', 0) <= time.time() * 1000:\n raise EnrollmentLostError('Workspace enrollment expired locally; authorized reenrollment is required')\n lease = request['lease']\n lease['leaseId'] = lease_id(lease['leaseId'])\n remaining = lease['expiresAtMs'] - time.time() * 1000\n if not 0 < remaining <= 16 * 60 * 1000:\n raise RuntimeError('Workspace egress renewal is invalid')\n config.update(bootId=BOOT_ID, expiresAtMs=lease['expiresAtMs'], devices=lease['devices'], state=lease['state'], deadlineMonotonic=time.monotonic() + min(remaining, 15 * 60 * 1000) / 1000)\n elif action in ('block', 'disable'):\n config = {'mode': 'direct' if action == 'disable' else 'blocked', 'workspaceId': workspace_id, 'ownerUserId': None if action == 'disable' else request.get('ownerUserId')}\n else:\n raise RuntimeError('Unknown workspace egress action')\n atomic(ROOT / 'config.json', config)\n if action in ('block', 'disable'): stop_controller()\n if action == 'renew':\n with open(ROOT / 'daemon.lock', 'a') as daemon_lock:\n try: fcntl.flock(daemon_lock, fcntl.LOCK_EX | fcntl.LOCK_NB)\n except BlockingIOError:\n prior = load(ROOT / 'status.json', {})\n return {**prior, 'expiresAtMs': config['expiresAtMs']}\n # The controller uses a root-owned copy after this caller's temporary files are removed.\n source = pathlib.Path(__file__).read_bytes() if '__file__' in globals() else sys.argv[1].encode()\n atomic(ROOT / 'controller.py', source, binary=True)\n subprocess.Popen([sys.executable, '-I', str(ROOT / 'controller.py'), 'run'], stdin=subprocess.DEVNULL,\n stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=True)\n if action == 'block': return status('blocked', config)\n return status('configuring', config)\n\nif __name__ == '__main__':\n try:\n if len(sys.argv) > 1 and sys.argv[1] == 'run': run()\n else: print(json.dumps(apply(json.load(sys.stdin))))\n except Exception as cause:\n try:\n if ROOT.exists() and not ROOT.is_symlink() and ROOT.stat().st_uid == 0:\n atomic(ROOT / 'last-error.json', {'error': str(cause)[:1000], 'atMs': int(time.time() * 1000)})\n except OSError: pass\n code = 'egress_enrollment_lost' if isinstance(cause, EnrollmentLostError) else 'prerequisite' if isinstance(cause, (FileNotFoundError, PrerequisiteError)) else 'conflict' if isinstance(cause, WorkspaceConflictError) else 'configuration'\n print(json.dumps({'errorCode': code}))\n sys.exit(1)\n`;\n\n// Verify the owned source before executing it; a cache miss requests the full bootstrap once.\nexport const cachedWorkspaceEgressBootstrap = (sha256: string): string => {\n if (!/^[a-f0-9]{64}$/.test(sha256)) throw new Error('Invalid workspace controller SHA256');\n return String.raw`import hashlib, os, pathlib, stat\npath = pathlib.Path('/run/final-workspace-egress/controller.py')\ntry:\n fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)\n with os.fdopen(fd, 'rb') as file:\n info = os.fstat(file.fileno())\n source = file.read(128 * 1024 + 1)\n valid = stat.S_ISREG(info.st_mode) and info.st_uid == 0 and not info.st_mode & 0o022 and len(source) <= 128 * 1024 and hashlib.sha256(source).hexdigest() == '${sha256}'\nexcept OSError: valid = False\nif valid: exec(compile(source, str(path), 'exec'), {'__name__': '__main__', '__file__': str(path)})\nelse: print('{\"needsBootstrap\":true}')\n`;\n};\n\n// Keep provider command arguments small; credentials and trusted source travel on stdin.\nexport const workspaceEgressLauncher = String.raw`import io,json,sys\nrequest=json.load(sys.stdin)\nsource=request['source']\nsys.argv=['-c',source]\nsys.stdin=io.StringIO(request['input'])\nexec(compile(source,'<final-workspace-egress>','exec'),{'__name__':'__main__'})\n`;\n"],
|
|
5
|
+
"mappings": "AACO,MAAM,2BAA2B,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAu4BxC,MAAM,iCAAiC,CAAC,WAA2B;AACxE,MAAI,CAAC,iBAAiB,KAAK,MAAM,EAAG,OAAM,IAAI,MAAM,qCAAqC;AACzF,SAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oKAOoJ,MAAM;AAAA;AAAA;AAAA;AAAA;AAK1K;AAGO,MAAM,0BAA0B,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -486,7 +486,8 @@ const createWorkspaceEgressManager = (options) => {
|
|
|
486
486
|
bytes = downloaded;
|
|
487
487
|
}
|
|
488
488
|
const hash = helper.sha256;
|
|
489
|
-
const
|
|
489
|
+
const stagingDirectory = bytes == null ? null : `/tmp/final-egress-${crypto.randomUUID()}`;
|
|
490
|
+
const helperPath = stagingDirectory == null ? "/run/final-workspace-egress/helper" : `${stagingDirectory}/helper`;
|
|
490
491
|
let leaseId = null;
|
|
491
492
|
const outcome = { result: null, failures: [] };
|
|
492
493
|
try {
|
|
@@ -550,8 +551,14 @@ const createWorkspaceEgressManager = (options) => {
|
|
|
550
551
|
}
|
|
551
552
|
}
|
|
552
553
|
try {
|
|
553
|
-
if (
|
|
554
|
+
if (stagingDirectory != null)
|
|
555
|
+
await options.sandbox.removePath({
|
|
556
|
+
path: stagingDirectory,
|
|
557
|
+
recursive: true,
|
|
558
|
+
force: true
|
|
559
|
+
});
|
|
554
560
|
} catch (cleanup) {
|
|
561
|
+
reportFailure("artifact-cleanup", cleanup);
|
|
555
562
|
outcome.failures.push(cleanup);
|
|
556
563
|
}
|
|
557
564
|
if (outcome.failures.length > 0 && outcome.result != null) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/sandboxes/egress.ts"],
|
|
4
|
-
"sourcesContent": ["import * as z from 'zod';\nimport {\n WorkspaceEgressAction,\n workspaceEgressRequestSchema,\n deviceEgressWorkspaceIdSchema,\n workspaceEgressStatusSchema,\n type WorkspaceEgressRequestIface,\n type WorkspaceEgressStatusIface,\n type DeviceEgressLeaseIface,\n WorkspaceNetworkPolicy,\n workspaceNetworkPolicySchema,\n} from '@finalai/agent-protocol/device-egress';\nimport { SandboxAccess, type JsonValue } from '@finalai/agent-provider';\nimport {\n SandboxCapability,\n SandboxExecutionOperation,\n withSandboxNetworking,\n withSandboxOverrides,\n type SandboxNetworkingControllerIface,\n type SandboxNetworkingExtensionIface,\n} from '@finalai/agent-provider/sandbox';\nimport type {\n NetworkSandboxSessionIface,\n SandboxActingUserIface,\n SandboxRunResultIface,\n SandboxProviderHandleIface,\n NetworkPolicyIface,\n} from '@finalai/agent-provider/sandbox';\nimport {\n createDeviceApiClient,\n type DeviceApiClientIface,\n type DeviceApiConfigIface,\n deviceApiStatusOf,\n deviceApiCodeOf,\n DeviceApiClientErrorCode,\n} from \"./device-api.mjs\";\nimport {\n workspaceEgressBootstrap,\n cachedWorkspaceEgressBootstrap,\n workspaceEgressLauncher,\n} from \"./egress-bootstrap.mjs\";\nimport { sleep } from \"./bytes.mjs\";\n\nconst localStatusSchema = workspaceEgressStatusSchema.extend({\n architecture: z.string().optional(),\n networkPristine: z.boolean().optional(),\n policyRouting: z.boolean().optional(),\n helperReady: z.boolean().optional(),\n busy: z.boolean().optional(),\n configuring: z.boolean().optional(),\n controllerAlive: z.boolean().optional(),\n restorePending: z.boolean().optional(),\n choicePending: z.boolean().optional(),\n ownerUserId: z.string().nullable().optional(),\n workspaceId: z.string().nullable().optional(),\n});\n\ninterface ConfigurationOutcomeIface {\n result: z.infer<typeof localStatusSchema> | null;\n failures: unknown[];\n}\n\nconst validateApprovedDevices = (lease: DeviceEgressLeaseIface, approved: readonly string[]) => {\n if (\n lease.devices.length !== approved.length ||\n lease.devices.some(\n (device, index) => device.deviceId.toLowerCase() !== approved[index]?.toLowerCase(),\n )\n )\n throw Object.assign(\n new Error('Egress lease Devices do not match the approved ordered Device list'),\n { invalidEgressLease: true, code: 'configuration' },\n );\n};\n\nconst validateActiveLease = (lease: DeviceEgressLeaseIface, at: number) => {\n if (lease.state !== 'active' || !Number.isFinite(lease.expiresAtMs) || lease.expiresAtMs <= at)\n throw Object.assign(new Error('Egress lease is not active or has expired'), {\n invalidEgressLease: true,\n code: 'configuration',\n });\n};\n\nconst isPermanentAuthorizationFailure = (error: Error): boolean => {\n const pending = [error];\n const visited = new Set<Error>();\n while (pending.length > 0 && visited.size < 32) {\n const current = pending.pop();\n if (current == null || visited.has(current)) continue;\n visited.add(current);\n const status = deviceApiStatusOf(current);\n if (status != null && [401, 403, 404, 410].includes(status)) return true;\n if (current.cause instanceof Error) pending.push(current.cause);\n if (current instanceof AggregateError)\n for (const nested of current.errors) if (nested instanceof Error) pending.push(nested);\n }\n return false;\n};\n\nexport interface WorkspaceEgressManagerOptionsIface {\n // Raw, unguarded session; passing withWorkspaceEgress() here recursively deadlocks.\n sandbox: NetworkSandboxSessionIface;\n workspaceId: string;\n organizationId: string;\n actingUser: SandboxActingUserIface;\n api: DeviceApiConfigIface | (() => DeviceApiConfigIface);\n // Must execute in this workspace's isolated network namespace, as root with NET_ADMIN.\n // Run python3 -I -c source source (or a file with __file__); pass JSON on stdin.\n privilegedRun?: (request: { source: string; input: string }) => Promise<SandboxRunResultIface>;\n client?: Pick<DeviceApiClientIface, 'egress'>;\n fetch?: typeof fetch;\n // Restore the provider's outer network policy only after the namespace guard is installed.\n afterGuard?: (policy?: NetworkPolicyIface) => Promise<void>;\n // Optional outer-provider fence after namespace denial; unsupported providers may retain namespace-only denial.\n afterBlock?: () => Promise<void>;\n // Provider-confirmed deletion permits authorization cleanup without entering a missing namespace.\n namespaceExists?: () => Promise<boolean>;\n initialNetworkPolicy?: NetworkPolicyIface;\n onNetworkPolicy?: (policy: NetworkPolicyIface) => Promise<void>;\n allowConfiguration?: boolean;\n allowOwnerChange?: boolean;\n authorizeOwnerChange?: (actingUserId: string | null) => Promise<void>;\n onClose?: () => void;\n now?: () => number;\n onFailure?: (event: {\n operation: string;\n workspaceId: string;\n leaseId: string | null;\n reason: string;\n httpStatus: number | null;\n }) => void;\n}\n\nexport const suspendWorkspaceEgress = async (args: {\n api: DeviceApiConfigIface | (() => DeviceApiConfigIface);\n organizationId: string;\n workspaceId: string;\n actingUser: SandboxActingUserIface;\n}): Promise<void> => {\n await createDeviceApiClient({ api: args.api }).egress.suspend({\n caller: { organizationId: args.organizationId, actingUser: args.actingUser },\n workspaceId: args.workspaceId,\n });\n};\n\n// Host-owned lease renewal; callers tie close() to their provider handle's lifecycle.\nexport const createWorkspaceEgressManager = (options: WorkspaceEgressManagerOptionsIface) => {\n if (!deviceEgressWorkspaceIdSchema.safeParse(options.workspaceId).success)\n throw new Error(\n 'Device egress requires a stable workspaceId of 1\u2013256 characters without control characters',\n );\n const client = options.client ?? createDeviceApiClient({ api: options.api });\n const revokeLease = async (args: Parameters<typeof client.egress.revoke>[0]) => {\n try {\n await client.egress.revoke(args);\n } catch (cause) {\n const status = cause instanceof Error ? deviceApiStatusOf(cause) : null;\n if (status !== 404 && status !== 410) throw cause;\n }\n };\n const now = options.now ?? Date.now;\n const run =\n options.privilegedRun ??\n ((request) =>\n options.sandbox.run({\n command: 'sudo',\n args: ['-n', 'python3', '-I', '-c', workspaceEgressLauncher],\n stdin: JSON.stringify(request),\n timeoutMs: 35_000,\n }));\n let pending: Promise<unknown> = Promise.resolve();\n let owner: string | null | undefined;\n let current: DeviceEgressLeaseIface | null = null;\n let closed = false;\n let stopped = false;\n let recovered = false;\n let createdLease: { leaseId: string; userId: string } | null = null;\n let directPolicy: NetworkPolicyIface | undefined = options.initialNetworkPolicy;\n let directPolicyKnown = false;\n let requiresChoice = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let nextRenewAttempt = 0;\n let nextRecoveryAttempt = 0;\n let nextRecoveryProbeAt = 0;\n let initializing = false;\n let configurationToken: string | null = null;\n let pendingUnlock: string | null = null;\n let repairProviderPolicy = false;\n let configurationFailure: unknown = null;\n let notifiedClosed = false;\n const notifyClosed = () => {\n if (!notifiedClosed) {\n notifiedClosed = true;\n options.onClose?.();\n }\n };\n let cachedStatus: {\n at: number;\n userId: string | null;\n value: z.infer<typeof localStatusSchema>;\n } | null = null;\n const reportFailure = (operation: string, cause: unknown) => {\n const rawCode = z.object({ code: z.string() }).safeParse(cause).data?.code;\n const known = [\n 'credential_missing',\n 'no_acting_user',\n 'unauthorized',\n 'forbidden',\n 'not_found',\n 'unavailable',\n 'invalid',\n 'rate_limited',\n 'prerequisite',\n 'conflict',\n 'configuration',\n 'request_failed',\n 'egress_enrollment_lost',\n ];\n try {\n options.onFailure?.({\n operation,\n workspaceId: options.workspaceId,\n leaseId: current?.leaseId ?? null,\n reason:\n rawCode != null && known.includes(rawCode)\n ? rawCode\n : cause instanceof TypeError\n ? 'transport'\n : 'operation_failed',\n httpStatus: cause instanceof Error ? deviceApiStatusOf(cause) : null,\n });\n } catch {\n // Host telemetry must not interrupt fencing, claim cleanup, or renewal.\n console.warn('Workspace egress failure observer threw');\n }\n };\n const serialized = <T>(work: () => Promise<T>): Promise<T> => {\n const task = pending.then(work, work);\n pending = task.catch(() => undefined);\n return task;\n };\n let sourceDigest: Promise<string> | null = null;\n const execute = async (request: Record<string, JsonValue>) => {\n if (request.action === 'block' && configurationToken == null && pendingUnlock != null) {\n try {\n await execute({\n action: 'claim',\n configurationToken: pendingUnlock,\n refresh: true,\n verifyOnly: true,\n });\n } catch (cause) {\n if (!z.object({ code: z.literal('conflict') }).safeParse(cause).success) throw cause;\n pendingUnlock = null;\n }\n }\n if (\n configurationFailure != null &&\n request.action !== 'status' &&\n request.action !== 'unlock' &&\n request.action !== 'block'\n )\n throw configurationFailure;\n if (request.action !== 'status') cachedStatus = null;\n sourceDigest ??= crypto.subtle\n .digest('SHA-256', new TextEncoder().encode(workspaceEgressBootstrap))\n .then((hash) =>\n [...new Uint8Array(hash)].map((byte) => byte.toString(16).padStart(2, '0')).join(''),\n );\n const input = JSON.stringify({\n ...request,\n configurationToken: request.configurationToken ?? configurationToken ?? pendingUnlock,\n workspaceId: options.workspaceId,\n });\n let result = await run({ source: cachedWorkspaceEgressBootstrap(await sourceDigest), input });\n if (result.exitCode === 0) {\n let response: unknown;\n try {\n response = JSON.parse(result.stdout);\n } catch {\n response = null;\n }\n if (z.object({ needsBootstrap: z.literal(true) }).safeParse(response).success)\n result = await run({ source: workspaceEgressBootstrap, input });\n }\n if (result.exitCode !== 0) {\n let failure: unknown;\n try {\n failure = JSON.parse(result.stdout);\n } catch {\n failure = null;\n }\n const parsed = z.object({ errorCode: z.string() }).safeParse(failure);\n const code =\n parsed.success &&\n [\n 'prerequisite',\n 'conflict',\n 'configuration',\n DeviceApiClientErrorCode.EgressEnrollmentLost,\n ].includes(parsed.data.errorCode)\n ? parsed.data.errorCode\n : 'prerequisite';\n throw Object.assign(\n new Error(\n `Workspace egress ${code} failed${code === 'prerequisite' ? ' (root, TUN, NET_ADMIN and policy routing required)' : ''}. Inspect the root-owned last-error.json for details`,\n ),\n { code },\n );\n }\n let raw: unknown;\n try {\n raw = JSON.parse(result.stdout);\n } catch {\n throw new Error('Invalid workspace egress status');\n }\n const status = localStatusSchema.parse(raw);\n if (request.action === 'block' && configurationToken == null && pendingUnlock != null) {\n try {\n await execute({ action: 'unlock', configurationToken: pendingUnlock });\n pendingUnlock = null;\n } catch (cause) {\n reportFailure('unlock', cause);\n }\n }\n return status;\n };\n const statusForGuard = async (userId: string | null) => {\n if (\n cachedStatus != null &&\n cachedStatus.userId === userId &&\n performance.now() - cachedStatus.at < 100\n )\n return cachedStatus.value;\n const value = await execute({ action: 'status' });\n cachedStatus = { at: performance.now(), userId, value };\n return value;\n };\n const callerFor = (userId: string | null) => ({\n organizationId: options.organizationId,\n actingUser: { current: async () => userId },\n });\n const block = async (userId: string | null, restoreDirect = false) => {\n current = null;\n const local = await execute({ action: 'block', ownerUserId: userId, restoreDirect }).catch(\n async (cause) => {\n if (z.object({ code: z.literal('conflict') }).safeParse(cause).success) throw cause;\n const fences = await Promise.allSettled([\n options.afterBlock?.(),\n options.afterGuard == null\n ? undefined\n : restoreNetwork({ mode: WorkspaceNetworkPolicy.DenyAll }),\n ]);\n const failures = fences.flatMap((result) =>\n result.status === 'rejected' ? [result.reason] : [],\n );\n if (failures.length > 0)\n throw new AggregateError([cause, ...failures], 'Namespace and provider denial failed');\n throw cause;\n },\n );\n await options.afterBlock?.();\n return local;\n };\n const release = async (args: {\n userId: string | null;\n leaseId: string | null;\n nextOwner: string | null;\n suspendWorkspace?: boolean;\n restoreDirect?: boolean;\n }) => {\n const failures: unknown[] = [];\n let denied = false;\n let superseded = false;\n current = null;\n try {\n const local = await execute({\n action: 'block',\n ownerUserId: args.nextOwner,\n expectedLeaseId: args.suspendWorkspace === true ? null : args.leaseId,\n restoreDirect: args.restoreDirect ?? false,\n });\n denied = local.mode === 'blocked';\n superseded = !denied;\n } catch (cause) {\n superseded = z.object({ code: z.literal('conflict') }).safeParse(cause).success;\n failures.push(cause);\n }\n if (!superseded || args.suspendWorkspace === true)\n try {\n const fences = await Promise.allSettled([\n options.afterBlock?.(),\n (!denied || options.afterBlock == null) && options.afterGuard != null\n ? restoreNetwork({ mode: WorkspaceNetworkPolicy.DenyAll, allow: [] })\n : undefined,\n ]);\n const rejected = fences.flatMap((result) =>\n result.status === 'rejected' ? [result.reason] : [],\n );\n if (rejected.length > 0) throw new AggregateError(rejected, 'Provider denial failed');\n repairProviderPolicy = false;\n } catch (cause) {\n failures.push(cause);\n }\n if (args.suspendWorkspace === true) {\n try {\n // Local owner/lease fields constrain the namespace guard, never API identity.\n await client.egress.suspend({\n caller: callerFor(args.userId),\n workspaceId: options.workspaceId,\n });\n createdLease = null;\n } catch (cause) {\n failures.push(cause);\n }\n } else if (args.userId != null && args.leaseId != null) {\n try {\n await revokeLease({\n caller: callerFor(args.userId),\n leaseId: args.leaseId,\n workspaceId: options.workspaceId,\n });\n if (createdLease?.leaseId === args.leaseId) createdLease = null;\n } catch (cause) {\n failures.push(cause);\n }\n }\n if (failures.length > 0)\n throw new AggregateError(failures, 'Workspace network block or egress revocation failed');\n };\n let reportedPolicy: string | null = null;\n const reportLogicalPolicy = async () => {\n const logical =\n directPolicyKnown && directPolicy != null\n ? directPolicy\n : { mode: WorkspaceNetworkPolicy.DenyAll };\n const encoded = JSON.stringify(logical);\n if (encoded !== reportedPolicy) {\n await options.onNetworkPolicy?.(logical);\n reportedPolicy = encoded;\n }\n };\n const restoreNetwork = async (policy: { mode: string; allow?: string[] } | null) => {\n const parsed = workspaceNetworkPolicySchema.safeParse(policy);\n if (policy != null && !parsed.success)\n throw new Error('Saved workspace network policy is unsupported; networking remains blocked');\n const desired = parsed.success ? parsed.data : { mode: WorkspaceNetworkPolicy.DenyAll };\n if (options.afterGuard != null) await options.afterGuard(desired);\n else if (desired.mode !== WorkspaceNetworkPolicy.AllowAll || options.afterBlock != null)\n throw new Error('A provider policy-restoration hook is required; networking remains blocked');\n await reportLogicalPolicy();\n };\n const profileFor = async (userId: string) => {\n const caller = callerFor(userId);\n const profile = await client.egress.workspace({ caller, workspaceId: options.workspaceId });\n if (profile.networkPolicy != null) {\n directPolicy = workspaceNetworkPolicySchema.parse(profile.networkPolicy);\n directPolicyKnown = true;\n }\n if (profile.networkPolicy == null && options.initialNetworkPolicy == null) {\n requiresChoice = true;\n await block(userId);\n throw new Error(\n 'The host must supply the current network policy before opting in a workspace',\n );\n }\n if (profile.networkPolicy == null && options.initialNetworkPolicy != null) {\n const policy = workspaceNetworkPolicySchema.parse(options.initialNetworkPolicy);\n directPolicy = policy;\n await client.egress.setNetworkPolicy({\n caller: callerFor(null),\n workspaceId: options.workspaceId,\n policy,\n initializeIfMissing: true,\n });\n const initialized = await client.egress.workspace({\n caller,\n workspaceId: options.workspaceId,\n });\n if (initialized.networkPolicy != null) {\n directPolicy = workspaceNetworkPolicySchema.parse(initialized.networkPolicy);\n directPolicyKnown = true;\n }\n return initialized;\n }\n return profile;\n };\n const authorizeRouteMutation = async (\n userId: string | null,\n local: z.infer<typeof localStatusSchema>,\n ) => {\n if (\n options.allowOwnerChange === false &&\n local.ownerUserId != null &&\n local.ownerUserId !== userId\n )\n throw new Error('Workspace egress belongs to another actor; this binding requires its owner');\n if (local.ownerUserId != null && local.ownerUserId !== userId)\n await options.authorizeOwnerChange?.(userId);\n // An owned active lease permits local cleanup during an outage; other routes require fresh authority.\n if (\n current != null &&\n owner === userId &&\n local.ownerUserId === userId &&\n local.leaseId === current.leaseId &&\n current.state === 'active' &&\n current.expiresAtMs > now()\n )\n return;\n if (userId == null) {\n await client.egress.networkState({\n organizationId: options.organizationId,\n workspaceId: options.workspaceId,\n });\n return;\n }\n const profile = await client.egress.workspace({\n caller: callerFor(userId),\n workspaceId: options.workspaceId,\n });\n if (options.allowOwnerChange === false && profile.lockedByOtherOwner)\n throw new Error('Workspace egress belongs to another actor; this binding requires its owner');\n };\n const waitReady = async (leaseId: string | null, mode: string) => {\n const deadline = performance.now() + 35_000;\n for (;;) {\n const result = await execute({ action: 'status' });\n if (result.mode === mode && (leaseId == null || result.leaseId === leaseId)) return result;\n if (performance.now() >= deadline)\n throw new Error('Workspace egress did not become ready; networking remains blocked');\n await sleep(200);\n }\n };\n const configureAttempt = async (userId: string, deviceIds: string[], dnsResolvers?: string[]) => {\n recovered = false;\n await authorizeRouteMutation(userId, await execute({ action: 'status' }));\n const local = await block(userId);\n if (local.policyRouting === false)\n throw new Error(\n 'This sandbox kernel does not support the Linux policy routing required for Device egress',\n );\n const caller = callerFor(userId);\n const profile = await profileFor(userId);\n if (\n options.afterGuard == null &&\n (directPolicy?.mode !== WorkspaceNetworkPolicy.AllowAll || options.afterBlock != null)\n )\n throw new Error('A provider policy-restoration hook is required before Device configuration');\n try {\n if (profile.lease != null)\n await revokeLease({\n caller,\n leaseId: profile.lease.leaseId,\n workspaceId: options.workspaceId,\n });\n if (\n profile.onlineDeviceIds != null &&\n deviceIds.every((id) =>\n profile.deviceIds.some((saved) => saved.toLowerCase() === id.toLowerCase()),\n ) &&\n !deviceIds.some((id) =>\n profile.onlineDeviceIds?.some((online) => online.toLowerCase() === id.toLowerCase()),\n )\n )\n throw new Error('No configured egress Device is online; networking remains blocked');\n const architecture = local.architecture ?? 'x86_64';\n const selectArtifact = (artifacts: DeviceEgressLeaseIface['helper']) => {\n const selected = [artifacts, ...(artifacts.alternatives ?? [])].find(\n (item) => (item.architecture ?? 'x86_64') === architecture,\n );\n if (selected == null)\n throw new Error(\n 'No approved networking helper is configured for this workspace architecture',\n );\n return selected;\n };\n const helper = selectArtifact(profile.helper);\n const helperUrl = new URL(helper.url);\n if (helperUrl.protocol !== 'https:') {\n throw new Error('Workspace networking artifacts require HTTPS');\n }\n const cached = await execute({ action: 'artifact', sha256: helper.sha256 });\n let bytes: Uint8Array | null = null;\n if (cached.helperReady !== true) {\n const response = await (options.fetch ?? fetch)(helperUrl, {\n redirect: 'error',\n signal: AbortSignal.timeout(60_000),\n });\n if (!response.ok || response.body == null) {\n await response.body?.cancel();\n throw new Error('Could not download the pinned workspace networking helper');\n }\n const chunks: Uint8Array[] = [];\n let size = 0;\n const reader = response.body.getReader();\n try {\n for (;;) {\n const next = await reader.read();\n if (next.done) break;\n size += next.value.byteLength;\n if (size > 128 * 1024 * 1024)\n throw new Error('Workspace networking helper exceeds its size limit');\n chunks.push(next.value);\n }\n } finally {\n await reader.cancel();\n }\n const downloaded = new Uint8Array(size);\n let offset = 0;\n for (const chunk of chunks) {\n downloaded.set(chunk, offset);\n offset += chunk.byteLength;\n }\n const hash = [...new Uint8Array(await crypto.subtle.digest('SHA-256', downloaded))]\n .map((byte) => byte.toString(16).padStart(2, '0'))\n .join('');\n if (hash !== helper.sha256)\n throw new Error('Workspace networking helper failed integrity verification');\n bytes = downloaded;\n }\n const hash = helper.sha256;\n const helperPath =\n bytes == null\n ? '/run/final-workspace-egress/helper'\n : `/tmp/final-egress-${crypto.randomUUID()}`;\n let leaseId: string | null = null;\n const outcome: ConfigurationOutcomeIface = { result: null, failures: [] };\n try {\n if (bytes != null)\n await options.sandbox.writeBinaryFile({ path: helperPath, content: bytes });\n // Downloads and uploads can outlive the claim; do not enroll after another binding wins.\n const refreshed = await execute({ action: 'claim', configurationToken, refresh: true });\n if (refreshed.busy === true)\n throw new Error('Workspace configuration claim was superseded');\n const lease = await client.egress.create({\n caller,\n workspaceId: options.workspaceId,\n deviceIds,\n dnsResolvers,\n });\n leaseId = lease.leaseId;\n createdLease = { leaseId: lease.leaseId, userId };\n validateApprovedDevices(lease, deviceIds);\n if (lease.workspaceId !== options.workspaceId)\n throw new Error('Egress enrollment belongs to a different workspace');\n if (lease.state !== 'provisioning')\n throw new Error('Egress enrollment must return provisioning state before activation');\n if (selectArtifact(lease.helper).sha256 !== hash)\n throw new Error('Networking artifact changed during enrollment; retry configuration');\n // Allow transport only once local denial, artifact integrity, and lease ownership are established.\n await execute({ action: 'claim', configurationToken, refresh: true });\n repairProviderPolicy = true;\n await restoreNetwork({ mode: WorkspaceNetworkPolicy.AllowAll, allow: [] });\n await execute({ action: 'claim', configurationToken, refresh: true });\n await execute({\n action: 'configure',\n ownerUserId: userId,\n helperPath,\n config: { ...lease, helper, ownerUserId: userId, revision: crypto.randomUUID() },\n });\n await waitReady(lease.leaseId, 'enrolled');\n if (configurationFailure != null) throw configurationFailure;\n // Revalidate the root-owned claim immediately before publishing packet grants.\n const claim = await execute({ action: 'claim', configurationToken, refresh: true });\n if (claim.busy === true) throw new Error('Workspace configuration claim was superseded');\n const active = await client.egress.activate({ caller, leaseId: lease.leaseId });\n validateApprovedDevices(active, deviceIds);\n if (active.leaseId !== lease.leaseId)\n throw new Error('Egress activation returned a different lease');\n if (active.workspaceId !== options.workspaceId)\n throw new Error('Egress activation belongs to a different workspace');\n if (active.state !== 'active')\n throw new Error('Egress activation must return active state');\n validateActiveLease(active, now());\n await execute({ action: 'renew', lease: active });\n const result = await waitReady(lease.leaseId, 'device');\n repairProviderPolicy = false;\n current = active;\n recovered = true;\n nextRenewAttempt = 0;\n nextRecoveryAttempt = 0;\n outcome.result = result;\n } catch (cause) {\n outcome.failures.push(cause);\n try {\n await release({ userId, leaseId, nextOwner: userId });\n } catch (cleanup) {\n outcome.failures.push(cleanup);\n }\n }\n try {\n if (bytes != null) await options.sandbox.removePath({ path: helperPath, force: true });\n } catch (cleanup) {\n outcome.failures.push(cleanup);\n }\n if (outcome.failures.length > 0 && outcome.result != null) {\n try {\n await release({ userId, leaseId, nextOwner: userId });\n } catch (cleanup) {\n outcome.failures.push(cleanup);\n }\n }\n if (outcome.failures.length > 0)\n throw new AggregateError(outcome.failures, 'Egress configuration or cleanup failed');\n if (outcome.result == null) throw new Error('Egress configuration did not return a status');\n return outcome.result;\n } catch (cause) {\n try {\n if (options.afterBlock == null && directPolicy != null) {\n let ownsClaim = false;\n try {\n const claim = await execute({ action: 'claim', configurationToken, refresh: true });\n ownsClaim = claim.busy !== true;\n } catch (claim) {\n reportFailure('outer-policy-claim', claim);\n }\n if (ownsClaim && (await execute({ action: 'status' })).mode === 'blocked')\n await restoreNetwork(directPolicy);\n }\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n 'Egress configuration and outer policy restoration failed',\n );\n }\n throw cause;\n }\n };\n\n const verifyConfigurationClaim = async () => {\n const claim = await execute({\n action: 'claim',\n configurationToken,\n refresh: true,\n verifyOnly: true,\n });\n if (claim.busy === true) throw new Error('Workspace configuration claim was superseded');\n };\n\n const withConfigurationClaim = async <T>(\n work: () => Promise<T>,\n cleanup?: () => Promise<void>,\n waitForClaim = true,\n ): Promise<T> => {\n if (pendingUnlock != null) {\n await execute({ action: 'unlock', configurationToken: pendingUnlock });\n pendingUnlock = null;\n }\n const token = crypto.randomUUID();\n const deadline = performance.now() + 180_000;\n for (;;) {\n let claim: Awaited<ReturnType<typeof execute>>;\n try {\n claim = await execute({ action: 'claim', configurationToken: token });\n } catch (cause) {\n // The guest may have recorded this token before its response was lost.\n pendingUnlock = token;\n recovered = false;\n throw cause;\n }\n if (claim.busy !== true) break;\n if (!waitForClaim)\n throw Object.assign(new Error('Another binding owns workspace configuration'), {\n code: 'conflict',\n });\n if (performance.now() >= deadline)\n throw new Error('Another binding is configuring workspace egress; retry later');\n await sleep(200);\n }\n configurationToken = token;\n let refreshing = true;\n let refreshTimer: ReturnType<typeof setTimeout> | null = null;\n let refresh: Promise<void> = Promise.resolve();\n const scheduleRefresh = () => {\n refreshTimer = setTimeout(() => {\n refresh = execute({ action: 'claim', configurationToken: token, refresh: true })\n .then((claim) => {\n if (claim.busy === true)\n throw new Error('Workspace configuration claim was superseded');\n })\n .catch((cause) => {\n configurationFailure = cause;\n reportFailure('configuration-claim', cause);\n });\n void refresh.then(() => {\n if (refreshing && configurationFailure == null) scheduleRefresh();\n });\n }, 60_000);\n if (typeof refreshTimer === 'object' && 'unref' in refreshTimer) refreshTimer.unref();\n };\n scheduleRefresh();\n let result: { value: T } | null = null;\n const failures: unknown[] = [];\n try {\n result = { value: await work() };\n } catch (cause) {\n failures.push(cause);\n }\n refreshing = false;\n if (refreshTimer != null) clearTimeout(refreshTimer);\n await refresh;\n if (configurationFailure != null && !failures.includes(configurationFailure))\n failures.push(configurationFailure);\n let cleaned = false;\n const clean = async () => {\n if (cleanup == null || cleaned) return;\n cleaned = true;\n try {\n await cleanup();\n } catch (cause) {\n failures.push(cause);\n reportFailure('configuration-cleanup', cause);\n }\n };\n if (failures.length > 0) await clean();\n try {\n await execute({ action: 'unlock', configurationToken: token });\n } catch (cause) {\n pendingUnlock = token;\n recovered = false;\n if (failures.length === 0) failures.push(cause);\n else reportFailure('unlock', cause);\n if (!cleaned && cleanup != null) {\n try {\n const claim = await execute({\n action: 'claim',\n configurationToken: token,\n refresh: true,\n });\n if (claim.busy === true) throw new Error('Workspace configuration claim was superseded');\n await clean();\n } catch (cleanupClaim) {\n failures.push(cleanupClaim);\n reportFailure('configuration-cleanup', cleanupClaim);\n }\n }\n }\n configurationToken = null;\n configurationFailure = null;\n if (repairProviderPolicy) {\n repairProviderPolicy = false;\n try {\n if (options.namespaceExists == null || (await options.namespaceExists()) !== false)\n await withConfigurationClaim(\n async () => {\n const latest = await execute({ action: 'status' });\n if (latest.leaseId != null) return;\n if (latest.choicePending === true || latest.mode !== 'direct') {\n if (options.afterBlock != null) await options.afterBlock();\n else await restoreNetwork({ mode: WorkspaceNetworkPolicy.DenyAll, allow: [] });\n await execute({ action: 'claim', configurationToken, refresh: true });\n return;\n }\n // Repair a late provider write against current state, never the superseded actor's policy.\n await block(latest.ownerUserId ?? null, true);\n const state = await client.egress.networkState({\n organizationId: options.organizationId,\n workspaceId: options.workspaceId,\n });\n if (state.enabled || state.networkPolicy == null)\n throw new Error(\n 'Current direct-access policy is unavailable; networking remains blocked',\n );\n await restoreNetwork(state.networkPolicy);\n await execute({ action: 'claim', configurationToken, refresh: true });\n await execute({ action: 'disable', ownerUserId: null });\n await waitReady(null, 'direct');\n },\n undefined,\n false,\n );\n } catch (cause) {\n if (!z.object({ code: z.literal('conflict') }).safeParse(cause).success)\n failures.push(cause);\n reportFailure('provider-policy-repair', cause);\n }\n }\n if (failures.length > 1)\n throw new AggregateError(\n failures,\n failures\n .map((failure) => (failure instanceof Error ? failure.message : String(failure)))\n .join('; '),\n { cause: failures[0] },\n );\n if (failures.length > 0) throw failures[0];\n if (result == null) throw new Error('Workspace egress configuration returned no result');\n return result.value;\n };\n\n const configure = (userId: string, deviceIds: string[], dnsResolvers?: string[]) =>\n withConfigurationClaim(\n () => configureAttempt(userId, deviceIds, dnsResolvers),\n async () => {\n if (\n current != null &&\n createdLease?.leaseId === current.leaseId &&\n createdLease.userId === userId\n )\n await release({ userId, leaseId: current.leaseId, nextOwner: userId });\n },\n );\n\n const recoverAttempt = async (userId: string | null, background: boolean) => {\n const local = await execute({ action: 'status' });\n if (local.ownerUserId != null && local.ownerUserId !== userId) {\n if (background) {\n requiresChoice = true;\n current = null;\n return;\n }\n await options.authorizeOwnerChange?.(userId);\n }\n if (local.mode === 'error' && local.ownerUserId !== userId) {\n requiresChoice = true;\n if (options.allowOwnerChange !== false) {\n await options.afterBlock?.();\n await restoreNetwork({ mode: WorkspaceNetworkPolicy.DenyAll, allow: [] });\n }\n throw new Error(\n 'Workspace egress enforcement is in error; explicitly configure or disable to repair',\n );\n }\n // Recovery holds the same namespace claim as explicit configuration and disable.\n // An actor change cannot inherit another person's exit, including after host restart.\n if (\n (local.ownerUserId != null && local.ownerUserId !== userId) ||\n (background && local.mode === 'blocked' && local.ownerUserId === null && userId != null)\n ) {\n if (options.allowOwnerChange === false)\n throw new Error(\n 'Workspace egress belongs to another actor; this binding requires its owner',\n );\n if (background) {\n requiresChoice = true;\n current = null;\n return;\n }\n await authorizeRouteMutation(userId, local);\n requiresChoice = true;\n await release({ userId, leaseId: local.leaseId, nextOwner: userId, suspendWorkspace: true });\n throw new Error(\n 'Workspace egress owner changed; explicitly configure or disable egress before running tools',\n );\n }\n const choicePending = local.choicePending ?? local.mode === 'blocked';\n if (userId == null) {\n const state = await client.egress.networkState({\n organizationId: options.organizationId,\n workspaceId: options.workspaceId,\n });\n if (state.enabled) {\n requiresChoice = true;\n await block(null);\n throw new Error(\n 'This workspace has Device egress configured; an acting user must choose its network policy',\n );\n }\n if (choicePending) {\n requiresChoice = true;\n await block(null);\n throw new Error('Workspace networking is blocked; explicitly configure or disable egress');\n }\n let policy = state.networkPolicy;\n if (policy == null) {\n if (options.initialNetworkPolicy == null) {\n requiresChoice = true;\n await block(null);\n throw new Error(\n 'The host must supply the current network policy before opting in a workspace',\n );\n }\n const initial = workspaceNetworkPolicySchema.parse(options.initialNetworkPolicy);\n await client.egress.setNetworkPolicy({\n caller: callerFor(null),\n workspaceId: options.workspaceId,\n policy: initial,\n initializeIfMissing: true,\n });\n policy = (\n await client.egress.networkState({\n organizationId: options.organizationId,\n workspaceId: options.workspaceId,\n })\n ).networkPolicy;\n }\n if (policy != null) {\n directPolicy = workspaceNetworkPolicySchema.parse(policy);\n directPolicyKnown = true;\n }\n await restoreNetwork(policy);\n if (local.mode !== 'direct' || local.restorePending === true) {\n await execute({ action: 'disable', ownerUserId: null });\n await waitReady(null, 'direct');\n }\n requiresChoice = false;\n return;\n }\n const desired = await profileFor(userId);\n if (desired.lockedByOtherOwner) {\n if (options.allowOwnerChange === false)\n throw new Error(\n 'Workspace egress belongs to another actor; this binding requires its owner',\n );\n requiresChoice = true;\n if (background) {\n current = null;\n return;\n }\n await block(userId);\n throw new Error(\n 'Workspace egress belongs to a different actor; configure or explicitly disable it before running tools',\n );\n }\n if (!desired.enabled) {\n if (choicePending) {\n requiresChoice = true;\n await block(userId);\n throw new Error('Workspace networking is blocked; explicitly configure or disable egress');\n }\n await restoreNetwork(desired.networkPolicy);\n if (local.mode !== 'direct' || local.restorePending === true) {\n await execute({ action: 'disable', ownerUserId: userId });\n await waitReady(null, 'direct');\n }\n current = null;\n return;\n }\n if (\n desired.lease != null &&\n (['device', 'reconnecting'].includes(local.mode) ||\n (['blocked', 'configuring'].includes(local.mode) && local.controllerAlive === true)) &&\n local.leaseId === desired.lease.leaseId\n ) {\n try {\n if (desired.lease.workspaceId !== options.workspaceId)\n throw new Error('Egress recovery belongs to a different workspace');\n validateApprovedDevices(desired.lease, desired.deviceIds);\n validateActiveLease(desired.lease, now());\n } catch (cause) {\n requiresChoice = true;\n if (options.allowOwnerChange !== false)\n await release({ userId, leaseId: desired.lease.leaseId, nextOwner: userId });\n throw cause;\n }\n current = desired.lease;\n await restoreNetwork({ mode: WorkspaceNetworkPolicy.AllowAll, allow: [] });\n if (local.mode === 'configuring' || local.expiresAtMs !== desired.lease.expiresAtMs) {\n await execute({ action: 'renew', lease: desired.lease });\n await waitReady(desired.lease.leaseId, 'device');\n }\n return;\n }\n if (options.allowOwnerChange === false)\n throw new Error(\n 'Workspace networking needs recovery by an active workspace binding before external access',\n );\n if (performance.now() < nextRecoveryAttempt)\n throw new Error(\n 'Workspace egress recovery is cooling down; retry later or explicitly configure',\n );\n nextRecoveryAttempt = performance.now() + 60_000;\n await configureAttempt(userId, desired.deviceIds, desired.dnsResolvers);\n nextRecoveryAttempt = 0;\n };\n const recover = async (userId: string | null, background: boolean) => {\n if (performance.now() < nextRecoveryProbeAt)\n throw new Error(\n 'Workspace egress recovery is cooling down; retry shortly or explicitly configure',\n );\n recovered = false;\n try {\n await withConfigurationClaim(\n () => recoverAttempt(userId, background),\n async () => {\n if (\n current != null &&\n createdLease?.leaseId === current.leaseId &&\n createdLease.userId === userId\n )\n await release({ userId, leaseId: current.leaseId, nextOwner: userId });\n },\n );\n recovered = true;\n nextRecoveryProbeAt = 0;\n } catch (cause) {\n if (cause instanceof Error && isPermanentAuthorizationFailure(cause)) {\n requiresChoice = true;\n try {\n if (options.allowOwnerChange !== false) await block(userId);\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n 'Egress recovery rejected and local denial failed',\n );\n }\n }\n if (!initializing && !requiresChoice) nextRecoveryProbeAt = performance.now() + 5_000;\n throw cause;\n }\n };\n const stableStatus = async (userId: string | null) => {\n const deadline = performance.now() + 180_000;\n for (;;) {\n const local = await statusForGuard(userId);\n if (local.configuring !== true) return local;\n if (performance.now() >= deadline)\n throw new Error('Another binding is configuring workspace egress; retry later');\n cachedStatus = null;\n await sleep(200);\n }\n };\n const maintain = async (background = false) => {\n if (closed) throw new Error('Workspace egress manager is closed');\n if (background && (requiresChoice || (recovered && current == null))) return;\n if (requiresChoice) {\n const actor = await options.actingUser.current();\n const local = await execute({ action: 'status' });\n const repaired =\n local.configuring !== true &&\n ((local.mode === 'direct' &&\n local.choicePending === false &&\n local.restorePending !== true &&\n local.ownerUserId == null) ||\n (local.mode === 'device' &&\n local.ownerUserId === actor &&\n local.expiresAtMs != null &&\n local.expiresAtMs > now()));\n if (!repaired)\n throw new Error('Explicitly configure or disable workspace egress before running tools');\n // Another authorized binding repaired the namespace; revalidate its saved route.\n requiresChoice = false;\n current = null;\n owner = undefined;\n recovered = false;\n cachedStatus = null;\n nextRecoveryProbeAt = 0;\n }\n if (background && owner === undefined) return;\n const userId = background ? (owner ?? null) : await options.actingUser.current();\n if (owner !== userId) {\n if (options.allowOwnerChange === false && owner !== undefined && current != null)\n throw new Error(\n 'Workspace egress belongs to another actor; this binding requires its owner',\n );\n if (owner !== undefined && current != null) {\n await authorizeRouteMutation(userId, await execute({ action: 'status' }));\n requiresChoice = true;\n const leaseId = current.leaseId;\n owner = userId;\n await release({ userId, leaseId, nextOwner: userId, suspendWorkspace: true });\n throw new Error(\n 'Workspace egress owner changed; configure or disable egress before running tools',\n );\n }\n // Recovery failures belong to the actor that attempted them.\n nextRecoveryProbeAt = 0;\n nextRecoveryAttempt = 0;\n // Retain the last foreground identity even when recovery fails transiently.\n owner = userId;\n await recover(userId, background);\n }\n if (!recovered) {\n await recover(userId, background);\n }\n if (background && requiresChoice) return;\n if (current != null && current.expiresAtMs <= now()) {\n await recover(userId, background);\n }\n const local = await stableStatus(userId);\n if (local.mode === 'blocked' && local.ownerUserId == null && local.leaseId == null) {\n requiresChoice = true;\n if (background) return;\n throw new Error(\n 'Workspace networking is blocked; explicitly configure or disable egress before running tools',\n );\n }\n if (local.mode === 'error' && local.ownerUserId !== userId) {\n requiresChoice = true;\n if (options.allowOwnerChange !== false) {\n await options.afterBlock?.();\n await restoreNetwork({ mode: WorkspaceNetworkPolicy.DenyAll, allow: [] });\n }\n throw new Error(\n 'Workspace egress enforcement is in error; explicitly configure or disable to repair',\n );\n }\n if (\n (local.ownerUserId != null && local.ownerUserId !== userId) ||\n (background && local.mode === 'blocked' && local.ownerUserId === null && userId != null)\n ) {\n if (options.allowOwnerChange === false)\n throw new Error(\n 'Workspace egress belongs to another actor; this binding requires its owner',\n );\n if (background) {\n requiresChoice = true;\n current = null;\n return;\n }\n await authorizeRouteMutation(userId, local);\n requiresChoice = true;\n await release({ userId, leaseId: local.leaseId, nextOwner: userId, suspendWorkspace: true });\n throw new Error(\n 'Workspace egress owner changed; configure or disable egress before running tools',\n );\n }\n if (\n (current != null && local.leaseId !== current.leaseId) ||\n (current == null && local.leaseId != null)\n ) {\n current = null;\n await recover(userId, background);\n return;\n }\n if (\n (local.mode === 'error' || (local.mode === 'blocked' && local.controllerAlive !== true)) &&\n local.ownerUserId === userId\n ) {\n // A live controller waits through Device outages; a dead controller needs recovery.\n current = null;\n await recover(userId, background);\n return;\n }\n if (\n current != null &&\n userId != null &&\n performance.now() >= nextRenewAttempt &&\n (current.expiresAtMs - now() < 10 * 60_000 ||\n ['blocked', 'reconnecting'].includes(local.mode))\n ) {\n try {\n const lease = await client.egress.renew({\n caller: callerFor(userId),\n leaseId: current.leaseId,\n });\n validateActiveLease(lease, now());\n validateApprovedDevices(\n lease,\n current.devices.map((device) => device.deviceId),\n );\n if (lease.leaseId !== current.leaseId)\n throw Object.assign(new Error('Egress renewal returned a different lease'), {\n invalidEgressLease: true,\n code: 'configuration',\n });\n if (lease.workspaceId !== options.workspaceId)\n throw Object.assign(new Error('Egress renewal belongs to a different workspace'), {\n invalidEgressLease: true,\n code: 'configuration',\n });\n await execute({ action: 'renew', lease });\n current = lease;\n nextRenewAttempt = performance.now() + 30_000;\n } catch (cause) {\n const status = cause instanceof Error ? deviceApiStatusOf(cause) : null;\n reportFailure('renew', cause);\n if (z.object({ invalidEgressLease: z.literal(true) }).safeParse(cause).success) {\n requiresChoice = true;\n const leaseId = current.leaseId;\n try {\n await release({ userId, leaseId, nextOwner: userId });\n } catch (cleanup) {\n throw new AggregateError([cause, cleanup], 'Invalid egress lease and cleanup failed');\n }\n throw cause;\n }\n if (deviceApiCodeOf(cause) === DeviceApiClientErrorCode.EgressEnrollmentLost) {\n const leaseId = current.leaseId;\n recovered = false;\n try {\n await release({ userId, leaseId, nextOwner: userId });\n } catch (cleanup) {\n throw new AggregateError([cause, cleanup], 'Egress renewal and cleanup failed');\n }\n current = null;\n nextRecoveryProbeAt = performance.now() + 5_000;\n throw cause;\n }\n if (status === 401 || status === 403 || status === 404 || status === 410) {\n if (status === 404) {\n const profile = await profileFor(userId).catch((lookup) => {\n nextRenewAttempt = performance.now() + 30_000;\n reportFailure('renew-profile', lookup);\n throw new AggregateError([cause, lookup], 'Egress renewal and profile lookup failed');\n });\n if (\n !profile.lockedByOtherOwner &&\n profile.configured === true &&\n !profile.enabled &&\n profile.networkPolicy != null\n ) {\n const latest = await execute({ action: 'status' });\n if (\n latest.mode === 'direct' &&\n latest.choicePending !== true &&\n latest.ownerUserId === userId\n ) {\n current = null;\n createdLease = null;\n recovered = false;\n requiresChoice = false;\n await recover(userId, background);\n return;\n }\n }\n if (\n !profile.lockedByOtherOwner &&\n profile.enabled &&\n profile.lease != null &&\n profile.lease.leaseId !== current.leaseId\n ) {\n current = null;\n recovered = false;\n await recover(userId, background);\n return;\n }\n }\n requiresChoice = true;\n try {\n await release({ userId, leaseId: current.leaseId, nextOwner: userId });\n } catch (cleanup) {\n throw new AggregateError([cause, cleanup], 'Egress renewal and cleanup failed');\n }\n throw cause;\n }\n nextRenewAttempt = performance.now() + 30_000;\n if (\n current.expiresAtMs > now() &&\n local.leaseId === current.leaseId &&\n (['device', 'reconnecting'].includes(local.mode) || local.controllerAlive === true)\n )\n return;\n throw cause;\n }\n }\n };\n const schedule = () => {\n if (closed) return;\n timer = setTimeout(() => {\n void serialized(() => maintain(true))\n .catch((cause) => reportFailure('maintenance', cause))\n .finally(schedule);\n }, 60_000);\n if (typeof timer === 'object' && 'unref' in timer) timer.unref();\n };\n const close = (stopWorkspace = false, onlyCurrent = false): Promise<void> =>\n serialized(async () => {\n if (stopped || (closed && !stopWorkspace)) return;\n if (onlyCurrent && (current == null || current.leaseId !== createdLease?.leaseId)) {\n closed = true;\n if (timer != null) clearTimeout(timer);\n timer = null;\n const created = createdLease;\n const results = await Promise.allSettled([\n (async () => {\n if (created == null) return;\n await revokeLease({\n caller: callerFor(created.userId),\n leaseId: created.leaseId,\n workspaceId: options.workspaceId,\n });\n createdLease = null;\n })(),\n (async () => {\n if (pendingUnlock == null) return;\n await execute({ action: 'unlock', configurationToken: pendingUnlock });\n pendingUnlock = null;\n })(),\n ]);\n notifyClosed();\n const failures = results.flatMap((result) =>\n result.status === 'rejected' ? [result.reason] : [],\n );\n if (failures.length > 0) throw new AggregateError(failures, 'Owned egress cleanup failed');\n return;\n }\n closed = true;\n if (timer != null) clearTimeout(timer);\n if (!stopWorkspace) {\n try {\n if (pendingUnlock != null) {\n await execute({ action: 'unlock', configurationToken: pendingUnlock });\n pendingUnlock = null;\n }\n } finally {\n notifyClosed();\n }\n return;\n }\n timer = null;\n try {\n const failures: unknown[] = [];\n let userId: string | null = onlyCurrent ? (createdLease?.userId ?? owner ?? null) : null;\n if (!onlyCurrent) {\n try {\n userId = await options.actingUser.current();\n } catch (cause) {\n failures.push(cause);\n }\n }\n let leaseId = current?.leaseId ?? null;\n let needsBlock = current != null || requiresChoice;\n let namespaceExists = true;\n try {\n namespaceExists = (await options.namespaceExists?.()) ?? true;\n } catch (cause) {\n failures.push(cause);\n }\n if (!namespaceExists) {\n try {\n if (!onlyCurrent)\n await client.egress.suspend({\n caller: callerFor(userId),\n workspaceId: options.workspaceId,\n });\n else if (userId != null && leaseId != null)\n await revokeLease({\n caller: callerFor(userId),\n leaseId,\n workspaceId: options.workspaceId,\n });\n } catch (cause) {\n failures.push(cause);\n }\n if (failures.length > 0)\n throw new AggregateError(failures, 'Workspace egress close or revocation failed');\n stopped = true;\n return;\n }\n if (pendingUnlock != null) {\n try {\n await execute({ action: 'unlock', configurationToken: pendingUnlock });\n pendingUnlock = null;\n } catch (cause) {\n failures.push(cause);\n }\n }\n if (!onlyCurrent && leaseId == null && userId != null) {\n try {\n leaseId =\n (\n await client.egress.workspace({\n caller: callerFor(userId),\n workspaceId: options.workspaceId,\n })\n ).lease?.leaseId ?? null;\n } catch (cause) {\n failures.push(cause);\n }\n }\n if (leaseId == null) {\n try {\n needsBlock ||= (await execute({ action: 'status' })).mode !== 'direct';\n } catch (cause) {\n failures.push(cause);\n needsBlock = true;\n }\n }\n if (leaseId != null || needsBlock) {\n try {\n await release({ userId, leaseId, nextOwner: userId, suspendWorkspace: !onlyCurrent });\n } catch (cause) {\n failures.push(cause);\n }\n } else if (!onlyCurrent) {\n try {\n await client.egress.suspend({\n caller: callerFor(userId),\n workspaceId: options.workspaceId,\n });\n } catch (cause) {\n failures.push(cause);\n }\n }\n if (failures.length > 0)\n throw new AggregateError(failures, 'Workspace egress close or revocation failed');\n stopped = true;\n } finally {\n notifyClosed();\n }\n });\n\n return {\n initialize: () =>\n serialized(async () => {\n initializing = true;\n try {\n await maintain();\n } catch (cause) {\n reportFailure('initialize', cause);\n /* Management remains available while execution is blocked. */\n } finally {\n initializing = false;\n }\n if (timer == null) schedule();\n }),\n guard: (args?: { background?: boolean }) =>\n serialized(async () => {\n await maintain(args?.background ?? false);\n if (requiresChoice)\n throw new Error('Explicitly configure or disable workspace egress before running tools');\n }),\n setNetworkPolicy: (\n policy: NetworkPolicyIface,\n apply: (policy: NetworkPolicyIface) => Promise<void>,\n ) =>\n serialized(async () => {\n if (closed) throw new Error('Workspace egress manager is closed');\n nextRecoveryProbeAt = 0;\n const userId = await options.actingUser.current();\n await withConfigurationClaim(async () => {\n const local = await execute({ action: 'status' });\n const deviceChoicePending = local.choicePending ?? local.mode === 'blocked';\n const validated = workspaceNetworkPolicySchema.parse(policy);\n const state = await client.egress.networkState({\n organizationId: options.organizationId,\n workspaceId: options.workspaceId,\n });\n if (current != null || state.enabled || deviceChoicePending)\n throw new Error(\n 'Disable Device egress before changing the saved direct-access network policy',\n );\n if (requiresChoice)\n await execute({ action: 'block', ownerUserId: userId, restoreDirect: true });\n try {\n await client.egress.setNetworkPolicy({\n caller: callerFor(userId),\n workspaceId: options.workspaceId,\n policy: validated,\n });\n directPolicy = validated;\n directPolicyKnown = true;\n await apply(validated);\n await reportLogicalPolicy();\n await execute({ action: 'disable', ownerUserId: userId });\n await waitReady(null, 'direct');\n requiresChoice = false;\n recovered = true;\n owner = userId;\n } catch (cause) {\n requiresChoice = true;\n try {\n await release({ userId, leaseId: null, nextOwner: userId, restoreDirect: true });\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n 'Network policy update and egress cleanup failed',\n );\n }\n throw cause;\n }\n });\n }),\n egress: (request: WorkspaceEgressRequestIface): Promise<WorkspaceEgressStatusIface> =>\n serialized(async () => {\n if (closed) throw new Error('Workspace egress manager is closed');\n const parsed = workspaceEgressRequestSchema.parse(request);\n const userId = await options.actingUser.current();\n if (parsed.action === WorkspaceEgressAction.Status) {\n const local = await execute({ action: 'status' });\n return workspaceEgressStatusSchema.parse(local);\n }\n if (userId == null) throw new Error('Changing Device egress requires an acting user');\n if (parsed.action === WorkspaceEgressAction.Configure) {\n if (options.allowConfiguration === false)\n throw new Error(\n 'New workspace egress configuration is disabled; existing settings can be inspected or disabled',\n );\n if (parsed.deviceIds == null) throw new Error('Configure requires Device IDs');\n await authorizeRouteMutation(userId, await execute({ action: 'status' }));\n owner = userId;\n requiresChoice = false;\n nextRecoveryAttempt = 0;\n nextRecoveryProbeAt = 0;\n try {\n return workspaceEgressStatusSchema.parse(\n await configure(userId, parsed.deviceIds, parsed.dnsResolvers),\n );\n } catch (cause) {\n requiresChoice = true;\n reportFailure('configure', cause);\n throw cause;\n }\n }\n await authorizeRouteMutation(userId, await execute({ action: 'status' }));\n owner = userId;\n requiresChoice = false;\n nextRecoveryAttempt = 0;\n nextRecoveryProbeAt = 0;\n try {\n return await withConfigurationClaim(async () => {\n const local = await execute({ action: 'status' });\n await authorizeRouteMutation(userId, local);\n await verifyConfigurationClaim();\n if (local.mode !== 'direct') {\n try {\n await block(userId);\n } catch (cause) {\n // The controller can confirm emergency denial even when the full guard fails.\n await verifyConfigurationClaim();\n const denied = await execute({ action: 'status' });\n if (\n (denied.mode !== 'blocked' &&\n !(denied.mode === 'error' && denied.networkPristine === true)) ||\n denied.ownerUserId !== userId\n )\n throw cause;\n }\n }\n await verifyConfigurationClaim();\n await client.egress.disable({\n caller: callerFor(userId),\n workspaceId: options.workspaceId,\n });\n createdLease = null;\n const profile = await client.egress.workspace({\n caller: callerFor(userId),\n workspaceId: options.workspaceId,\n });\n await verifyConfigurationClaim();\n repairProviderPolicy = true;\n if (profile.networkPolicy != null) {\n directPolicy = workspaceNetworkPolicySchema.parse(profile.networkPolicy);\n directPolicyKnown = true;\n }\n await restoreNetwork(profile.networkPolicy);\n await verifyConfigurationClaim();\n repairProviderPolicy = false;\n await execute({ action: 'disable', ownerUserId: userId });\n const result = workspaceEgressStatusSchema.parse(await waitReady(null, 'direct'));\n current = null;\n recovered = true;\n return result;\n });\n } catch (cause) {\n requiresChoice = true;\n throw cause;\n }\n }),\n close: (stopWorkspace = false) => close(stopWorkspace),\n closeOnFailure: () => close(true, true),\n };\n};\n\n// Persist the provider's policy before any boot fence, including passive first attachments.\nexport const preserveWorkspaceNetworkPolicy = async (options: {\n api: DeviceApiConfigIface | (() => DeviceApiConfigIface);\n organizationId: string;\n workspaceId: string;\n policy: NetworkPolicyIface;\n client?: Pick<DeviceApiClientIface, 'egress'>;\n}): Promise<void> => {\n deviceEgressWorkspaceIdSchema.parse(options.workspaceId);\n const api = typeof options.api === 'function' ? options.api() : options.api;\n await (options.client ?? createDeviceApiClient({ api })).egress.setNetworkPolicy({\n caller: { organizationId: options.organizationId, actingUser: { current: async () => null } },\n workspaceId: options.workspaceId,\n policy: options.policy,\n initializeIfMissing: true,\n });\n};\n\nexport type WorkspaceEgressManagerIface = ReturnType<typeof createWorkspaceEgressManager>;\n\nconst workspaceEgressController = (\n manager: WorkspaceEgressManagerIface,\n): SandboxNetworkingControllerIface => ({\n initialize: manager.initialize,\n guard: async (context) => {\n // The policy operation authorizes and repairs networking without requiring a usable tunnel.\n if (\n context == null ||\n ![SandboxExecutionOperation.SetNetworkPolicy, SandboxExecutionOperation.Egress].includes(\n context.operation,\n )\n )\n await manager.guard(context);\n },\n close: manager.close,\n closeOnFailure: manager.closeOnFailure,\n extendSandbox: (sandbox) => {\n const overrides: Partial<NetworkSandboxSessionIface> = { egress: manager.egress };\n if (sandbox.screen != null) {\n const screen = sandbox.screen.bind(sandbox);\n overrides.screen = async (args) => {\n if (args?.viewOnly === false)\n throw new Error(\n 'Managed workspace screen grants are view-only; use the guarded computer-use channel for input',\n );\n return screen({ ...args, viewOnly: true });\n };\n }\n if (sandbox.setNetworkPolicy != null) {\n const apply = sandbox.setNetworkPolicy.bind(sandbox);\n overrides.setNetworkPolicy = (policy) => manager.setNetworkPolicy(policy, apply);\n }\n return withSandboxOverrides(sandbox, overrides);\n },\n authorizeExternalAccess: async () => {\n await manager.guard();\n const status = await manager.egress({ action: WorkspaceEgressAction.Status });\n return { expiresAtMs: status.expiresAtMs == null ? null : status.expiresAtMs - 90_000 };\n },\n});\n\nexport interface WorkspaceDeviceNetworkingOptionsIface {\n api: WorkspaceEgressManagerOptionsIface['api'];\n mcpFetch?: typeof globalThis.fetch;\n needed: (args: {\n organizationId: string;\n workspaceId: string;\n teardown?: boolean;\n access?: SandboxAccess;\n }) => Promise<boolean>;\n allowConfiguration?: boolean;\n authorizeOwnerChange?: (args: {\n organizationId: string;\n workspaceId: string;\n actingUserId: string | null;\n }) => Promise<void>;\n}\n\n// Final Device is one opinionated implementation of the public networking extension contract.\nexport const createWorkspaceDeviceNetworking = (\n options: WorkspaceDeviceNetworkingOptionsIface,\n): SandboxNetworkingExtensionIface => ({\n capabilities: [SandboxCapability.Egress],\n fetch: options.mcpFetch,\n validateWorkspaceId: (workspaceId) => {\n deviceEgressWorkspaceIdSchema.parse(workspaceId);\n },\n enabled: ({ ctx, workspaceId, teardown, access }) =>\n options.needed({ organizationId: ctx.organizationId, workspaceId, teardown, access }),\n prepare: async ({ ctx, workspaceId, policy }) => {\n const client = createDeviceApiClient({ api: options.api });\n await preserveWorkspaceNetworkPolicy({\n client,\n api: options.api,\n organizationId: ctx.organizationId,\n workspaceId,\n policy,\n });\n try {\n const saved = await client.egress.networkState({\n organizationId: ctx.organizationId,\n workspaceId,\n });\n return workspaceNetworkPolicySchema.parse(saved.networkPolicy);\n } catch {\n // The initialized ledger remains authoritative; admission restores reporting after recovery.\n return { mode: WorkspaceNetworkPolicy.DenyAll, allow: [] };\n }\n },\n suspend: ({ ctx, workspaceId }) =>\n suspendWorkspaceEgress({\n api: options.api,\n organizationId: ctx.organizationId,\n workspaceId,\n actingUser: ctx.actingUser,\n }),\n controller: (args) =>\n workspaceEgressController(\n createWorkspaceEgressManager({\n sandbox: args.sandbox,\n workspaceId: args.workspaceId,\n organizationId: args.ctx.organizationId,\n actingUser: args.ctx.actingUser,\n api: options.api,\n initialNetworkPolicy: args.initialNetworkPolicy,\n onNetworkPolicy: args.ctx.platformNetworkPolicy,\n privilegedRun: args.privilegedRun,\n afterGuard: args.afterGuard,\n afterBlock: args.afterBlock,\n namespaceExists: args.namespaceExists,\n onClose: args.onClose,\n allowConfiguration:\n args.access === SandboxAccess.Write && options.allowConfiguration !== false,\n allowOwnerChange: args.allowOwnerChange ?? args.access === SandboxAccess.Write,\n authorizeOwnerChange: (actingUserId) =>\n options.authorizeOwnerChange?.({\n organizationId: args.ctx.organizationId,\n workspaceId: args.workspaceId,\n actingUserId,\n }) ?? Promise.resolve(),\n onFailure: (event) => args.log?.('workspace_egress.control_failure', { ...event }),\n }),\n ),\n});\n\nexport const withWorkspaceEgress = <S extends NetworkSandboxSessionIface>(options: {\n handle: SandboxProviderHandleIface<S>;\n manager: WorkspaceEgressManagerIface;\n access: SandboxAccess;\n beforeUse?: () => Promise<void>;\n initialized?: boolean;\n fetch?: typeof globalThis.fetch;\n}): Promise<SandboxProviderHandleIface<S>> =>\n withSandboxNetworking({\n ...options,\n controller: workspaceEgressController(options.manager),\n });\n\nexport const withWorkspaceAdmission = <S extends NetworkSandboxSessionIface>(options: {\n handle: SandboxProviderHandleIface<S>;\n access: SandboxAccess;\n admission: () => Promise<void>;\n fetch?: typeof globalThis.fetch;\n}): Promise<SandboxProviderHandleIface<S>> => withSandboxNetworking(options);\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import * as z from 'zod';\nimport {\n WorkspaceEgressAction,\n workspaceEgressRequestSchema,\n deviceEgressWorkspaceIdSchema,\n workspaceEgressStatusSchema,\n type WorkspaceEgressRequestIface,\n type WorkspaceEgressStatusIface,\n type DeviceEgressLeaseIface,\n WorkspaceNetworkPolicy,\n workspaceNetworkPolicySchema,\n} from '@finalai/agent-protocol/device-egress';\nimport { SandboxAccess, type JsonValue } from '@finalai/agent-provider';\nimport {\n SandboxCapability,\n SandboxExecutionOperation,\n withSandboxNetworking,\n withSandboxOverrides,\n type SandboxNetworkingControllerIface,\n type SandboxNetworkingExtensionIface,\n} from '@finalai/agent-provider/sandbox';\nimport type {\n NetworkSandboxSessionIface,\n SandboxActingUserIface,\n SandboxRunResultIface,\n SandboxProviderHandleIface,\n NetworkPolicyIface,\n} from '@finalai/agent-provider/sandbox';\nimport {\n createDeviceApiClient,\n type DeviceApiClientIface,\n type DeviceApiConfigIface,\n deviceApiStatusOf,\n deviceApiCodeOf,\n DeviceApiClientErrorCode,\n} from \"./device-api.mjs\";\nimport {\n workspaceEgressBootstrap,\n cachedWorkspaceEgressBootstrap,\n workspaceEgressLauncher,\n} from \"./egress-bootstrap.mjs\";\nimport { sleep } from \"./bytes.mjs\";\n\nconst localStatusSchema = workspaceEgressStatusSchema.extend({\n architecture: z.string().optional(),\n networkPristine: z.boolean().optional(),\n policyRouting: z.boolean().optional(),\n helperReady: z.boolean().optional(),\n busy: z.boolean().optional(),\n configuring: z.boolean().optional(),\n controllerAlive: z.boolean().optional(),\n restorePending: z.boolean().optional(),\n choicePending: z.boolean().optional(),\n ownerUserId: z.string().nullable().optional(),\n workspaceId: z.string().nullable().optional(),\n});\n\ninterface ConfigurationOutcomeIface {\n result: z.infer<typeof localStatusSchema> | null;\n failures: unknown[];\n}\n\nconst validateApprovedDevices = (lease: DeviceEgressLeaseIface, approved: readonly string[]) => {\n if (\n lease.devices.length !== approved.length ||\n lease.devices.some(\n (device, index) => device.deviceId.toLowerCase() !== approved[index]?.toLowerCase(),\n )\n )\n throw Object.assign(\n new Error('Egress lease Devices do not match the approved ordered Device list'),\n { invalidEgressLease: true, code: 'configuration' },\n );\n};\n\nconst validateActiveLease = (lease: DeviceEgressLeaseIface, at: number) => {\n if (lease.state !== 'active' || !Number.isFinite(lease.expiresAtMs) || lease.expiresAtMs <= at)\n throw Object.assign(new Error('Egress lease is not active or has expired'), {\n invalidEgressLease: true,\n code: 'configuration',\n });\n};\n\nconst isPermanentAuthorizationFailure = (error: Error): boolean => {\n const pending = [error];\n const visited = new Set<Error>();\n while (pending.length > 0 && visited.size < 32) {\n const current = pending.pop();\n if (current == null || visited.has(current)) continue;\n visited.add(current);\n const status = deviceApiStatusOf(current);\n if (status != null && [401, 403, 404, 410].includes(status)) return true;\n if (current.cause instanceof Error) pending.push(current.cause);\n if (current instanceof AggregateError)\n for (const nested of current.errors) if (nested instanceof Error) pending.push(nested);\n }\n return false;\n};\n\nexport interface WorkspaceEgressManagerOptionsIface {\n // Raw, unguarded session; passing withWorkspaceEgress() here recursively deadlocks.\n sandbox: NetworkSandboxSessionIface;\n workspaceId: string;\n organizationId: string;\n actingUser: SandboxActingUserIface;\n api: DeviceApiConfigIface | (() => DeviceApiConfigIface);\n // Must execute in this workspace's isolated network namespace, as root with NET_ADMIN.\n // Run python3 -I -c source source (or a file with __file__); pass JSON on stdin.\n privilegedRun?: (request: { source: string; input: string }) => Promise<SandboxRunResultIface>;\n client?: Pick<DeviceApiClientIface, 'egress'>;\n fetch?: typeof fetch;\n // Restore the provider's outer network policy only after the namespace guard is installed.\n afterGuard?: (policy?: NetworkPolicyIface) => Promise<void>;\n // Optional outer-provider fence after namespace denial; unsupported providers may retain namespace-only denial.\n afterBlock?: () => Promise<void>;\n // Provider-confirmed deletion permits authorization cleanup without entering a missing namespace.\n namespaceExists?: () => Promise<boolean>;\n initialNetworkPolicy?: NetworkPolicyIface;\n onNetworkPolicy?: (policy: NetworkPolicyIface) => Promise<void>;\n allowConfiguration?: boolean;\n allowOwnerChange?: boolean;\n authorizeOwnerChange?: (actingUserId: string | null) => Promise<void>;\n onClose?: () => void;\n now?: () => number;\n onFailure?: (event: {\n operation: string;\n workspaceId: string;\n leaseId: string | null;\n reason: string;\n httpStatus: number | null;\n }) => void;\n}\n\nexport const suspendWorkspaceEgress = async (args: {\n api: DeviceApiConfigIface | (() => DeviceApiConfigIface);\n organizationId: string;\n workspaceId: string;\n actingUser: SandboxActingUserIface;\n}): Promise<void> => {\n await createDeviceApiClient({ api: args.api }).egress.suspend({\n caller: { organizationId: args.organizationId, actingUser: args.actingUser },\n workspaceId: args.workspaceId,\n });\n};\n\n// Host-owned lease renewal; callers tie close() to their provider handle's lifecycle.\nexport const createWorkspaceEgressManager = (options: WorkspaceEgressManagerOptionsIface) => {\n if (!deviceEgressWorkspaceIdSchema.safeParse(options.workspaceId).success)\n throw new Error(\n 'Device egress requires a stable workspaceId of 1\u2013256 characters without control characters',\n );\n const client = options.client ?? createDeviceApiClient({ api: options.api });\n const revokeLease = async (args: Parameters<typeof client.egress.revoke>[0]) => {\n try {\n await client.egress.revoke(args);\n } catch (cause) {\n const status = cause instanceof Error ? deviceApiStatusOf(cause) : null;\n if (status !== 404 && status !== 410) throw cause;\n }\n };\n const now = options.now ?? Date.now;\n const run =\n options.privilegedRun ??\n ((request) =>\n options.sandbox.run({\n command: 'sudo',\n args: ['-n', 'python3', '-I', '-c', workspaceEgressLauncher],\n stdin: JSON.stringify(request),\n timeoutMs: 35_000,\n }));\n let pending: Promise<unknown> = Promise.resolve();\n let owner: string | null | undefined;\n let current: DeviceEgressLeaseIface | null = null;\n let closed = false;\n let stopped = false;\n let recovered = false;\n let createdLease: { leaseId: string; userId: string } | null = null;\n let directPolicy: NetworkPolicyIface | undefined = options.initialNetworkPolicy;\n let directPolicyKnown = false;\n let requiresChoice = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let nextRenewAttempt = 0;\n let nextRecoveryAttempt = 0;\n let nextRecoveryProbeAt = 0;\n let initializing = false;\n let configurationToken: string | null = null;\n let pendingUnlock: string | null = null;\n let repairProviderPolicy = false;\n let configurationFailure: unknown = null;\n let notifiedClosed = false;\n const notifyClosed = () => {\n if (!notifiedClosed) {\n notifiedClosed = true;\n options.onClose?.();\n }\n };\n let cachedStatus: {\n at: number;\n userId: string | null;\n value: z.infer<typeof localStatusSchema>;\n } | null = null;\n const reportFailure = (operation: string, cause: unknown) => {\n const rawCode = z.object({ code: z.string() }).safeParse(cause).data?.code;\n const known = [\n 'credential_missing',\n 'no_acting_user',\n 'unauthorized',\n 'forbidden',\n 'not_found',\n 'unavailable',\n 'invalid',\n 'rate_limited',\n 'prerequisite',\n 'conflict',\n 'configuration',\n 'request_failed',\n 'egress_enrollment_lost',\n ];\n try {\n options.onFailure?.({\n operation,\n workspaceId: options.workspaceId,\n leaseId: current?.leaseId ?? null,\n reason:\n rawCode != null && known.includes(rawCode)\n ? rawCode\n : cause instanceof TypeError\n ? 'transport'\n : 'operation_failed',\n httpStatus: cause instanceof Error ? deviceApiStatusOf(cause) : null,\n });\n } catch {\n // Host telemetry must not interrupt fencing, claim cleanup, or renewal.\n console.warn('Workspace egress failure observer threw');\n }\n };\n const serialized = <T>(work: () => Promise<T>): Promise<T> => {\n const task = pending.then(work, work);\n pending = task.catch(() => undefined);\n return task;\n };\n let sourceDigest: Promise<string> | null = null;\n const execute = async (request: Record<string, JsonValue>) => {\n if (request.action === 'block' && configurationToken == null && pendingUnlock != null) {\n try {\n await execute({\n action: 'claim',\n configurationToken: pendingUnlock,\n refresh: true,\n verifyOnly: true,\n });\n } catch (cause) {\n if (!z.object({ code: z.literal('conflict') }).safeParse(cause).success) throw cause;\n pendingUnlock = null;\n }\n }\n if (\n configurationFailure != null &&\n request.action !== 'status' &&\n request.action !== 'unlock' &&\n request.action !== 'block'\n )\n throw configurationFailure;\n if (request.action !== 'status') cachedStatus = null;\n sourceDigest ??= crypto.subtle\n .digest('SHA-256', new TextEncoder().encode(workspaceEgressBootstrap))\n .then((hash) =>\n [...new Uint8Array(hash)].map((byte) => byte.toString(16).padStart(2, '0')).join(''),\n );\n const input = JSON.stringify({\n ...request,\n configurationToken: request.configurationToken ?? configurationToken ?? pendingUnlock,\n workspaceId: options.workspaceId,\n });\n let result = await run({ source: cachedWorkspaceEgressBootstrap(await sourceDigest), input });\n if (result.exitCode === 0) {\n let response: unknown;\n try {\n response = JSON.parse(result.stdout);\n } catch {\n response = null;\n }\n if (z.object({ needsBootstrap: z.literal(true) }).safeParse(response).success)\n result = await run({ source: workspaceEgressBootstrap, input });\n }\n if (result.exitCode !== 0) {\n let failure: unknown;\n try {\n failure = JSON.parse(result.stdout);\n } catch {\n failure = null;\n }\n const parsed = z.object({ errorCode: z.string() }).safeParse(failure);\n const code =\n parsed.success &&\n [\n 'prerequisite',\n 'conflict',\n 'configuration',\n DeviceApiClientErrorCode.EgressEnrollmentLost,\n ].includes(parsed.data.errorCode)\n ? parsed.data.errorCode\n : 'prerequisite';\n throw Object.assign(\n new Error(\n `Workspace egress ${code} failed${code === 'prerequisite' ? ' (root, TUN, NET_ADMIN and policy routing required)' : ''}. Inspect the root-owned last-error.json for details`,\n ),\n { code },\n );\n }\n let raw: unknown;\n try {\n raw = JSON.parse(result.stdout);\n } catch {\n throw new Error('Invalid workspace egress status');\n }\n const status = localStatusSchema.parse(raw);\n if (request.action === 'block' && configurationToken == null && pendingUnlock != null) {\n try {\n await execute({ action: 'unlock', configurationToken: pendingUnlock });\n pendingUnlock = null;\n } catch (cause) {\n reportFailure('unlock', cause);\n }\n }\n return status;\n };\n const statusForGuard = async (userId: string | null) => {\n if (\n cachedStatus != null &&\n cachedStatus.userId === userId &&\n performance.now() - cachedStatus.at < 100\n )\n return cachedStatus.value;\n const value = await execute({ action: 'status' });\n cachedStatus = { at: performance.now(), userId, value };\n return value;\n };\n const callerFor = (userId: string | null) => ({\n organizationId: options.organizationId,\n actingUser: { current: async () => userId },\n });\n const block = async (userId: string | null, restoreDirect = false) => {\n current = null;\n const local = await execute({ action: 'block', ownerUserId: userId, restoreDirect }).catch(\n async (cause) => {\n if (z.object({ code: z.literal('conflict') }).safeParse(cause).success) throw cause;\n const fences = await Promise.allSettled([\n options.afterBlock?.(),\n options.afterGuard == null\n ? undefined\n : restoreNetwork({ mode: WorkspaceNetworkPolicy.DenyAll }),\n ]);\n const failures = fences.flatMap((result) =>\n result.status === 'rejected' ? [result.reason] : [],\n );\n if (failures.length > 0)\n throw new AggregateError([cause, ...failures], 'Namespace and provider denial failed');\n throw cause;\n },\n );\n await options.afterBlock?.();\n return local;\n };\n const release = async (args: {\n userId: string | null;\n leaseId: string | null;\n nextOwner: string | null;\n suspendWorkspace?: boolean;\n restoreDirect?: boolean;\n }) => {\n const failures: unknown[] = [];\n let denied = false;\n let superseded = false;\n current = null;\n try {\n const local = await execute({\n action: 'block',\n ownerUserId: args.nextOwner,\n expectedLeaseId: args.suspendWorkspace === true ? null : args.leaseId,\n restoreDirect: args.restoreDirect ?? false,\n });\n denied = local.mode === 'blocked';\n superseded = !denied;\n } catch (cause) {\n superseded = z.object({ code: z.literal('conflict') }).safeParse(cause).success;\n failures.push(cause);\n }\n if (!superseded || args.suspendWorkspace === true)\n try {\n const fences = await Promise.allSettled([\n options.afterBlock?.(),\n (!denied || options.afterBlock == null) && options.afterGuard != null\n ? restoreNetwork({ mode: WorkspaceNetworkPolicy.DenyAll, allow: [] })\n : undefined,\n ]);\n const rejected = fences.flatMap((result) =>\n result.status === 'rejected' ? [result.reason] : [],\n );\n if (rejected.length > 0) throw new AggregateError(rejected, 'Provider denial failed');\n repairProviderPolicy = false;\n } catch (cause) {\n failures.push(cause);\n }\n if (args.suspendWorkspace === true) {\n try {\n // Local owner/lease fields constrain the namespace guard, never API identity.\n await client.egress.suspend({\n caller: callerFor(args.userId),\n workspaceId: options.workspaceId,\n });\n createdLease = null;\n } catch (cause) {\n failures.push(cause);\n }\n } else if (args.userId != null && args.leaseId != null) {\n try {\n await revokeLease({\n caller: callerFor(args.userId),\n leaseId: args.leaseId,\n workspaceId: options.workspaceId,\n });\n if (createdLease?.leaseId === args.leaseId) createdLease = null;\n } catch (cause) {\n failures.push(cause);\n }\n }\n if (failures.length > 0)\n throw new AggregateError(failures, 'Workspace network block or egress revocation failed');\n };\n let reportedPolicy: string | null = null;\n const reportLogicalPolicy = async () => {\n const logical =\n directPolicyKnown && directPolicy != null\n ? directPolicy\n : { mode: WorkspaceNetworkPolicy.DenyAll };\n const encoded = JSON.stringify(logical);\n if (encoded !== reportedPolicy) {\n await options.onNetworkPolicy?.(logical);\n reportedPolicy = encoded;\n }\n };\n const restoreNetwork = async (policy: { mode: string; allow?: string[] } | null) => {\n const parsed = workspaceNetworkPolicySchema.safeParse(policy);\n if (policy != null && !parsed.success)\n throw new Error('Saved workspace network policy is unsupported; networking remains blocked');\n const desired = parsed.success ? parsed.data : { mode: WorkspaceNetworkPolicy.DenyAll };\n if (options.afterGuard != null) await options.afterGuard(desired);\n else if (desired.mode !== WorkspaceNetworkPolicy.AllowAll || options.afterBlock != null)\n throw new Error('A provider policy-restoration hook is required; networking remains blocked');\n await reportLogicalPolicy();\n };\n const profileFor = async (userId: string) => {\n const caller = callerFor(userId);\n const profile = await client.egress.workspace({ caller, workspaceId: options.workspaceId });\n if (profile.networkPolicy != null) {\n directPolicy = workspaceNetworkPolicySchema.parse(profile.networkPolicy);\n directPolicyKnown = true;\n }\n if (profile.networkPolicy == null && options.initialNetworkPolicy == null) {\n requiresChoice = true;\n await block(userId);\n throw new Error(\n 'The host must supply the current network policy before opting in a workspace',\n );\n }\n if (profile.networkPolicy == null && options.initialNetworkPolicy != null) {\n const policy = workspaceNetworkPolicySchema.parse(options.initialNetworkPolicy);\n directPolicy = policy;\n await client.egress.setNetworkPolicy({\n caller: callerFor(null),\n workspaceId: options.workspaceId,\n policy,\n initializeIfMissing: true,\n });\n const initialized = await client.egress.workspace({\n caller,\n workspaceId: options.workspaceId,\n });\n if (initialized.networkPolicy != null) {\n directPolicy = workspaceNetworkPolicySchema.parse(initialized.networkPolicy);\n directPolicyKnown = true;\n }\n return initialized;\n }\n return profile;\n };\n const authorizeRouteMutation = async (\n userId: string | null,\n local: z.infer<typeof localStatusSchema>,\n ) => {\n if (\n options.allowOwnerChange === false &&\n local.ownerUserId != null &&\n local.ownerUserId !== userId\n )\n throw new Error('Workspace egress belongs to another actor; this binding requires its owner');\n if (local.ownerUserId != null && local.ownerUserId !== userId)\n await options.authorizeOwnerChange?.(userId);\n // An owned active lease permits local cleanup during an outage; other routes require fresh authority.\n if (\n current != null &&\n owner === userId &&\n local.ownerUserId === userId &&\n local.leaseId === current.leaseId &&\n current.state === 'active' &&\n current.expiresAtMs > now()\n )\n return;\n if (userId == null) {\n await client.egress.networkState({\n organizationId: options.organizationId,\n workspaceId: options.workspaceId,\n });\n return;\n }\n const profile = await client.egress.workspace({\n caller: callerFor(userId),\n workspaceId: options.workspaceId,\n });\n if (options.allowOwnerChange === false && profile.lockedByOtherOwner)\n throw new Error('Workspace egress belongs to another actor; this binding requires its owner');\n };\n const waitReady = async (leaseId: string | null, mode: string) => {\n const deadline = performance.now() + 35_000;\n for (;;) {\n const result = await execute({ action: 'status' });\n if (result.mode === mode && (leaseId == null || result.leaseId === leaseId)) return result;\n if (performance.now() >= deadline)\n throw new Error('Workspace egress did not become ready; networking remains blocked');\n await sleep(200);\n }\n };\n const configureAttempt = async (userId: string, deviceIds: string[], dnsResolvers?: string[]) => {\n recovered = false;\n await authorizeRouteMutation(userId, await execute({ action: 'status' }));\n const local = await block(userId);\n if (local.policyRouting === false)\n throw new Error(\n 'This sandbox kernel does not support the Linux policy routing required for Device egress',\n );\n const caller = callerFor(userId);\n const profile = await profileFor(userId);\n if (\n options.afterGuard == null &&\n (directPolicy?.mode !== WorkspaceNetworkPolicy.AllowAll || options.afterBlock != null)\n )\n throw new Error('A provider policy-restoration hook is required before Device configuration');\n try {\n if (profile.lease != null)\n await revokeLease({\n caller,\n leaseId: profile.lease.leaseId,\n workspaceId: options.workspaceId,\n });\n if (\n profile.onlineDeviceIds != null &&\n deviceIds.every((id) =>\n profile.deviceIds.some((saved) => saved.toLowerCase() === id.toLowerCase()),\n ) &&\n !deviceIds.some((id) =>\n profile.onlineDeviceIds?.some((online) => online.toLowerCase() === id.toLowerCase()),\n )\n )\n throw new Error('No configured egress Device is online; networking remains blocked');\n const architecture = local.architecture ?? 'x86_64';\n const selectArtifact = (artifacts: DeviceEgressLeaseIface['helper']) => {\n const selected = [artifacts, ...(artifacts.alternatives ?? [])].find(\n (item) => (item.architecture ?? 'x86_64') === architecture,\n );\n if (selected == null)\n throw new Error(\n 'No approved networking helper is configured for this workspace architecture',\n );\n return selected;\n };\n const helper = selectArtifact(profile.helper);\n const helperUrl = new URL(helper.url);\n if (helperUrl.protocol !== 'https:') {\n throw new Error('Workspace networking artifacts require HTTPS');\n }\n const cached = await execute({ action: 'artifact', sha256: helper.sha256 });\n let bytes: Uint8Array | null = null;\n if (cached.helperReady !== true) {\n const response = await (options.fetch ?? fetch)(helperUrl, {\n redirect: 'error',\n signal: AbortSignal.timeout(60_000),\n });\n if (!response.ok || response.body == null) {\n await response.body?.cancel();\n throw new Error('Could not download the pinned workspace networking helper');\n }\n const chunks: Uint8Array[] = [];\n let size = 0;\n const reader = response.body.getReader();\n try {\n for (;;) {\n const next = await reader.read();\n if (next.done) break;\n size += next.value.byteLength;\n if (size > 128 * 1024 * 1024)\n throw new Error('Workspace networking helper exceeds its size limit');\n chunks.push(next.value);\n }\n } finally {\n await reader.cancel();\n }\n const downloaded = new Uint8Array(size);\n let offset = 0;\n for (const chunk of chunks) {\n downloaded.set(chunk, offset);\n offset += chunk.byteLength;\n }\n const hash = [...new Uint8Array(await crypto.subtle.digest('SHA-256', downloaded))]\n .map((byte) => byte.toString(16).padStart(2, '0'))\n .join('');\n if (hash !== helper.sha256)\n throw new Error('Workspace networking helper failed integrity verification');\n bytes = downloaded;\n }\n const hash = helper.sha256;\n // Upload APIs can create root-owned files; a sandbox-owned parent allows normal cleanup.\n const stagingDirectory = bytes == null ? null : `/tmp/final-egress-${crypto.randomUUID()}`;\n const helperPath =\n stagingDirectory == null\n ? '/run/final-workspace-egress/helper'\n : `${stagingDirectory}/helper`;\n let leaseId: string | null = null;\n const outcome: ConfigurationOutcomeIface = { result: null, failures: [] };\n try {\n if (bytes != null)\n await options.sandbox.writeBinaryFile({ path: helperPath, content: bytes });\n // Downloads and uploads can outlive the claim; do not enroll after another binding wins.\n const refreshed = await execute({ action: 'claim', configurationToken, refresh: true });\n if (refreshed.busy === true)\n throw new Error('Workspace configuration claim was superseded');\n const lease = await client.egress.create({\n caller,\n workspaceId: options.workspaceId,\n deviceIds,\n dnsResolvers,\n });\n leaseId = lease.leaseId;\n createdLease = { leaseId: lease.leaseId, userId };\n validateApprovedDevices(lease, deviceIds);\n if (lease.workspaceId !== options.workspaceId)\n throw new Error('Egress enrollment belongs to a different workspace');\n if (lease.state !== 'provisioning')\n throw new Error('Egress enrollment must return provisioning state before activation');\n if (selectArtifact(lease.helper).sha256 !== hash)\n throw new Error('Networking artifact changed during enrollment; retry configuration');\n // Allow transport only once local denial, artifact integrity, and lease ownership are established.\n await execute({ action: 'claim', configurationToken, refresh: true });\n repairProviderPolicy = true;\n await restoreNetwork({ mode: WorkspaceNetworkPolicy.AllowAll, allow: [] });\n await execute({ action: 'claim', configurationToken, refresh: true });\n await execute({\n action: 'configure',\n ownerUserId: userId,\n helperPath,\n config: { ...lease, helper, ownerUserId: userId, revision: crypto.randomUUID() },\n });\n await waitReady(lease.leaseId, 'enrolled');\n if (configurationFailure != null) throw configurationFailure;\n // Revalidate the root-owned claim immediately before publishing packet grants.\n const claim = await execute({ action: 'claim', configurationToken, refresh: true });\n if (claim.busy === true) throw new Error('Workspace configuration claim was superseded');\n const active = await client.egress.activate({ caller, leaseId: lease.leaseId });\n validateApprovedDevices(active, deviceIds);\n if (active.leaseId !== lease.leaseId)\n throw new Error('Egress activation returned a different lease');\n if (active.workspaceId !== options.workspaceId)\n throw new Error('Egress activation belongs to a different workspace');\n if (active.state !== 'active')\n throw new Error('Egress activation must return active state');\n validateActiveLease(active, now());\n await execute({ action: 'renew', lease: active });\n const result = await waitReady(lease.leaseId, 'device');\n repairProviderPolicy = false;\n current = active;\n recovered = true;\n nextRenewAttempt = 0;\n nextRecoveryAttempt = 0;\n outcome.result = result;\n } catch (cause) {\n outcome.failures.push(cause);\n try {\n await release({ userId, leaseId, nextOwner: userId });\n } catch (cleanup) {\n outcome.failures.push(cleanup);\n }\n }\n try {\n if (stagingDirectory != null)\n await options.sandbox.removePath({\n path: stagingDirectory,\n recursive: true,\n force: true,\n });\n } catch (cleanup) {\n reportFailure('artifact-cleanup', cleanup);\n outcome.failures.push(cleanup);\n }\n if (outcome.failures.length > 0 && outcome.result != null) {\n try {\n await release({ userId, leaseId, nextOwner: userId });\n } catch (cleanup) {\n outcome.failures.push(cleanup);\n }\n }\n if (outcome.failures.length > 0)\n throw new AggregateError(outcome.failures, 'Egress configuration or cleanup failed');\n if (outcome.result == null) throw new Error('Egress configuration did not return a status');\n return outcome.result;\n } catch (cause) {\n try {\n if (options.afterBlock == null && directPolicy != null) {\n let ownsClaim = false;\n try {\n const claim = await execute({ action: 'claim', configurationToken, refresh: true });\n ownsClaim = claim.busy !== true;\n } catch (claim) {\n reportFailure('outer-policy-claim', claim);\n }\n if (ownsClaim && (await execute({ action: 'status' })).mode === 'blocked')\n await restoreNetwork(directPolicy);\n }\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n 'Egress configuration and outer policy restoration failed',\n );\n }\n throw cause;\n }\n };\n\n const verifyConfigurationClaim = async () => {\n const claim = await execute({\n action: 'claim',\n configurationToken,\n refresh: true,\n verifyOnly: true,\n });\n if (claim.busy === true) throw new Error('Workspace configuration claim was superseded');\n };\n\n const withConfigurationClaim = async <T>(\n work: () => Promise<T>,\n cleanup?: () => Promise<void>,\n waitForClaim = true,\n ): Promise<T> => {\n if (pendingUnlock != null) {\n await execute({ action: 'unlock', configurationToken: pendingUnlock });\n pendingUnlock = null;\n }\n const token = crypto.randomUUID();\n const deadline = performance.now() + 180_000;\n for (;;) {\n let claim: Awaited<ReturnType<typeof execute>>;\n try {\n claim = await execute({ action: 'claim', configurationToken: token });\n } catch (cause) {\n // The guest may have recorded this token before its response was lost.\n pendingUnlock = token;\n recovered = false;\n throw cause;\n }\n if (claim.busy !== true) break;\n if (!waitForClaim)\n throw Object.assign(new Error('Another binding owns workspace configuration'), {\n code: 'conflict',\n });\n if (performance.now() >= deadline)\n throw new Error('Another binding is configuring workspace egress; retry later');\n await sleep(200);\n }\n configurationToken = token;\n let refreshing = true;\n let refreshTimer: ReturnType<typeof setTimeout> | null = null;\n let refresh: Promise<void> = Promise.resolve();\n const scheduleRefresh = () => {\n refreshTimer = setTimeout(() => {\n refresh = execute({ action: 'claim', configurationToken: token, refresh: true })\n .then((claim) => {\n if (claim.busy === true)\n throw new Error('Workspace configuration claim was superseded');\n })\n .catch((cause) => {\n configurationFailure = cause;\n reportFailure('configuration-claim', cause);\n });\n void refresh.then(() => {\n if (refreshing && configurationFailure == null) scheduleRefresh();\n });\n }, 60_000);\n if (typeof refreshTimer === 'object' && 'unref' in refreshTimer) refreshTimer.unref();\n };\n scheduleRefresh();\n let result: { value: T } | null = null;\n const failures: unknown[] = [];\n try {\n result = { value: await work() };\n } catch (cause) {\n failures.push(cause);\n }\n refreshing = false;\n if (refreshTimer != null) clearTimeout(refreshTimer);\n await refresh;\n if (configurationFailure != null && !failures.includes(configurationFailure))\n failures.push(configurationFailure);\n let cleaned = false;\n const clean = async () => {\n if (cleanup == null || cleaned) return;\n cleaned = true;\n try {\n await cleanup();\n } catch (cause) {\n failures.push(cause);\n reportFailure('configuration-cleanup', cause);\n }\n };\n if (failures.length > 0) await clean();\n try {\n await execute({ action: 'unlock', configurationToken: token });\n } catch (cause) {\n pendingUnlock = token;\n recovered = false;\n if (failures.length === 0) failures.push(cause);\n else reportFailure('unlock', cause);\n if (!cleaned && cleanup != null) {\n try {\n const claim = await execute({\n action: 'claim',\n configurationToken: token,\n refresh: true,\n });\n if (claim.busy === true) throw new Error('Workspace configuration claim was superseded');\n await clean();\n } catch (cleanupClaim) {\n failures.push(cleanupClaim);\n reportFailure('configuration-cleanup', cleanupClaim);\n }\n }\n }\n configurationToken = null;\n configurationFailure = null;\n if (repairProviderPolicy) {\n repairProviderPolicy = false;\n try {\n if (options.namespaceExists == null || (await options.namespaceExists()) !== false)\n await withConfigurationClaim(\n async () => {\n const latest = await execute({ action: 'status' });\n if (latest.leaseId != null) return;\n if (latest.choicePending === true || latest.mode !== 'direct') {\n if (options.afterBlock != null) await options.afterBlock();\n else await restoreNetwork({ mode: WorkspaceNetworkPolicy.DenyAll, allow: [] });\n await execute({ action: 'claim', configurationToken, refresh: true });\n return;\n }\n // Repair a late provider write against current state, never the superseded actor's policy.\n await block(latest.ownerUserId ?? null, true);\n const state = await client.egress.networkState({\n organizationId: options.organizationId,\n workspaceId: options.workspaceId,\n });\n if (state.enabled || state.networkPolicy == null)\n throw new Error(\n 'Current direct-access policy is unavailable; networking remains blocked',\n );\n await restoreNetwork(state.networkPolicy);\n await execute({ action: 'claim', configurationToken, refresh: true });\n await execute({ action: 'disable', ownerUserId: null });\n await waitReady(null, 'direct');\n },\n undefined,\n false,\n );\n } catch (cause) {\n if (!z.object({ code: z.literal('conflict') }).safeParse(cause).success)\n failures.push(cause);\n reportFailure('provider-policy-repair', cause);\n }\n }\n if (failures.length > 1)\n throw new AggregateError(\n failures,\n failures\n .map((failure) => (failure instanceof Error ? failure.message : String(failure)))\n .join('; '),\n { cause: failures[0] },\n );\n if (failures.length > 0) throw failures[0];\n if (result == null) throw new Error('Workspace egress configuration returned no result');\n return result.value;\n };\n\n const configure = (userId: string, deviceIds: string[], dnsResolvers?: string[]) =>\n withConfigurationClaim(\n () => configureAttempt(userId, deviceIds, dnsResolvers),\n async () => {\n if (\n current != null &&\n createdLease?.leaseId === current.leaseId &&\n createdLease.userId === userId\n )\n await release({ userId, leaseId: current.leaseId, nextOwner: userId });\n },\n );\n\n const recoverAttempt = async (userId: string | null, background: boolean) => {\n const local = await execute({ action: 'status' });\n if (local.ownerUserId != null && local.ownerUserId !== userId) {\n if (background) {\n requiresChoice = true;\n current = null;\n return;\n }\n await options.authorizeOwnerChange?.(userId);\n }\n if (local.mode === 'error' && local.ownerUserId !== userId) {\n requiresChoice = true;\n if (options.allowOwnerChange !== false) {\n await options.afterBlock?.();\n await restoreNetwork({ mode: WorkspaceNetworkPolicy.DenyAll, allow: [] });\n }\n throw new Error(\n 'Workspace egress enforcement is in error; explicitly configure or disable to repair',\n );\n }\n // Recovery holds the same namespace claim as explicit configuration and disable.\n // An actor change cannot inherit another person's exit, including after host restart.\n if (\n (local.ownerUserId != null && local.ownerUserId !== userId) ||\n (background && local.mode === 'blocked' && local.ownerUserId === null && userId != null)\n ) {\n if (options.allowOwnerChange === false)\n throw new Error(\n 'Workspace egress belongs to another actor; this binding requires its owner',\n );\n if (background) {\n requiresChoice = true;\n current = null;\n return;\n }\n await authorizeRouteMutation(userId, local);\n requiresChoice = true;\n await release({ userId, leaseId: local.leaseId, nextOwner: userId, suspendWorkspace: true });\n throw new Error(\n 'Workspace egress owner changed; explicitly configure or disable egress before running tools',\n );\n }\n const choicePending = local.choicePending ?? local.mode === 'blocked';\n if (userId == null) {\n const state = await client.egress.networkState({\n organizationId: options.organizationId,\n workspaceId: options.workspaceId,\n });\n if (state.enabled) {\n requiresChoice = true;\n await block(null);\n throw new Error(\n 'This workspace has Device egress configured; an acting user must choose its network policy',\n );\n }\n if (choicePending) {\n requiresChoice = true;\n await block(null);\n throw new Error('Workspace networking is blocked; explicitly configure or disable egress');\n }\n let policy = state.networkPolicy;\n if (policy == null) {\n if (options.initialNetworkPolicy == null) {\n requiresChoice = true;\n await block(null);\n throw new Error(\n 'The host must supply the current network policy before opting in a workspace',\n );\n }\n const initial = workspaceNetworkPolicySchema.parse(options.initialNetworkPolicy);\n await client.egress.setNetworkPolicy({\n caller: callerFor(null),\n workspaceId: options.workspaceId,\n policy: initial,\n initializeIfMissing: true,\n });\n policy = (\n await client.egress.networkState({\n organizationId: options.organizationId,\n workspaceId: options.workspaceId,\n })\n ).networkPolicy;\n }\n if (policy != null) {\n directPolicy = workspaceNetworkPolicySchema.parse(policy);\n directPolicyKnown = true;\n }\n await restoreNetwork(policy);\n if (local.mode !== 'direct' || local.restorePending === true) {\n await execute({ action: 'disable', ownerUserId: null });\n await waitReady(null, 'direct');\n }\n requiresChoice = false;\n return;\n }\n const desired = await profileFor(userId);\n if (desired.lockedByOtherOwner) {\n if (options.allowOwnerChange === false)\n throw new Error(\n 'Workspace egress belongs to another actor; this binding requires its owner',\n );\n requiresChoice = true;\n if (background) {\n current = null;\n return;\n }\n await block(userId);\n throw new Error(\n 'Workspace egress belongs to a different actor; configure or explicitly disable it before running tools',\n );\n }\n if (!desired.enabled) {\n if (choicePending) {\n requiresChoice = true;\n await block(userId);\n throw new Error('Workspace networking is blocked; explicitly configure or disable egress');\n }\n await restoreNetwork(desired.networkPolicy);\n if (local.mode !== 'direct' || local.restorePending === true) {\n await execute({ action: 'disable', ownerUserId: userId });\n await waitReady(null, 'direct');\n }\n current = null;\n return;\n }\n if (\n desired.lease != null &&\n (['device', 'reconnecting'].includes(local.mode) ||\n (['blocked', 'configuring'].includes(local.mode) && local.controllerAlive === true)) &&\n local.leaseId === desired.lease.leaseId\n ) {\n try {\n if (desired.lease.workspaceId !== options.workspaceId)\n throw new Error('Egress recovery belongs to a different workspace');\n validateApprovedDevices(desired.lease, desired.deviceIds);\n validateActiveLease(desired.lease, now());\n } catch (cause) {\n requiresChoice = true;\n if (options.allowOwnerChange !== false)\n await release({ userId, leaseId: desired.lease.leaseId, nextOwner: userId });\n throw cause;\n }\n current = desired.lease;\n await restoreNetwork({ mode: WorkspaceNetworkPolicy.AllowAll, allow: [] });\n if (local.mode === 'configuring' || local.expiresAtMs !== desired.lease.expiresAtMs) {\n await execute({ action: 'renew', lease: desired.lease });\n await waitReady(desired.lease.leaseId, 'device');\n }\n return;\n }\n if (options.allowOwnerChange === false)\n throw new Error(\n 'Workspace networking needs recovery by an active workspace binding before external access',\n );\n if (performance.now() < nextRecoveryAttempt)\n throw new Error(\n 'Workspace egress recovery is cooling down; retry later or explicitly configure',\n );\n nextRecoveryAttempt = performance.now() + 60_000;\n await configureAttempt(userId, desired.deviceIds, desired.dnsResolvers);\n nextRecoveryAttempt = 0;\n };\n const recover = async (userId: string | null, background: boolean) => {\n if (performance.now() < nextRecoveryProbeAt)\n throw new Error(\n 'Workspace egress recovery is cooling down; retry shortly or explicitly configure',\n );\n recovered = false;\n try {\n await withConfigurationClaim(\n () => recoverAttempt(userId, background),\n async () => {\n if (\n current != null &&\n createdLease?.leaseId === current.leaseId &&\n createdLease.userId === userId\n )\n await release({ userId, leaseId: current.leaseId, nextOwner: userId });\n },\n );\n recovered = true;\n nextRecoveryProbeAt = 0;\n } catch (cause) {\n if (cause instanceof Error && isPermanentAuthorizationFailure(cause)) {\n requiresChoice = true;\n try {\n if (options.allowOwnerChange !== false) await block(userId);\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n 'Egress recovery rejected and local denial failed',\n );\n }\n }\n if (!initializing && !requiresChoice) nextRecoveryProbeAt = performance.now() + 5_000;\n throw cause;\n }\n };\n const stableStatus = async (userId: string | null) => {\n const deadline = performance.now() + 180_000;\n for (;;) {\n const local = await statusForGuard(userId);\n if (local.configuring !== true) return local;\n if (performance.now() >= deadline)\n throw new Error('Another binding is configuring workspace egress; retry later');\n cachedStatus = null;\n await sleep(200);\n }\n };\n const maintain = async (background = false) => {\n if (closed) throw new Error('Workspace egress manager is closed');\n if (background && (requiresChoice || (recovered && current == null))) return;\n if (requiresChoice) {\n const actor = await options.actingUser.current();\n const local = await execute({ action: 'status' });\n const repaired =\n local.configuring !== true &&\n ((local.mode === 'direct' &&\n local.choicePending === false &&\n local.restorePending !== true &&\n local.ownerUserId == null) ||\n (local.mode === 'device' &&\n local.ownerUserId === actor &&\n local.expiresAtMs != null &&\n local.expiresAtMs > now()));\n if (!repaired)\n throw new Error('Explicitly configure or disable workspace egress before running tools');\n // Another authorized binding repaired the namespace; revalidate its saved route.\n requiresChoice = false;\n current = null;\n owner = undefined;\n recovered = false;\n cachedStatus = null;\n nextRecoveryProbeAt = 0;\n }\n if (background && owner === undefined) return;\n const userId = background ? (owner ?? null) : await options.actingUser.current();\n if (owner !== userId) {\n if (options.allowOwnerChange === false && owner !== undefined && current != null)\n throw new Error(\n 'Workspace egress belongs to another actor; this binding requires its owner',\n );\n if (owner !== undefined && current != null) {\n await authorizeRouteMutation(userId, await execute({ action: 'status' }));\n requiresChoice = true;\n const leaseId = current.leaseId;\n owner = userId;\n await release({ userId, leaseId, nextOwner: userId, suspendWorkspace: true });\n throw new Error(\n 'Workspace egress owner changed; configure or disable egress before running tools',\n );\n }\n // Recovery failures belong to the actor that attempted them.\n nextRecoveryProbeAt = 0;\n nextRecoveryAttempt = 0;\n // Retain the last foreground identity even when recovery fails transiently.\n owner = userId;\n await recover(userId, background);\n }\n if (!recovered) {\n await recover(userId, background);\n }\n if (background && requiresChoice) return;\n if (current != null && current.expiresAtMs <= now()) {\n await recover(userId, background);\n }\n const local = await stableStatus(userId);\n if (local.mode === 'blocked' && local.ownerUserId == null && local.leaseId == null) {\n requiresChoice = true;\n if (background) return;\n throw new Error(\n 'Workspace networking is blocked; explicitly configure or disable egress before running tools',\n );\n }\n if (local.mode === 'error' && local.ownerUserId !== userId) {\n requiresChoice = true;\n if (options.allowOwnerChange !== false) {\n await options.afterBlock?.();\n await restoreNetwork({ mode: WorkspaceNetworkPolicy.DenyAll, allow: [] });\n }\n throw new Error(\n 'Workspace egress enforcement is in error; explicitly configure or disable to repair',\n );\n }\n if (\n (local.ownerUserId != null && local.ownerUserId !== userId) ||\n (background && local.mode === 'blocked' && local.ownerUserId === null && userId != null)\n ) {\n if (options.allowOwnerChange === false)\n throw new Error(\n 'Workspace egress belongs to another actor; this binding requires its owner',\n );\n if (background) {\n requiresChoice = true;\n current = null;\n return;\n }\n await authorizeRouteMutation(userId, local);\n requiresChoice = true;\n await release({ userId, leaseId: local.leaseId, nextOwner: userId, suspendWorkspace: true });\n throw new Error(\n 'Workspace egress owner changed; configure or disable egress before running tools',\n );\n }\n if (\n (current != null && local.leaseId !== current.leaseId) ||\n (current == null && local.leaseId != null)\n ) {\n current = null;\n await recover(userId, background);\n return;\n }\n if (\n (local.mode === 'error' || (local.mode === 'blocked' && local.controllerAlive !== true)) &&\n local.ownerUserId === userId\n ) {\n // A live controller waits through Device outages; a dead controller needs recovery.\n current = null;\n await recover(userId, background);\n return;\n }\n if (\n current != null &&\n userId != null &&\n performance.now() >= nextRenewAttempt &&\n (current.expiresAtMs - now() < 10 * 60_000 ||\n ['blocked', 'reconnecting'].includes(local.mode))\n ) {\n try {\n const lease = await client.egress.renew({\n caller: callerFor(userId),\n leaseId: current.leaseId,\n });\n validateActiveLease(lease, now());\n validateApprovedDevices(\n lease,\n current.devices.map((device) => device.deviceId),\n );\n if (lease.leaseId !== current.leaseId)\n throw Object.assign(new Error('Egress renewal returned a different lease'), {\n invalidEgressLease: true,\n code: 'configuration',\n });\n if (lease.workspaceId !== options.workspaceId)\n throw Object.assign(new Error('Egress renewal belongs to a different workspace'), {\n invalidEgressLease: true,\n code: 'configuration',\n });\n await execute({ action: 'renew', lease });\n current = lease;\n nextRenewAttempt = performance.now() + 30_000;\n } catch (cause) {\n const status = cause instanceof Error ? deviceApiStatusOf(cause) : null;\n reportFailure('renew', cause);\n if (z.object({ invalidEgressLease: z.literal(true) }).safeParse(cause).success) {\n requiresChoice = true;\n const leaseId = current.leaseId;\n try {\n await release({ userId, leaseId, nextOwner: userId });\n } catch (cleanup) {\n throw new AggregateError([cause, cleanup], 'Invalid egress lease and cleanup failed');\n }\n throw cause;\n }\n if (deviceApiCodeOf(cause) === DeviceApiClientErrorCode.EgressEnrollmentLost) {\n const leaseId = current.leaseId;\n recovered = false;\n try {\n await release({ userId, leaseId, nextOwner: userId });\n } catch (cleanup) {\n throw new AggregateError([cause, cleanup], 'Egress renewal and cleanup failed');\n }\n current = null;\n nextRecoveryProbeAt = performance.now() + 5_000;\n throw cause;\n }\n if (status === 401 || status === 403 || status === 404 || status === 410) {\n if (status === 404) {\n const profile = await profileFor(userId).catch((lookup) => {\n nextRenewAttempt = performance.now() + 30_000;\n reportFailure('renew-profile', lookup);\n throw new AggregateError([cause, lookup], 'Egress renewal and profile lookup failed');\n });\n if (\n !profile.lockedByOtherOwner &&\n profile.configured === true &&\n !profile.enabled &&\n profile.networkPolicy != null\n ) {\n const latest = await execute({ action: 'status' });\n if (\n latest.mode === 'direct' &&\n latest.choicePending !== true &&\n latest.ownerUserId === userId\n ) {\n current = null;\n createdLease = null;\n recovered = false;\n requiresChoice = false;\n await recover(userId, background);\n return;\n }\n }\n if (\n !profile.lockedByOtherOwner &&\n profile.enabled &&\n profile.lease != null &&\n profile.lease.leaseId !== current.leaseId\n ) {\n current = null;\n recovered = false;\n await recover(userId, background);\n return;\n }\n }\n requiresChoice = true;\n try {\n await release({ userId, leaseId: current.leaseId, nextOwner: userId });\n } catch (cleanup) {\n throw new AggregateError([cause, cleanup], 'Egress renewal and cleanup failed');\n }\n throw cause;\n }\n nextRenewAttempt = performance.now() + 30_000;\n if (\n current.expiresAtMs > now() &&\n local.leaseId === current.leaseId &&\n (['device', 'reconnecting'].includes(local.mode) || local.controllerAlive === true)\n )\n return;\n throw cause;\n }\n }\n };\n const schedule = () => {\n if (closed) return;\n timer = setTimeout(() => {\n void serialized(() => maintain(true))\n .catch((cause) => reportFailure('maintenance', cause))\n .finally(schedule);\n }, 60_000);\n if (typeof timer === 'object' && 'unref' in timer) timer.unref();\n };\n const close = (stopWorkspace = false, onlyCurrent = false): Promise<void> =>\n serialized(async () => {\n if (stopped || (closed && !stopWorkspace)) return;\n if (onlyCurrent && (current == null || current.leaseId !== createdLease?.leaseId)) {\n closed = true;\n if (timer != null) clearTimeout(timer);\n timer = null;\n const created = createdLease;\n const results = await Promise.allSettled([\n (async () => {\n if (created == null) return;\n await revokeLease({\n caller: callerFor(created.userId),\n leaseId: created.leaseId,\n workspaceId: options.workspaceId,\n });\n createdLease = null;\n })(),\n (async () => {\n if (pendingUnlock == null) return;\n await execute({ action: 'unlock', configurationToken: pendingUnlock });\n pendingUnlock = null;\n })(),\n ]);\n notifyClosed();\n const failures = results.flatMap((result) =>\n result.status === 'rejected' ? [result.reason] : [],\n );\n if (failures.length > 0) throw new AggregateError(failures, 'Owned egress cleanup failed');\n return;\n }\n closed = true;\n if (timer != null) clearTimeout(timer);\n if (!stopWorkspace) {\n try {\n if (pendingUnlock != null) {\n await execute({ action: 'unlock', configurationToken: pendingUnlock });\n pendingUnlock = null;\n }\n } finally {\n notifyClosed();\n }\n return;\n }\n timer = null;\n try {\n const failures: unknown[] = [];\n let userId: string | null = onlyCurrent ? (createdLease?.userId ?? owner ?? null) : null;\n if (!onlyCurrent) {\n try {\n userId = await options.actingUser.current();\n } catch (cause) {\n failures.push(cause);\n }\n }\n let leaseId = current?.leaseId ?? null;\n let needsBlock = current != null || requiresChoice;\n let namespaceExists = true;\n try {\n namespaceExists = (await options.namespaceExists?.()) ?? true;\n } catch (cause) {\n failures.push(cause);\n }\n if (!namespaceExists) {\n try {\n if (!onlyCurrent)\n await client.egress.suspend({\n caller: callerFor(userId),\n workspaceId: options.workspaceId,\n });\n else if (userId != null && leaseId != null)\n await revokeLease({\n caller: callerFor(userId),\n leaseId,\n workspaceId: options.workspaceId,\n });\n } catch (cause) {\n failures.push(cause);\n }\n if (failures.length > 0)\n throw new AggregateError(failures, 'Workspace egress close or revocation failed');\n stopped = true;\n return;\n }\n if (pendingUnlock != null) {\n try {\n await execute({ action: 'unlock', configurationToken: pendingUnlock });\n pendingUnlock = null;\n } catch (cause) {\n failures.push(cause);\n }\n }\n if (!onlyCurrent && leaseId == null && userId != null) {\n try {\n leaseId =\n (\n await client.egress.workspace({\n caller: callerFor(userId),\n workspaceId: options.workspaceId,\n })\n ).lease?.leaseId ?? null;\n } catch (cause) {\n failures.push(cause);\n }\n }\n if (leaseId == null) {\n try {\n needsBlock ||= (await execute({ action: 'status' })).mode !== 'direct';\n } catch (cause) {\n failures.push(cause);\n needsBlock = true;\n }\n }\n if (leaseId != null || needsBlock) {\n try {\n await release({ userId, leaseId, nextOwner: userId, suspendWorkspace: !onlyCurrent });\n } catch (cause) {\n failures.push(cause);\n }\n } else if (!onlyCurrent) {\n try {\n await client.egress.suspend({\n caller: callerFor(userId),\n workspaceId: options.workspaceId,\n });\n } catch (cause) {\n failures.push(cause);\n }\n }\n if (failures.length > 0)\n throw new AggregateError(failures, 'Workspace egress close or revocation failed');\n stopped = true;\n } finally {\n notifyClosed();\n }\n });\n\n return {\n initialize: () =>\n serialized(async () => {\n initializing = true;\n try {\n await maintain();\n } catch (cause) {\n reportFailure('initialize', cause);\n /* Management remains available while execution is blocked. */\n } finally {\n initializing = false;\n }\n if (timer == null) schedule();\n }),\n guard: (args?: { background?: boolean }) =>\n serialized(async () => {\n await maintain(args?.background ?? false);\n if (requiresChoice)\n throw new Error('Explicitly configure or disable workspace egress before running tools');\n }),\n setNetworkPolicy: (\n policy: NetworkPolicyIface,\n apply: (policy: NetworkPolicyIface) => Promise<void>,\n ) =>\n serialized(async () => {\n if (closed) throw new Error('Workspace egress manager is closed');\n nextRecoveryProbeAt = 0;\n const userId = await options.actingUser.current();\n await withConfigurationClaim(async () => {\n const local = await execute({ action: 'status' });\n const deviceChoicePending = local.choicePending ?? local.mode === 'blocked';\n const validated = workspaceNetworkPolicySchema.parse(policy);\n const state = await client.egress.networkState({\n organizationId: options.organizationId,\n workspaceId: options.workspaceId,\n });\n if (current != null || state.enabled || deviceChoicePending)\n throw new Error(\n 'Disable Device egress before changing the saved direct-access network policy',\n );\n if (requiresChoice)\n await execute({ action: 'block', ownerUserId: userId, restoreDirect: true });\n try {\n await client.egress.setNetworkPolicy({\n caller: callerFor(userId),\n workspaceId: options.workspaceId,\n policy: validated,\n });\n directPolicy = validated;\n directPolicyKnown = true;\n await apply(validated);\n await reportLogicalPolicy();\n await execute({ action: 'disable', ownerUserId: userId });\n await waitReady(null, 'direct');\n requiresChoice = false;\n recovered = true;\n owner = userId;\n } catch (cause) {\n requiresChoice = true;\n try {\n await release({ userId, leaseId: null, nextOwner: userId, restoreDirect: true });\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n 'Network policy update and egress cleanup failed',\n );\n }\n throw cause;\n }\n });\n }),\n egress: (request: WorkspaceEgressRequestIface): Promise<WorkspaceEgressStatusIface> =>\n serialized(async () => {\n if (closed) throw new Error('Workspace egress manager is closed');\n const parsed = workspaceEgressRequestSchema.parse(request);\n const userId = await options.actingUser.current();\n if (parsed.action === WorkspaceEgressAction.Status) {\n const local = await execute({ action: 'status' });\n return workspaceEgressStatusSchema.parse(local);\n }\n if (userId == null) throw new Error('Changing Device egress requires an acting user');\n if (parsed.action === WorkspaceEgressAction.Configure) {\n if (options.allowConfiguration === false)\n throw new Error(\n 'New workspace egress configuration is disabled; existing settings can be inspected or disabled',\n );\n if (parsed.deviceIds == null) throw new Error('Configure requires Device IDs');\n await authorizeRouteMutation(userId, await execute({ action: 'status' }));\n owner = userId;\n requiresChoice = false;\n nextRecoveryAttempt = 0;\n nextRecoveryProbeAt = 0;\n try {\n return workspaceEgressStatusSchema.parse(\n await configure(userId, parsed.deviceIds, parsed.dnsResolvers),\n );\n } catch (cause) {\n requiresChoice = true;\n reportFailure('configure', cause);\n throw cause;\n }\n }\n await authorizeRouteMutation(userId, await execute({ action: 'status' }));\n owner = userId;\n requiresChoice = false;\n nextRecoveryAttempt = 0;\n nextRecoveryProbeAt = 0;\n try {\n return await withConfigurationClaim(async () => {\n const local = await execute({ action: 'status' });\n await authorizeRouteMutation(userId, local);\n await verifyConfigurationClaim();\n if (local.mode !== 'direct') {\n try {\n await block(userId);\n } catch (cause) {\n // The controller can confirm emergency denial even when the full guard fails.\n await verifyConfigurationClaim();\n const denied = await execute({ action: 'status' });\n if (\n (denied.mode !== 'blocked' &&\n !(denied.mode === 'error' && denied.networkPristine === true)) ||\n denied.ownerUserId !== userId\n )\n throw cause;\n }\n }\n await verifyConfigurationClaim();\n await client.egress.disable({\n caller: callerFor(userId),\n workspaceId: options.workspaceId,\n });\n createdLease = null;\n const profile = await client.egress.workspace({\n caller: callerFor(userId),\n workspaceId: options.workspaceId,\n });\n await verifyConfigurationClaim();\n repairProviderPolicy = true;\n if (profile.networkPolicy != null) {\n directPolicy = workspaceNetworkPolicySchema.parse(profile.networkPolicy);\n directPolicyKnown = true;\n }\n await restoreNetwork(profile.networkPolicy);\n await verifyConfigurationClaim();\n repairProviderPolicy = false;\n await execute({ action: 'disable', ownerUserId: userId });\n const result = workspaceEgressStatusSchema.parse(await waitReady(null, 'direct'));\n current = null;\n recovered = true;\n return result;\n });\n } catch (cause) {\n requiresChoice = true;\n throw cause;\n }\n }),\n close: (stopWorkspace = false) => close(stopWorkspace),\n closeOnFailure: () => close(true, true),\n };\n};\n\n// Persist the provider's policy before any boot fence, including passive first attachments.\nexport const preserveWorkspaceNetworkPolicy = async (options: {\n api: DeviceApiConfigIface | (() => DeviceApiConfigIface);\n organizationId: string;\n workspaceId: string;\n policy: NetworkPolicyIface;\n client?: Pick<DeviceApiClientIface, 'egress'>;\n}): Promise<void> => {\n deviceEgressWorkspaceIdSchema.parse(options.workspaceId);\n const api = typeof options.api === 'function' ? options.api() : options.api;\n await (options.client ?? createDeviceApiClient({ api })).egress.setNetworkPolicy({\n caller: { organizationId: options.organizationId, actingUser: { current: async () => null } },\n workspaceId: options.workspaceId,\n policy: options.policy,\n initializeIfMissing: true,\n });\n};\n\nexport type WorkspaceEgressManagerIface = ReturnType<typeof createWorkspaceEgressManager>;\n\nconst workspaceEgressController = (\n manager: WorkspaceEgressManagerIface,\n): SandboxNetworkingControllerIface => ({\n initialize: manager.initialize,\n guard: async (context) => {\n // The policy operation authorizes and repairs networking without requiring a usable tunnel.\n if (\n context == null ||\n ![SandboxExecutionOperation.SetNetworkPolicy, SandboxExecutionOperation.Egress].includes(\n context.operation,\n )\n )\n await manager.guard(context);\n },\n close: manager.close,\n closeOnFailure: manager.closeOnFailure,\n extendSandbox: (sandbox) => {\n const overrides: Partial<NetworkSandboxSessionIface> = { egress: manager.egress };\n if (sandbox.screen != null) {\n const screen = sandbox.screen.bind(sandbox);\n overrides.screen = async (args) => {\n if (args?.viewOnly === false)\n throw new Error(\n 'Managed workspace screen grants are view-only; use the guarded computer-use channel for input',\n );\n return screen({ ...args, viewOnly: true });\n };\n }\n if (sandbox.setNetworkPolicy != null) {\n const apply = sandbox.setNetworkPolicy.bind(sandbox);\n overrides.setNetworkPolicy = (policy) => manager.setNetworkPolicy(policy, apply);\n }\n return withSandboxOverrides(sandbox, overrides);\n },\n authorizeExternalAccess: async () => {\n await manager.guard();\n const status = await manager.egress({ action: WorkspaceEgressAction.Status });\n return { expiresAtMs: status.expiresAtMs == null ? null : status.expiresAtMs - 90_000 };\n },\n});\n\nexport interface WorkspaceDeviceNetworkingOptionsIface {\n api: WorkspaceEgressManagerOptionsIface['api'];\n mcpFetch?: typeof globalThis.fetch;\n needed: (args: {\n organizationId: string;\n workspaceId: string;\n teardown?: boolean;\n access?: SandboxAccess;\n }) => Promise<boolean>;\n allowConfiguration?: boolean;\n authorizeOwnerChange?: (args: {\n organizationId: string;\n workspaceId: string;\n actingUserId: string | null;\n }) => Promise<void>;\n}\n\n// Final Device is one opinionated implementation of the public networking extension contract.\nexport const createWorkspaceDeviceNetworking = (\n options: WorkspaceDeviceNetworkingOptionsIface,\n): SandboxNetworkingExtensionIface => ({\n capabilities: [SandboxCapability.Egress],\n fetch: options.mcpFetch,\n validateWorkspaceId: (workspaceId) => {\n deviceEgressWorkspaceIdSchema.parse(workspaceId);\n },\n enabled: ({ ctx, workspaceId, teardown, access }) =>\n options.needed({ organizationId: ctx.organizationId, workspaceId, teardown, access }),\n prepare: async ({ ctx, workspaceId, policy }) => {\n const client = createDeviceApiClient({ api: options.api });\n await preserveWorkspaceNetworkPolicy({\n client,\n api: options.api,\n organizationId: ctx.organizationId,\n workspaceId,\n policy,\n });\n try {\n const saved = await client.egress.networkState({\n organizationId: ctx.organizationId,\n workspaceId,\n });\n return workspaceNetworkPolicySchema.parse(saved.networkPolicy);\n } catch {\n // The initialized ledger remains authoritative; admission restores reporting after recovery.\n return { mode: WorkspaceNetworkPolicy.DenyAll, allow: [] };\n }\n },\n suspend: ({ ctx, workspaceId }) =>\n suspendWorkspaceEgress({\n api: options.api,\n organizationId: ctx.organizationId,\n workspaceId,\n actingUser: ctx.actingUser,\n }),\n controller: (args) =>\n workspaceEgressController(\n createWorkspaceEgressManager({\n sandbox: args.sandbox,\n workspaceId: args.workspaceId,\n organizationId: args.ctx.organizationId,\n actingUser: args.ctx.actingUser,\n api: options.api,\n initialNetworkPolicy: args.initialNetworkPolicy,\n onNetworkPolicy: args.ctx.platformNetworkPolicy,\n privilegedRun: args.privilegedRun,\n afterGuard: args.afterGuard,\n afterBlock: args.afterBlock,\n namespaceExists: args.namespaceExists,\n onClose: args.onClose,\n allowConfiguration:\n args.access === SandboxAccess.Write && options.allowConfiguration !== false,\n allowOwnerChange: args.allowOwnerChange ?? args.access === SandboxAccess.Write,\n authorizeOwnerChange: (actingUserId) =>\n options.authorizeOwnerChange?.({\n organizationId: args.ctx.organizationId,\n workspaceId: args.workspaceId,\n actingUserId,\n }) ?? Promise.resolve(),\n onFailure: (event) => args.log?.('workspace_egress.control_failure', { ...event }),\n }),\n ),\n});\n\nexport const withWorkspaceEgress = <S extends NetworkSandboxSessionIface>(options: {\n handle: SandboxProviderHandleIface<S>;\n manager: WorkspaceEgressManagerIface;\n access: SandboxAccess;\n beforeUse?: () => Promise<void>;\n initialized?: boolean;\n fetch?: typeof globalThis.fetch;\n}): Promise<SandboxProviderHandleIface<S>> =>\n withSandboxNetworking({\n ...options,\n controller: workspaceEgressController(options.manager),\n });\n\nexport const withWorkspaceAdmission = <S extends NetworkSandboxSessionIface>(options: {\n handle: SandboxProviderHandleIface<S>;\n access: SandboxAccess;\n admission: () => Promise<void>;\n fetch?: typeof globalThis.fetch;\n}): Promise<SandboxProviderHandleIface<S>> => withSandboxNetworking(options);\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["hash", "local"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finalai/final-agent-provider",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Final's provider package: serverless, remote and local harnesses; the computer and device sandboxes; the messaging, schedule and event channels.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -220,13 +220,13 @@
|
|
|
220
220
|
"dependencies": {
|
|
221
221
|
"@agentclientprotocol/sdk": "1.8.0",
|
|
222
222
|
"@finalai/acp-session": "0.1.10",
|
|
223
|
-
"@finalai/agent-protocol": "0.4.
|
|
224
|
-
"@finalai/agent-provider": "0.4.
|
|
223
|
+
"@finalai/agent-protocol": "0.4.2",
|
|
224
|
+
"@finalai/agent-provider": "0.4.3",
|
|
225
225
|
"@finalai/computers": "0.2.0",
|
|
226
226
|
"@finalai/websockets": "0.1.6",
|
|
227
227
|
"ws": "^8.21.3",
|
|
228
228
|
"zod": "4.6.5",
|
|
229
|
-
"@finalai/agent-definition": "0.4.
|
|
229
|
+
"@finalai/agent-definition": "0.4.3"
|
|
230
230
|
},
|
|
231
231
|
"engines": {
|
|
232
232
|
"node": ">=26"
|