Repository navigation
fix(hermes): recognize OpenShell sandbox absence #9912
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
Changes from all commits
92ca8f4
a2db45d
634136f
1819a12
b354975
074ca72
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| import { describe, expect, it } from "vitest"; | ||
|
|
||
| import { createPodmanHostLocalInferenceTestHarness } from "../../../../test/helpers/podman-host-local-inference-test-harness"; | ||
| import type { HostLocalInferenceRuntime } from "./host-local-inference"; | ||
| import { createPodmanHostLocalInferenceOperation } from "./podman-host-local-inference"; | ||
|
|
||
| function operationRuntime( | ||
| harness: ReturnType<typeof createPodmanHostLocalInferenceTestHarness>, | ||
| ): HostLocalInferenceRuntime { | ||
| const operation = createPodmanHostLocalInferenceOperation({ | ||
| engine: harness.engine, | ||
| env: harness.env, | ||
| acceleration: harness.operationAcceleration, | ||
| authorityStore: harness.authorityStore, | ||
| routeAuthorityStore: harness.routeAuthorityStore, | ||
| onFailureEvidence: harness.onFailureEvidence, | ||
| redactSensitive: harness.redactSensitive, | ||
| }); | ||
| return ( | ||
| operation.managedRuntime ?? | ||
| (() => { | ||
| throw new Error("test operation lacks managed runtime"); | ||
| })() | ||
| ); | ||
| } | ||
|
|
||
| const probeId = "c".repeat(64); | ||
| const inspectEvent = `podman:container inspect ${probeId}`; | ||
|
|
||
| describe("Podman host-local inference post-create probe inspection", () => { | ||
| it("retries one timeout using the same full probe ID", () => { | ||
| const harness = createPodmanHostLocalInferenceTestHarness(); | ||
| harness.state.probePostCreateInspectTimeoutsRemaining = 1; | ||
|
|
||
| const prepared = operationRuntime(harness).startManaged(harness.input, harness.writer); | ||
|
|
||
| const waitIndex = harness.events.indexOf(`podman:wait ${probeId}`); | ||
| expect(waitIndex).toBeGreaterThan(0); | ||
| expect( | ||
| harness.events.slice(0, waitIndex).filter((event) => event === inspectEvent), | ||
| ).toHaveLength(2); | ||
| expect(prepared.receipt.service).toBe("nim"); | ||
| expect(harness.probe()).toBeNull(); | ||
| }); | ||
|
|
||
| it("fails closed after two timeouts without acting on the probe", () => { | ||
| const harness = createPodmanHostLocalInferenceTestHarness(); | ||
| harness.state.probePostCreateInspectTimeoutsRemaining = 2; | ||
| harness.state.probeForbiddenActions = ["wait", "logs", "rm"]; | ||
|
|
||
| expect(() => operationRuntime(harness).startManaged(harness.input, harness.writer)).toThrow( | ||
| "probe identity is indeterminate after create", | ||
| ); | ||
|
|
||
| expect(harness.events.filter((event) => event === inspectEvent)).toHaveLength(2); | ||
| expect(harness.probe()).toMatchObject({ id: probeId }); | ||
| expect(harness.written).toHaveLength(0); | ||
| }); | ||
|
|
||
| it("does not retry a non-timeout failure", () => { | ||
| const harness = createPodmanHostLocalInferenceTestHarness(); | ||
| harness.state.probePostCreateInspectFailuresRemaining = 1; | ||
| harness.state.probeForbiddenActions = ["wait", "logs", "rm"]; | ||
|
|
||
| expect(() => operationRuntime(harness).startManaged(harness.input, harness.writer)).toThrow( | ||
| "probe identity is indeterminate after create", | ||
| ); | ||
|
|
||
| expect(harness.events.filter((event) => event === inspectEvent)).toHaveLength(1); | ||
| expect(harness.probe()).toMatchObject({ id: probeId }); | ||
| expect(harness.written).toHaveLength(0); | ||
| }); | ||
|
|
||
| it("does not retry an inspect result with a mismatched container ID", () => { | ||
| const harness = createPodmanHostLocalInferenceTestHarness(); | ||
| harness.state.probeInspectRuntimeIdMismatchAt = 1; | ||
| harness.state.probeForbiddenActions = ["wait", "logs", "rm"]; | ||
|
|
||
| expect(() => operationRuntime(harness).startManaged(harness.input, harness.writer)).toThrow( | ||
| "probe identity is indeterminate after create", | ||
| ); | ||
|
|
||
| expect(harness.events.filter((event) => event === inspectEvent)).toHaveLength(1); | ||
| expect(harness.probe()).toMatchObject({ id: probeId }); | ||
| expect(harness.written).toHaveLength(0); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -221,15 +221,15 @@ export function createHermesPortableTestInput(stateDir: string, policyPath: stri | |
| authority: { | ||
| schemaVersion: 1, | ||
| sourceRevision: "1".repeat(40), | ||
| dockerfileRelativePath: "agents/hermes/Dockerfile", | ||
| dockerfileRelativePath: "Dockerfile", | ||
| sourceManifestSha256: "2".repeat(64), | ||
| contextManifestSha256: "3".repeat(64), | ||
| }, | ||
| sourceDockerfilePath, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win Use a filesystem path for At Line 228, the fixture assigns an OCI image reference to 🤖 Prompt for AI AgentsSource: Path instructions |
||
| assertCurrentSource: vi.fn(), | ||
| materialize: vi.fn(() => ({ | ||
| buildContextPath: "/private/staged-hermes", | ||
| dockerfilePath: "/private/staged-hermes/agents/hermes/Dockerfile", | ||
| dockerfilePath: "/private/staged-hermes/Dockerfile", | ||
| assertCurrent: vi.fn(), | ||
| })), | ||
| retire: vi.fn(() => true), | ||
|
|
@@ -390,7 +390,7 @@ export function createHermesPortableTransactionFixture( | |
| const policyIndex = argv.indexOf("--policy"); | ||
| expect(argv[policyIndex + 1]).toContain("policy."); | ||
| expect(argv[argv.indexOf("--from") + 1]).toBe( | ||
| options.expectedDockerfilePath ?? "/private/staged-hermes/agents/hermes/Dockerfile", | ||
| options.expectedDockerfilePath ?? "/private/staged-hermes/Dockerfile", | ||
| ); | ||
| expect(buildContextPath).toBe(options.expectedBuildContextPath ?? "/private/staged-hermes"); | ||
| present = true; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
Repository: NVIDIA/NemoClaw
Length of output: 50372
🏁 Script executed:
Repository: NVIDIA/NemoClaw
Length of output: 50372
🏁 Script executed:
Repository: NVIDIA/NemoClaw
Length of output: 50372
🏁 Script executed:
Repository: NVIDIA/NemoClaw
Length of output: 50371
🏁 Script executed:
Repository: NVIDIA/NemoClaw
Length of output: 50371
🏁 Script executed:
Repository: NVIDIA/NemoClaw
Length of output: 50371
🏁 Script executed:
Repository: NVIDIA/NemoClaw
Length of output: 175
Migrate persisted Hermes portable build-context authorities
materialize()now uses<context>/Dockerfile, but the active lifecycle test still expects<context>/agents/hermes/Dockerfile. Update the test and add migration or bounded compatibility handling for interrupted sessions with the old persisted entry path. The currentschemaVersion: 1authority will otherwise fail during resume and cleanup.🤖 Prompt for AI Agents
Source: Path instructions