diff --git a/scripts/nemoclaw-start.sh b/scripts/nemoclaw-start.sh index 9e316b395..4c68e2925 100755 --- a/scripts/nemoclaw-start.sh +++ b/scripts/nemoclaw-start.sh @@ -295,7 +295,8 @@ if [ "$(id -u)" -ne 0 ]; then echo "[gateway] Running as non-root (uid=$(id -u)) — privilege separation disabled" export HOME=/sandbox if ! verify_config_integrity; then - echo "[SECURITY WARNING] Config integrity check failed — proceeding anyway (non-root mode)" + echo "[SECURITY] Config integrity check failed — refusing to start (non-root mode)" + exit 1 fi write_auth_profile diff --git a/test/nemoclaw-start.test.js b/test/nemoclaw-start.test.js index 246b67cb9..046120fd5 100644 --- a/test/nemoclaw-start.test.js +++ b/test/nemoclaw-start.test.js @@ -16,3 +16,31 @@ describe("nemoclaw-start non-root fallback", () => { expect(src).toMatch(/nohup "\$OPENCLAW" gateway run >\/tmp\/gateway\.log 2>&1 &/); }); }); + +describe("config integrity check", () => { + const src = fs.readFileSync(START_SCRIPT, "utf-8"); + + it("exits on integrity failure in non-root mode", () => { + // Extract the outer non-root block. The trailing \nfi\n targets the + // closing "fi" at column 0 — inner "fi" lines are indented (e.g. " fi") + // so [\s\S]*? stops at the first unindented fi, selecting only the outer + // block. This relies on consistent indentation in nemoclaw-start.sh. + const nonRootMatch = src.match( + /if \[ "\$\(id -u\)" -ne 0 \]; then\n([\s\S]*?)\nfi\n/ + ); + expect(nonRootMatch).not.toBeNull(); + const nonRootBlock = nonRootMatch[1]; + + // The block must NOT contain "proceeding anyway" — that was the old bypass + expect(nonRootBlock).not.toMatch(/proceeding anyway/i); + + // The block must exit on integrity failure + expect(nonRootBlock).toMatch(/verify_config_integrity/); + expect(nonRootBlock).toMatch(/exit 1/); + }); + + it("does not bypass verify_config_integrity in any code path", () => { + // No line should catch and ignore a verify_config_integrity failure + expect(src).not.toMatch(/verify_config_integrity[\s\S]*?proceeding anyway/); + }); +});