-
Notifications
You must be signed in to change notification settings - Fork 2.8k
fix(macos): restore VM inference and Hermes Discord paths #3445
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 8 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
6d08d7a
fix(onboard): skip Docker bridge probe for VM driver
ericksoa c98d291
fix(onboard): keep bridge probe patch entrypoint-neutral
ericksoa 26b66cd
fix(onboard): wait for VM startup output before detaching
ericksoa a458b2f
fix(onboard): keep VM startup gate out of entrypoint
ericksoa d3fbfeb
fix(hermes): keep macos vm startup mutable
ericksoa 3869623
fix(onboard): reuse stored messaging channels
ericksoa cef0079
fix(connect): avoid legacy dns repair for vm sandboxes
ericksoa 8343311
fix: monkeypatch macos vm dns for inference
ericksoa 696be2a
fix: allow discord guild users for hermes
ericksoa db6b0d4
refactor: keep onboard entrypoint net neutral
ericksoa aed17c3
Merge remote-tracking branch 'origin/main' into fix/macos-vm-skip-doc…
ericksoa 11cc7f3
fix: allow discord regional websocket gateways
ericksoa 0f54432
fix: address messaging reuse review feedback
ericksoa 46ab1f6
Merge remote-tracking branch 'origin/main' into fix/macos-vm-skip-doc…
ericksoa 2b290c0
fix: flush sandbox create tail before ready recovery
ericksoa 3a9f58f
fix: keep VM DNS monkeypatch best-effort
ericksoa 242a624
fix(onboard): address messaging reuse feedback
ericksoa 32056fa
fix(macos): harden VM DNS monkeypatch
ericksoa d7a3b25
Merge branch 'main' into fix/macos-vm-skip-docker-bridge-probe
cv 793666c
fix(macos): address VM DNS review feedback
ericksoa 70a4887
fix(macos): special-case only VM DNS repair
ericksoa cd513ea
Merge branch 'main' into fix/macos-vm-skip-docker-bridge-probe
cv 5a84abb
Merge remote-tracking branch 'origin/main' into fix/macos-vm-skip-doc…
cv 2646709
Merge remote-tracking branch 'origin/main' into fix/macos-vm-skip-doc…
ericksoa 4c36539
fix(connect): probe VM inference after route reapply
ericksoa 55296c4
merge: main into fix/macos-vm-skip-docker-bridge-probe
cv 69698b7
fix(onboard): satisfy entrypoint budget
cv 7a22871
Merge branch 'main' into fix/macos-vm-skip-docker-bridge-probe
ericksoa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| import fs from "node:fs"; | ||
| import os from "node:os"; | ||
| import path from "node:path"; | ||
|
|
||
| import { | ||
| type CaptureOpenshellResult, | ||
| stripAnsi, | ||
| } from "../../adapters/openshell/client"; | ||
| import { captureOpenshell } from "../../adapters/openshell/runtime"; | ||
| import type { SandboxEntry } from "../../state/registry"; | ||
|
|
||
| const GVPROXY_DNS = "192.168.127.1"; | ||
| const LEGACY_PUBLIC_DNS_BLOCK = ` if [ ! -s /etc/resolv.conf ]; then | ||
| echo "nameserver 8.8.8.8" > /etc/resolv.conf | ||
| echo "nameserver 8.8.4.4" >> /etc/resolv.conf | ||
| fi`; | ||
| const GVPROXY_DNS_BLOCK = ` echo "nameserver \${GVPROXY_GATEWAY_IP}" > /etc/resolv.conf`; | ||
|
|
||
| type CaptureFn = ( | ||
| args: string[], | ||
| opts: { ignoreError?: boolean; timeout?: number }, | ||
| ) => CaptureOpenshellResult; | ||
|
|
||
| export type VmDnsMonkeypatchResult = { | ||
| attempted: boolean; | ||
| changed: boolean; | ||
| ok: boolean; | ||
| reason?: string; | ||
| rootfs?: string; | ||
| }; | ||
|
|
||
| export function shouldApplyVmDnsMonkeypatch( | ||
| entry: Pick<SandboxEntry, "openshellDriver"> | null | undefined, | ||
| platform: NodeJS.Platform = process.platform, | ||
| env: NodeJS.ProcessEnv = process.env, | ||
| ): boolean { | ||
| if (env.NEMOCLAW_DISABLE_VM_DNS_MONKEYPATCH === "1") return false; | ||
| if (entry?.openshellDriver !== "vm") return false; | ||
| return platform === "darwin" || env.NEMOCLAW_FORCE_VM_DNS_MONKEYPATCH === "1"; | ||
| } | ||
|
|
||
| function dockerDriverGatewayStateDir(env: NodeJS.ProcessEnv, homeDir: string): string { | ||
| const configured = env.NEMOCLAW_OPENSHELL_GATEWAY_STATE_DIR; | ||
| if (configured && configured.trim()) return path.resolve(configured.trim()); | ||
| return path.join(homeDir, ".local", "state", "nemoclaw", "openshell-docker-gateway"); | ||
| } | ||
|
|
||
| export function parseSandboxIdFromGetOutput(output: string): string | null { | ||
| const match = stripAnsi(output).match(/^\s*(?:Id|ID):\s*([A-Za-z0-9._-]+)\s*$/m); | ||
| return match?.[1] ?? null; | ||
| } | ||
|
|
||
| function patchGuestInit(initPath: string): boolean { | ||
| if (!fs.existsSync(initPath)) return false; | ||
| const original = fs.readFileSync(initPath, "utf-8"); | ||
| if (original.includes('nameserver ${GVPROXY_GATEWAY_IP}')) return false; | ||
| const patched = original.replace(LEGACY_PUBLIC_DNS_BLOCK, GVPROXY_DNS_BLOCK); | ||
| if (patched === original) return false; | ||
| fs.writeFileSync(initPath, patched); | ||
Check failureCode scanning / CodeQL Potential file system race condition High
The file may have changed since it
was checked Error loading related location Loading |
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| return true; | ||
| } | ||
|
|
||
| export function applyOpenShellVmDnsMonkeypatch( | ||
| sandboxName: string, | ||
| entry: Pick<SandboxEntry, "openshellDriver"> | null | undefined, | ||
| deps: { | ||
| capture?: CaptureFn; | ||
| env?: NodeJS.ProcessEnv; | ||
| homeDir?: string; | ||
| platform?: NodeJS.Platform; | ||
| stateDir?: string; | ||
| } = {}, | ||
| ): VmDnsMonkeypatchResult { | ||
| const env = deps.env ?? process.env; | ||
| if (!shouldApplyVmDnsMonkeypatch(entry, deps.platform ?? process.platform, env)) { | ||
| return { | ||
| attempted: false, | ||
| changed: false, | ||
| ok: false, | ||
| reason: "not a macOS OpenShell VM sandbox", | ||
| }; | ||
| } | ||
|
|
||
| const capture = deps.capture ?? captureOpenshell; | ||
| const get = capture(["sandbox", "get", sandboxName], { | ||
| ignoreError: true, | ||
| timeout: 10_000, | ||
| }); | ||
| const sandboxId = parseSandboxIdFromGetOutput(get.output || ""); | ||
| if (!sandboxId) { | ||
| return { | ||
| attempted: true, | ||
| changed: false, | ||
| ok: false, | ||
| reason: "could not resolve OpenShell sandbox id", | ||
| }; | ||
| } | ||
|
|
||
| const stateDir = | ||
| deps.stateDir ?? dockerDriverGatewayStateDir(env, deps.homeDir ?? os.homedir()); | ||
| const rootfs = path.join(stateDir, "vm-driver", "sandboxes", sandboxId, "rootfs"); | ||
| const resolvConf = path.join(rootfs, "etc", "resolv.conf"); | ||
| if (!fs.existsSync(rootfs)) { | ||
| return { | ||
| attempted: true, | ||
| changed: false, | ||
| ok: false, | ||
| reason: `VM rootfs not found: ${rootfs}`, | ||
| }; | ||
| } | ||
|
|
||
| fs.mkdirSync(path.dirname(resolvConf), { recursive: true }); | ||
| const desired = `nameserver ${GVPROXY_DNS}\n`; | ||
| const current = fs.existsSync(resolvConf) ? fs.readFileSync(resolvConf, "utf-8") : ""; | ||
| let changed = current !== desired; | ||
| if (changed) { | ||
| fs.writeFileSync(resolvConf, desired); | ||
Check failureCode scanning / CodeQL Potential file system race condition High
The file may have changed since it
was checked Error loading related location Loading |
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| } | ||
| changed = | ||
| patchGuestInit(path.join(rootfs, "srv", "openshell-vm-sandbox-init.sh")) || changed; | ||
|
|
||
| return { attempted: true, changed, ok: true, rootfs }; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.