Skip to content

Commit b1320d5

Browse files
authored
fix(status): show gateway active policy version, not the schema constant (NVIDIA#3185)
## Summary `nemoclaw <sandbox> status` rendered the merged policy YAML's schema `version: 1` even after onboarding had advanced the gateway active version to 6, leaving users uncertain whether their preset selections actually took effect. ## Related Issue Closes NVIDIA#1961 ## Changes - `src/lib/actions/sandbox/gateway-state.ts`: capture the `Active: N` line emitted by `openshell policy get --full` (the metadata block above `---`) and rewrite the leading `version:` in the YAML payload to that value before display. - `test/gateway-state.test.ts`: cover the rewrite, the no-`Active:` fallback (YAML left untouched), and the error-output case (original output preserved). ## Type of Change - [x] Code change (feature, bug fix, or refactor) - [ ] Code change with doc updates - [ ] Doc only (prose changes, no code sample modifications) - [ ] Doc only (includes code sample changes) ## Verification - [x] `npx prek run --all-files` passes - [x] `npm test` passes - [x] Tests added or updated for new or changed behavior - [x] No secrets, API keys, or credentials committed - [ ] Docs updated for user-facing behavior changes - [ ] `make docs` builds without warnings (doc changes only) - [ ] Doc pages follow the [style guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md) (doc changes only) - [ ] New doc pages include SPDX header and frontmatter (new pages only) --- Signed-off-by: Tinson Lai <tinsonl@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Sandbox output now synchronizes its YAML "version" with the live policy "Active" value when present; handles and strips ANSI escape sequences and preserves prior behavior for missing, error-like, or non-YAML live policy content. * **Tests** * Added tests for version sync, ANSI-wrapped metadata handling, absent/unusable metadata, and error-string live policy cases. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
1 parent 16947f2 commit b1320d5

2 files changed

Lines changed: 64 additions & 4 deletions

File tree

src/lib/actions/sandbox/gateway-state.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,26 @@ export function mergeLivePolicyIntoSandboxOutput(
5555
if (policyLineIdx === -1) return output;
5656

5757
const before = rawLines.slice(0, policyLineIdx + 1).join("\n");
58-
const delimIdx = livePolicyOutput.search(/^---\s*$/m);
58+
const cleanLivePolicy = stripAnsi(String(livePolicyOutput));
59+
const delimIdx = cleanLivePolicy.search(/^---\s*$/m);
60+
const metadataPart = delimIdx !== -1 ? cleanLivePolicy.slice(0, delimIdx) : "";
5961
const yamlPart =
6062
delimIdx !== -1
61-
? livePolicyOutput.slice(delimIdx).replace(/^---\s*[\r\n]+/, "")
62-
: livePolicyOutput;
63+
? cleanLivePolicy.slice(delimIdx).replace(/^---\s*[\r\n]+/, "")
64+
: cleanLivePolicy;
6365
const trimmedYaml = yamlPart.trim();
6466
const looksLikeError = /^(error|failed|invalid|warning|status)\b/i.test(trimmedYaml);
6567
if (!trimmedYaml || looksLikeError || !/^[a-z_][a-z0-9_]*\s*:/m.test(trimmedYaml)) {
6668
return output;
6769
}
6870

69-
const indented = trimmedYaml
71+
const activeMatch = metadataPart.match(/^Active:\s*(\d+)\s*$/m);
72+
const rewrittenYaml =
73+
activeMatch && /^version:\s*\d+/m.test(trimmedYaml)
74+
? trimmedYaml.replace(/^version:\s*\d+/m, `version: ${activeMatch[1]}`)
75+
: trimmedYaml;
76+
77+
const indented = rewrittenYaml
7078
.split("\n")
7179
.map((line: string) => (line ? ` ${line}` : line))
7280
.join("\n");

test/gateway-state.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
shouldSelectNamedGatewayForReuse,
1717
parseSandboxPhase,
1818
} from "../src/lib/state/gateway.js";
19+
import { mergeLivePolicyIntoSandboxOutput } from "../dist/lib/actions/sandbox/gateway-state.js";
1920

2021
// Realistic CLI outputs
2122
const STATUS_CONNECTED = `
@@ -287,3 +288,54 @@ describe("shouldSelectNamedGatewayForReuse", () => {
287288
);
288289
});
289290
});
291+
292+
describe("mergeLivePolicyIntoSandboxOutput (#1961)", () => {
293+
const sandboxOutput = "Sandbox:\n Id: abc\n Phase: Ready\n\nPolicy:\n schema-stub";
294+
295+
it("rewrites the YAML version line to the gateway active version", () => {
296+
const livePolicy = [
297+
"Version: 5",
298+
"Hash: 738a54c8520a",
299+
"Status: Loaded",
300+
"Active: 6",
301+
"---",
302+
"version: 1",
303+
"filesystem_policy:",
304+
" include_workdir: false",
305+
].join("\n");
306+
307+
const merged = mergeLivePolicyIntoSandboxOutput(sandboxOutput, livePolicy);
308+
expect(merged).toContain(" version: 6");
309+
expect(merged).not.toContain(" version: 1");
310+
expect(merged).not.toContain(" version: 5");
311+
});
312+
313+
it("leaves the YAML untouched when no Active metadata is provided", () => {
314+
const livePolicy = ["---", "version: 1", "filesystem_policy:", " include_workdir: false"].join(
315+
"\n",
316+
);
317+
318+
const merged = mergeLivePolicyIntoSandboxOutput(sandboxOutput, livePolicy);
319+
expect(merged).toContain(" version: 1");
320+
});
321+
322+
it("returns the original output when livePolicy is an error string", () => {
323+
const merged = mergeLivePolicyIntoSandboxOutput(sandboxOutput, "Error: not found");
324+
expect(merged).toBe(sandboxOutput);
325+
});
326+
327+
it("rewrites version when metadata and separator are ANSI-wrapped", () => {
328+
const livePolicy = [
329+
"\x1b[1mVersion:\x1b[0m 5",
330+
"\x1b[1mActive:\x1b[0m 6",
331+
"\x1b[2m---\x1b[0m",
332+
"version: 1",
333+
"filesystem_policy:",
334+
" include_workdir: false",
335+
].join("\n");
336+
337+
const merged = mergeLivePolicyIntoSandboxOutput(sandboxOutput, livePolicy);
338+
expect(merged).toContain(" version: 6");
339+
expect(merged).not.toContain(" version: 1");
340+
});
341+
});

0 commit comments

Comments
 (0)