-
Notifications
You must be signed in to change notification settings - Fork 2.3k
test: add real runAgentInSandbox() E2E tests for telegram injection (Phases 7-11) #1219
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 3 commits
fba1ab0
3f376eb
0e11c49
25e3a4e
ab80478
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 |
|---|---|---|
|
|
@@ -37,8 +37,29 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | |
| export NEEDRESTART_MODE=a | ||
| export DEBIAN_FRONTEND=noninteractive | ||
|
|
||
| # Wait for any existing apt locks (e.g. Brev's own provisioning on boot) | ||
| wait_for_apt() { | ||
| local max_wait=300 # 5 minutes | ||
| local waited=0 | ||
| while fuser /var/lib/dpkg/lock-frontend /var/lib/apt/lists/lock /var/cache/apt/archives/lock >/dev/null 2>&1; do | ||
| if [ $waited -ge $max_wait ]; then | ||
| fail "apt lock still held after ${max_wait}s — another process is stuck" | ||
| fi | ||
| info "Waiting for apt lock to be released... (${waited}s)" | ||
| sleep 10 | ||
| waited=$((waited + 10)) | ||
| done | ||
| # Wait for any apt processes to fully exit — locks can be released | ||
| # momentarily between apt operations in a multi-step provisioning sequence | ||
| while pgrep -Ex "apt-get|apt|dpkg" >/dev/null 2>&1; do | ||
| info "Waiting for apt/dpkg processes to finish..." | ||
| sleep 5 | ||
| done | ||
| } | ||
|
||
|
|
||
| # --- 0. Node.js (needed for services) --- | ||
| if ! command -v node >/dev/null 2>&1; then | ||
| wait_for_apt | ||
| info "Installing Node.js..." | ||
| NODESOURCE_URL="https://deb.nodesource.com/setup_22.x" | ||
| NODESOURCE_SHA256="575583bbac2fccc0b5edd0dbc03e222d9f9dc8d724da996d22754d6411104fd1" | ||
|
|
@@ -55,27 +76,44 @@ if ! command -v node >/dev/null 2>&1; then | |
| else | ||
| fail "No SHA-256 verification tool found (need sha256sum or shasum)" | ||
| fi | ||
| sudo -E bash "$tmpdir/setup_node.sh" >/dev/null 2>&1 | ||
| sudo -E bash "$tmpdir/setup_node.sh" | ||
| ) | ||
| sudo apt-get install -y -qq nodejs >/dev/null 2>&1 | ||
| # Retry apt-get install — Brev provisioning can grab the lock between operations | ||
| for attempt in 1 2 3 4 5; do | ||
| wait_for_apt | ||
| if sudo apt-get install -y -qq nodejs 2>&1; then | ||
| break | ||
| fi | ||
| info "apt-get install nodejs failed (attempt $attempt/5), retrying..." | ||
| sleep 10 | ||
| done | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| info "Node.js $(node --version) installed" | ||
| else | ||
| info "Node.js already installed: $(node --version)" | ||
| fi | ||
|
|
||
| # --- 1. Docker --- | ||
| if ! command -v docker >/dev/null 2>&1; then | ||
| wait_for_apt | ||
| info "Installing Docker..." | ||
| sudo apt-get update -qq >/dev/null 2>&1 | ||
| sudo apt-get install -y -qq docker.io >/dev/null 2>&1 | ||
| for attempt in 1 2 3 4 5; do | ||
| wait_for_apt | ||
| if sudo apt-get update -qq >/dev/null 2>&1 && sudo apt-get install -y -qq docker.io >/dev/null 2>&1; then | ||
| break | ||
| fi | ||
| info "Docker install failed (attempt $attempt/5), retrying..." | ||
| sleep 10 | ||
| done | ||
| sudo usermod -aG docker "$(whoami)" | ||
| info "Docker installed" | ||
| else | ||
| info "Docker already installed" | ||
| fi | ||
|
|
||
| # --- 2. NVIDIA Container Toolkit (if GPU present) --- | ||
| if command -v nvidia-smi >/dev/null 2>&1; then | ||
| # Check that nvidia-smi actually works, not just that the binary exists. | ||
| # Brev GPU images ship nvidia-smi even on CPU-only instances. | ||
| if command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi >/dev/null 2>&1; then | ||
|
Comment on lines
+113
to
+115
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. Use one GPU capability flag across all GPU-gated sections. This block correctly checks runnable Proposed fix+# Detect GPU availability once and reuse everywhere.
+HAS_GPU=false
+if command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi >/dev/null 2>&1; then
+ HAS_GPU=true
+fi
+
# --- 2. NVIDIA Container Toolkit (if GPU present) ---
-if command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi >/dev/null 2>&1; then
+if [ "$HAS_GPU" = true ]; then
...
fi
# --- 4. vLLM (local inference, if GPU present) ---
...
-elif command -v nvidia-smi >/dev/null 2>&1; then
+elif [ "$HAS_GPU" = true ]; then
...
fi🤖 Prompt for AI Agents |
||
| if ! dpkg -s nvidia-container-toolkit >/dev/null 2>&1; then | ||
| info "Installing NVIDIA Container Toolkit..." | ||
| curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \ | ||
|
|
@@ -91,6 +129,22 @@ if command -v nvidia-smi >/dev/null 2>&1; then | |
| else | ||
| info "NVIDIA Container Toolkit already installed" | ||
| fi | ||
| else | ||
| # CPU-only instance: ensure Docker uses runc (not nvidia) as default runtime. | ||
| # Brev GPU images pre-configure nvidia as the default Docker runtime even on | ||
| # CPU instances, causing "nvidia-container-cli: nvml error: driver not loaded" | ||
| # when starting containers. | ||
| if grep -q '"default-runtime".*nvidia' /etc/docker/daemon.json 2>/dev/null; then | ||
| info "Resetting Docker default runtime to runc (no GPU detected)..." | ||
| sudo python3 -c " | ||
| import json | ||
| with open('/etc/docker/daemon.json') as f: cfg = json.load(f) | ||
| cfg.pop('default-runtime', None) | ||
| with open('/etc/docker/daemon.json', 'w') as f: json.dump(cfg, f, indent=2) | ||
| " | ||
| sudo systemctl restart docker | ||
| info "Docker runtime reset to runc" | ||
| fi | ||
| fi | ||
|
|
||
| # --- 3. openshell CLI (binary release, not pip) --- | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -58,19 +58,15 @@ function ssh(cmd, { timeout = 120_000, stream = false } = {}) { | |||||||||||||||||||||||||||||||||||||||||||||||||||
| return stream ? "" : result.trim(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Escape a value for safe inclusion in a single-quoted shell string. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Replaces single quotes with the shell-safe sequence: '\'' | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| function shellEscape(value) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return String(value).replace(/'/g, "'\\''"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| function shellQuote(value) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return `'${String(value).replace(/'/g, "'\\''")}'`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** Run a command on the remote VM with env vars set for NemoClaw. */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| function sshEnv(cmd, { timeout = 600_000, stream = false } = {}) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const envPrefix = [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| `export NVIDIA_API_KEY='${shellEscape(process.env.NVIDIA_API_KEY)}'`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| `export GITHUB_TOKEN='${shellEscape(process.env.GITHUB_TOKEN)}'`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| `export NVIDIA_API_KEY=${shellQuote(process.env.NVIDIA_API_KEY)}`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| `export GITHUB_TOKEN=${shellQuote(process.env.GITHUB_TOKEN)}`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| `export NEMOCLAW_NON_INTERACTIVE=1`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| `export NEMOCLAW_SANDBOX_NAME=e2e-test`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ].join(" && "); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -131,6 +127,14 @@ describe.runIf(hasRequiredVars)("Brev E2E", () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| brev("login", "--token", process.env.BREV_API_TOKEN); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Delete any leftover instance from a previous failed run | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| brev("delete", INSTANCE_NAME); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(`[${elapsed()}] Deleted leftover instance "${INSTANCE_NAME}"`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Expected — no leftover instance | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Create bare CPU instance via brev search cpu | brev create | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(`[${elapsed()}] Creating CPU instance via brev search cpu | brev create...`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(`[${elapsed()}] min-vcpu: ${BREV_MIN_VCPU}, min-ram: ${BREV_MIN_RAM}GB`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -161,6 +165,20 @@ describe.runIf(hasRequiredVars)("Brev E2E", () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(`[${elapsed()}] Code synced`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Wait for Brev's provisioning to finish — it runs apt-get on boot | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // and the locks can be released between operations, so we wait for | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // both locks AND processes to be gone. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(`[${elapsed()}] Waiting for Brev provisioning (apt) to finish...`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ssh( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| `for i in $(seq 1 120); do ` + | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| `if fuser /var/lib/dpkg/lock-frontend /var/lib/apt/lists/lock /var/cache/apt/archives/lock >/dev/null 2>&1 || ` + | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| `pgrep -Ex "apt-get|apt|dpkg" >/dev/null 2>&1; then ` + | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| `echo "apt still running... ($i/120)"; sleep 5; ` + | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| `else break; fi; done`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { timeout: 660_000, stream: true }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Wait for Brev's provisioning to finish — it runs apt-get on boot | |
| // and the locks can be released between operations, so we wait for | |
| // both locks AND processes to be gone. | |
| console.log(`[${elapsed()}] Waiting for Brev provisioning (apt) to finish...`); | |
| ssh( | |
| `for i in $(seq 1 120); do ` + | |
| `if fuser /var/lib/dpkg/lock-frontend /var/lib/apt/lists/lock /var/cache/apt/archives/lock >/dev/null 2>&1 || ` + | |
| `pgrep -Ex "apt-get|apt|dpkg" >/dev/null 2>&1; then ` + | |
| `echo "apt still running... ($i/120)"; sleep 5; ` + | |
| `else break; fi; done`, | |
| { timeout: 660_000, stream: true }, | |
| ); | |
| // Wait for Brev's provisioning to finish — it runs apt-get on boot | |
| // and the locks can be released between operations, so we wait for | |
| // both locks AND processes to be gone. | |
| console.log(`[${elapsed()}] Waiting for Brev provisioning (apt) to finish...`); | |
| ssh( | |
| `ready=0; for i in $(seq 1 120); do ` + | |
| `if fuser /var/lib/dpkg/lock-frontend /var/lib/apt/lists/lock /var/cache/apt/archives/lock >/dev/null 2>&1 || ` + | |
| `pgrep -Ex "apt-get|apt|dpkg" >/dev/null 2>&1; then ` + | |
| `echo "apt still running... ($i/120)"; sleep 5; ` + | |
| `else ready=1; break; fi; done; ` + | |
| `test "$ready" = 1 || { echo "apt still running after 600s"; exit 1; }`, | |
| { timeout: 660_000, stream: true }, | |
| ); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@test/e2e/brev-e2e.test.js` around lines 168 - 179, The loop that waits for
apt in the ssh call can exit after 120 tries with apt still running, so change
the remote script executed by ssh (the code around the ssh(...) call and the
inline for loop) to fail the readiness gate when apt/dpkg is still busy: after
the for loop add a final check (using the same fuser/pgrep conditions) and if it
still finds locks or processes, print an error and exit 1 so the ssh command
returns non-zero; otherwise continue normally. Ensure the failing branch returns
non-zero to fail the test/bootstrap rather than silently succeeding.
Uh oh!
There was an error while loading. Please reload this page.