test(e2e): migrate dashboard remote bind#5186
Conversation
📝 WalkthroughWalkthroughThis PR migrates the dashboard remote-bind E2E test from a legacy shell script to a TypeScript Vitest scenario test. It introduces a new ChangesDashboard Remote-Bind Test Migration
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
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 docstrings
🧪 Generate unit tests (beta)
Comment |
E2E Advisor RecommendationRequired E2E: None Full advisor summaryE2E Recommendation AdvisorBase: Required E2E
Optional E2E
New E2E recommendations
|
Vitest E2E Scenario RecommendationRequired Vitest E2E scenarios: Dispatch required Vitest E2E scenarios:
Full Vitest E2E advisor summaryVitest E2E Scenario AdvisorBase: Required Vitest E2E scenarios
Optional Vitest E2E scenarios
Relevant changed files
|
PR Review AdvisorFindings: 1 needs attention, 1 worth checking, 0 nice ideas Review findings🛠️ Needs attention
🔎 Worth checking
🌱 Nice ideas
Consider writing more tests for
Since last review detailsCurrent findings:
This is an automated advisory review. A human maintainer must make the final merge decision. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/e2e-scenario/live/dashboard-remote-bind.test.ts`:
- Around line 25-37: The RegExp constructors in bindsAllInterfaces and
bindsLoopback interpolate the env-derived dashboardPort directly, which can
allow regex metacharacters to change matching; fix by escaping dashboardPort
before constructing the RegExp (add a small helper like escapeRegExp that
replaces /[.*+?^${}()|[\]\\]/g with '\\$&' and use the escaped value in new
RegExp calls), and update both functions (bindsAllInterfaces and bindsLoopback)
to use the escaped port value when building the regex.
🪄 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: 8f03a7ed-0b51-454a-9bb9-f5ffe7521006
📒 Files selected for processing (4)
test/e2e-scenario/live/dashboard-remote-bind.test.tstest/e2e-script-workflow.test.tstest/e2e/brev-e2e.test.tstest/e2e/test-dashboard-remote-bind.sh
💤 Files with no reviewable changes (1)
- test/e2e/test-dashboard-remote-bind.sh
| function bindsAllInterfaces(line: string, dashboardPort: string): boolean { | ||
| return ( | ||
| line.includes(`0.0.0.0:${dashboardPort}`) || | ||
| line.includes(`*:${dashboardPort}`) || | ||
| new RegExp(`\\b0\\.0\\.0\\.0\\s+${dashboardPort}\\b`).test(line) | ||
| ); | ||
| } | ||
|
|
||
| function bindsLoopback(line: string, dashboardPort: string): boolean { | ||
| return ( | ||
| line.includes(`127.0.0.1:${dashboardPort}`) || | ||
| line.includes(`localhost:${dashboardPort}`) || | ||
| new RegExp(`\\b127\\.0\\.0\\.1\\s+${dashboardPort}\\b`).test(line) |
There was a problem hiding this comment.
Escape dashboardPort before injecting into RegExp patterns.
dashboardPort is env-derived and interpolated directly into regex sources, so metacharacters can change match behavior and make this scenario pass/fail incorrectly.
Suggested fix
+function escapeRegExp(value: string): string {
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+}
+
function bindsAllInterfaces(line: string, dashboardPort: string): boolean {
+ const port = escapeRegExp(dashboardPort);
return (
line.includes(`0.0.0.0:${dashboardPort}`) ||
line.includes(`*:${dashboardPort}`) ||
- new RegExp(`\\b0\\.0\\.0\\.0\\s+${dashboardPort}\\b`).test(line)
+ new RegExp(`\\b0\\.0\\.0\\.0\\s+${port}\\b`).test(line)
);
}
function bindsLoopback(line: string, dashboardPort: string): boolean {
+ const port = escapeRegExp(dashboardPort);
return (
line.includes(`127.0.0.1:${dashboardPort}`) ||
line.includes(`localhost:${dashboardPort}`) ||
- new RegExp(`\\b127\\.0\\.0\\.1\\s+${dashboardPort}\\b`).test(line)
+ new RegExp(`\\b127\\.0\\.0\\.1\\s+${port}\\b`).test(line)
);
}📝 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.
| function bindsAllInterfaces(line: string, dashboardPort: string): boolean { | |
| return ( | |
| line.includes(`0.0.0.0:${dashboardPort}`) || | |
| line.includes(`*:${dashboardPort}`) || | |
| new RegExp(`\\b0\\.0\\.0\\.0\\s+${dashboardPort}\\b`).test(line) | |
| ); | |
| } | |
| function bindsLoopback(line: string, dashboardPort: string): boolean { | |
| return ( | |
| line.includes(`127.0.0.1:${dashboardPort}`) || | |
| line.includes(`localhost:${dashboardPort}`) || | |
| new RegExp(`\\b127\\.0\\.0\\.1\\s+${dashboardPort}\\b`).test(line) | |
| function escapeRegExp(value: string): string { | |
| return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); | |
| } | |
| function bindsAllInterfaces(line: string, dashboardPort: string): boolean { | |
| const port = escapeRegExp(dashboardPort); | |
| return ( | |
| line.includes(`0.0.0.0:${dashboardPort}`) || | |
| line.includes(`*:${dashboardPort}`) || | |
| new RegExp(`\\b0\\.0\\.0\\.0\\s+${port}\\b`).test(line) | |
| ); | |
| } | |
| function bindsLoopback(line: string, dashboardPort: string): boolean { | |
| const port = escapeRegExp(dashboardPort); | |
| return ( | |
| line.includes(`127.0.0.1:${dashboardPort}`) || | |
| line.includes(`localhost:${dashboardPort}`) || | |
| new RegExp(`\\b127\\.0\\.0\\.1\\s+${port}\\b`).test(line) | |
| ); | |
| } |
🧰 Tools
🪛 ast-grep (0.43.0)
[warning] 28-28: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(\\b0\\.0\\.0\\.0\\s+${dashboardPort}\\b)
Note: [CWE-1333] Inefficient Regular Expression Complexity
(regexp-from-variable)
[warning] 36-36: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(\\b127\\.0\\.0\\.1\\s+${dashboardPort}\\b)
Note: [CWE-1333] Inefficient Regular Expression Complexity
(regexp-from-variable)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@test/e2e-scenario/live/dashboard-remote-bind.test.ts` around lines 25 - 37,
The RegExp constructors in bindsAllInterfaces and bindsLoopback interpolate the
env-derived dashboardPort directly, which can allow regex metacharacters to
change matching; fix by escaping dashboardPort before constructing the RegExp
(add a small helper like escapeRegExp that replaces /[.*+?^${}()|[\]\\]/g with
'\\$&' and use the escaped value in new RegExp calls), and update both functions
(bindsAllInterfaces and bindsLoopback) to use the escaped port value when
building the regex.
Source: Linters/SAST tools
Summary
Migrate the active
dashboard-remote-bindBrev suite path to a small live Vitest test while keepingtest/e2e/test-dashboard-remote-bind.shin place per maintainer request.This uses Carlos's PR #5133 as the seed, but keeps only the direct dashboard remote-bind migration and drops the stale #5126-era framework/ledger/workflow noise.
Related Issues
Refs #5098
Refs #5133
Contract mapping
test/e2e-scenario/live/dashboard-remote-bind.test.tsrunscommand -v nemoclaw && command -v openshell.openshell forward stop <dashboardPort>thennemoclaw <sandbox> connect.NEMOCLAW_DASHBOARD_BIND=0.0.0.0is honored.host.nemoclaw([...], { env: { NEMOCLAW_DASHBOARD_BIND: "0.0.0.0" } }).openshell forward list, fail on127.0.0.1/localhost, require0.0.0.0/*for the dashboard port.Simplicity check
dashboard-remote-bindsuite now invokes the live Vitest test fromtest/e2e/brev-e2e.test.ts.test/e2e/test-dashboard-remote-bind.shremains in place; this PR no longer deletes anytest/e2eshell script.Verification
NEMOCLAW_RUN_E2E_SCENARIOS=1 npx vitest run --project e2e-scenarios-live test/e2e-scenario/live/dashboard-remote-bind.test.ts --silent=false --reporter=default(local opt-in live test is skipped unlessNEMOCLAW_E2E_DASHBOARD_REMOTE_BIND=1is set by branch validation)npx vitest run --project cli test/e2e-script-workflow.test.ts --silent=false --reporter=defaultgit diff --check origin/main...HEADnpm run build:cli && npm run typecheck:cli