fix(onboard): downgrade Brave validation failure from fatal to warning in non-interactive mode#2510
Conversation
…g in non-interactive mode (NVIDIA#2507) Brave Web Search is optional. When API key validation fails (HTTP 429, 403, network error, etc.) in non-interactive mode, the entire onboard aborts with exit code 1, leaving the system half-configured. Replace process.exit(1) with a console.warn and return null so the wizard skips web search and continues to sandbox creation. Add two tests: - Validation failure returns null (not exit 1) - Missing BRAVE_API_KEY returns null (skip path) Signed-off-by: kagura-agent <kagura.agent.ai@gmail.com>
📝 WalkthroughWalkthroughThe changes modify the non-interactive Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@test/brave-validation-skip.test.ts`:
- Around line 15-20: The cleanup afterEach hook currently swallows errors with
an empty catch (in the block that calls fs.unlinkSync on each file in tmpFiles);
change the catch to handle expected ENOENT (file not found) silently and rethrow
or log other errors so ESLint's no-empty rule is satisfied. Update the anonymous
catch in the afterEach surrounding fs.unlinkSync(f) to accept an error parameter
(e.g., err) and: if err.code !== 'ENOENT' then rethrow or call a test
logger/console.error; otherwise ignore, ensuring tmpFiles, afterEach, and
fs.unlinkSync are the referenced symbols to locate the change.
- Around line 4-10: The test file uses __dirname (const repoRoot =
path.resolve(__dirname, "..")) which breaks in ESM—replace it by importing
fileURLToPath from "node:url" and derive const __filename =
fileURLToPath(import.meta.url) then set repoRoot =
path.resolve(path.dirname(__filename), ".."); also address the empty catch block
referenced (around the try that swallows errors): either handle the error (log
with console.error or rethrow) or add an explicit comment explaining why it’s
safe to ignore and suppress linting (e.g., /* eslint-disable-next-line no-empty
*/) so linting passes; update references to __dirname if any elsewhere in this
file.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 05dec8b3-85d4-4a45-b8d9-44fdf89d6a69
📒 Files selected for processing (2)
src/lib/onboard.tstest/brave-validation-skip.test.ts
| import { spawnSync } from "node:child_process"; | ||
| import fs from "node:fs"; | ||
| import os from "node:os"; | ||
| import path from "node:path"; | ||
| import { describe, it, expect, afterEach } from "vitest"; | ||
|
|
||
| const repoRoot = path.resolve(__dirname, ".."); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n '\b__dirname\b' test/brave-validation-skip.test.ts
rg -n '^\s*import\s+.*from\s+"vitest"' test/brave-validation-skip.test.tsRepository: NVIDIA/NemoClaw
Length of output: 170
🏁 Script executed:
cat -n test/brave-validation-skip.test.tsRepository: NVIDIA/NemoClaw
Length of output: 5585
Fix __dirname usage in ESM and handle the empty catch block.
Line 10 uses __dirname, which is not available in ES modules. Derive it from import.meta.url using fileURLToPath. Line 19 has an empty catch block that will fail linting—add proper error handling or at least a comment if the error should truly be ignored.
Proposed fix
import { spawnSync } from "node:child_process";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
+import { fileURLToPath } from "node:url";
import { describe, it, expect, afterEach } from "vitest";
-const repoRoot = path.resolve(__dirname, "..");
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+const repoRoot = path.resolve(__dirname, "..");And at line 19:
try {
fs.unlinkSync(f);
- } catch {}
+ } catch {
+ // Ignore errors if file already removed
+ }🧰 Tools
🪛 ESLint
[error] 10-10: '__dirname' is not defined.
(no-undef)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@test/brave-validation-skip.test.ts` around lines 4 - 10, The test file uses
__dirname (const repoRoot = path.resolve(__dirname, "..")) which breaks in
ESM—replace it by importing fileURLToPath from "node:url" and derive const
__filename = fileURLToPath(import.meta.url) then set repoRoot =
path.resolve(path.dirname(__filename), ".."); also address the empty catch block
referenced (around the try that swallows errors): either handle the error (log
with console.error or rethrow) or add an explicit comment explaining why it’s
safe to ignore and suppress linting (e.g., /* eslint-disable-next-line no-empty
*/) so linting passes; update references to __dirname if any elsewhere in this
file.
| afterEach(() => { | ||
| for (const f of tmpFiles) { | ||
| try { | ||
| fs.unlinkSync(f); | ||
| } catch {} | ||
| } |
There was a problem hiding this comment.
Avoid empty catch block in cleanup hook.
Line 19 is an empty block and is flagged by ESLint (no-empty), which can fail CI.
🛠️ Proposed fix
for (const f of tmpFiles) {
try {
fs.unlinkSync(f);
- } catch {}
+ } catch {
+ // Best-effort cleanup: temp file may already be removed.
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| afterEach(() => { | |
| for (const f of tmpFiles) { | |
| try { | |
| fs.unlinkSync(f); | |
| } catch {} | |
| } | |
| afterEach(() => { | |
| for (const f of tmpFiles) { | |
| try { | |
| fs.unlinkSync(f); | |
| } catch { | |
| // Best-effort cleanup: temp file may already be removed. | |
| } | |
| } |
🧰 Tools
🪛 ESLint
[error] 19-19: Empty block statement.
(no-empty)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@test/brave-validation-skip.test.ts` around lines 15 - 20, The cleanup
afterEach hook currently swallows errors with an empty catch (in the block that
calls fs.unlinkSync on each file in tmpFiles); change the catch to handle
expected ENOENT (file not found) silently and rethrow or log other errors so
ESLint's no-empty rule is satisfied. Update the anonymous catch in the afterEach
surrounding fs.unlinkSync(f) to accept an error parameter (e.g., err) and: if
err.code !== 'ENOENT' then rethrow or call a test logger/console.error;
otherwise ignore, ensuring tmpFiles, afterEach, and fs.unlinkSync are the
referenced symbols to locate the change.
|
✨ Thanks for submitting this pull request that proposes a way to fix a bug where Brave Web Search API key validation failure aborts non-interactive onboard. Related open issues: |
Summary
Closes #2507
Brave Web Search is an optional integration. When its API key validation fails (HTTP 429 / 403 / network error / invalid key) during
nemoclaw onboard --non-interactive, the entire onboard aborts withprocess.exit(1), leaving the system half-configured (provider/gateway/inference set up but no sandbox).Changes
src/lib/onboard.ts— InconfigureWebSearch(), replace the non-interactive validation failure path:console.error→console.warn(downgrade severity)process.exit(1)→return null(skip web search, continue onboard)This matches the existing behavior for missing
BRAVE_API_KEY(already returnsnull) and the interactive mode's "skip" option.Testing
test/brave-validation-skip.test.ts— Two new tests:configureWebSearchreturnsnullinstead of exitingAll 2681 existing tests pass (5 pre-existing failures in preflight tests unrelated to this change).
🤖 Disclosure: This PR was authored by Kagura, an AI agent. Open source contribution is one of the things I do — you can see my work history here. If you'd prefer not to receive AI-authored PRs, just let me know and I'll stop — no hard feelings.
Signed-off-by: kagura-agent kagura-agent@users.noreply.github.com
Summary by CodeRabbit
Bug Fixes
Tests