Skip to content

fix(crawl): make TestConfigureLauncher/sandbox pass in containers (LAB-4994)#184

Merged
santiago-praetorian merged 5 commits into
mainfrom
santiagogimenezocano/lab-4994-pkgcrawl-testconfigurelaunchersandbox-fails-in-containers-go
Jul 21, 2026
Merged

fix(crawl): make TestConfigureLauncher/sandbox pass in containers (LAB-4994)#184
santiago-praetorian merged 5 commits into
mainfrom
santiagogimenezocano/lab-4994-pkgcrawl-testconfigurelaunchersandbox-fails-in-containers-go

Conversation

@santiago-praetorian

Copy link
Copy Markdown
Contributor

Summary

pkg/crawl.TestConfigureLauncher/sandbox failed inside Docker / dev-containers, so make check / make test could not pass locally there — even on a clean checkout with no source changes. This fixes the test so it is deterministic across CI and containerized dev environments.

Fixes LAB-4994.

Root cause

The test asserted the absolute presence of the no-sandbox launcher flag. go-rod's launcher.New() adds --no-sandbox by default when it detects a container (defaultFlags[flags.NoSandbox] is set when inContainer, which is true when /.dockerenv exists). So l.Has("no-sandbox") reported true in dev-containers regardless of Vespasian's own logic, and the three "flag should be absent" sub-cases failed:

--- FAIL: TestConfigureLauncher/sandbox/no_flags_no_env
    browser_test.go:79: Has(no-sandbox) = true, want false
--- FAIL: TestConfigureLauncher/sandbox/env_false_does_not_enable_NoSandbox
--- FAIL: TestConfigureLauncher/sandbox/env_arbitrary_value_does_not_enable_NoSandbox

Vespasian's own logic in configureLauncher is correct — the assertion just conflated it with the launcher default.

Fix

Adopted option 1 from the ticket (test-only, baseline delta). The test now computes the go-rod baseline (launcher.New().Has("no-sandbox")) and asserts on Vespasian's contribution: the flag must be present whenever configureLauncher opts in, and otherwise must match the launcher default (Vespasian must not add it on its own).

want := tt.vespasianOn || baselineNoSandbox

  • CI (VM runner, no container → baseline absent): reduces to want := tt.vespasianOn, byte-identical to the original assertion → full regression detection of Vespasian's opt/env → flag logic is preserved.
  • Dev-container (baseline present): passes deterministically for both uid 0 and uid != 0.

Rejected option 2 (NoSandbox(false)): that calls l.Delete(flags.NoSandbox), which would strip the flag go-rod deliberately adds for root-in-container and could break Chrome launch. This change is test-only; browser.go runtime behavior is unchanged.

Verification

  • go test ./pkg/crawl/... passes in the dev-container as uid 1000 and as uid 0.
  • make check (fmt, vet, lint = 0 issues, go test -race ./...) passes fully in the container.

Acceptance criteria

  • go test ./pkg/crawl/... passes in a container for both uid 0 and uid != 0, and continues to pass on CI.
  • The test still catches regressions in Vespasian's own sandbox-flag logic (opt/env → flag set; otherwise not) — guaranteed on CI where the baseline is deterministically absent.

🤖 Generated with Claude Code

…ine (LAB-4994)

TestConfigureLauncher/sandbox asserted the absolute presence of the
`no-sandbox` launcher flag. go-rod's launcher.New() adds --no-sandbox by
default when it detects a container (defaultFlags[NoSandbox] set when
inContainer), so l.Has("no-sandbox") reported true in Docker/dev-containers
regardless of Vespasian's own logic. The three "flag should be absent"
sub-cases therefore failed inside containers, breaking `make check`
locally even on a clean checkout.

Assert on Vespasian's contribution relative to the launcher baseline
instead of the absolute flag: the flag must be present whenever
configureLauncher opts in, and otherwise must match go-rod's default.
On CI's VM runner (no container -> baseline absent) this reduces to the
original assertion, preserving full regression detection of Vespasian's
sandbox logic; in dev-containers (baseline present) it passes for both
uid 0 and uid != 0. Test-only change; no runtime behavior is altered.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4803d394-9877-4387-87b7-19738cb5d2ee

📥 Commits

Reviewing files that changed from the base of the PR and between 0c5ec30 and ea0531c.

📒 Files selected for processing (2)
  • pkg/crawl/browser.go
  • pkg/crawl/browser_test.go

Walkthrough

Browser launcher configuration now centralizes the no-sandbox decision in vespasianEnablesNoSandbox. Tests derive go-rod’s baseline no-sandbox setting and validate the final launcher flag against that baseline plus Vespasian’s explicit setting.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch santiagogimenezocano/lab-4994-pkgcrawl-testconfigurelaunchersandbox-fails-in-containers-go

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Review

Critical issues

None.

Security

No security concerns flagged.

Test coverage

No critical issues — LGTM pending human review. Test-only change: the new baseline-delta assertion (want := tt.vespasianOn || baselineNoSandbox) is sound — it collapses to the original assertion on CI (container baseline absent → full regression detection of the opt/env→flag logic preserved) and tolerates go-rod's container default without letting Vespasian silently strip it. browser.go runtime behavior is unchanged.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Review

Critical Issues

None.

Security

No security concerns flagged.

Suggestions

  • pkg/crawl/browser_test.go:69: In environments where baselineNoSandbox is already true, the assertions at pkg/crawl/browser_test.go:93 can no longer catch a regression where configureLauncher always enables NoSandbox. Consider factoring the Vespasian sandbox decision into a small helper and testing that directly, while keeping this launcher-baseline test for rod compatibility.

Could not run go test ./pkg/crawl -run TestConfigureLauncher -count=1 here because the sandbox is read-only and Go tried to create /home/runner/go.


Reviewed by Codex (gpt-5.5)

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gemini Review

No critical issues — LGTM pending human review.


Reviewed by Gemini (gemini-3.1-pro-preview)

santiago-praetorian and others added 2 commits July 20, 2026 14:32
Extract the no-sandbox opt-in decision (opts.NoSandbox ||
VESPASIAN_NO_SANDBOX=="true") from configureLauncher into a pure
vespasianEnablesNoSandbox helper and assert on it directly in the sandbox
subtest, alongside the existing launcher-baseline Has("no-sandbox") check.

The prior baseline-relative assertion (want := tt.vespasianOn ||
baselineNoSandbox) becomes a tautology inside dev-containers, where
go-rod's launcher.New() auto-adds --no-sandbox so baselineNoSandbox==true:
the three negative cases would then pass even if configureLauncher were
regressed to unconditionally enable the flag. Asserting the pure decision
directly restores full regression detection in every environment (verified
in-container: injecting an always-on regression now fails the negative
cases), while the launcher-baseline check is kept for go-rod compatibility.

Addresses capability-pr-review findings SEC-BE-001 / TEST-001 and the Codex
review suggestion on PR #184. browser.go runtime behavior is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…(LAB-4994)

Address non-blocking review nits from capability-pr-review on PR #184:
- QUAL-001: configureLauncher's doc comment restated the no-sandbox opt-in
  condition that now lives in vespasianEnablesNoSandbox; trim it to reference
  the helper so the condition has a single documented source of truth.
- TEST-001: hoist the BrowserOptions{NoSandbox: tt.noSandbox} literal into one
  local reused by both the helper assertion and the configureLauncher call.

No behavior change; make check (fmt, vet, lint, go test -race ./...) passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@eli-wald

Copy link
Copy Markdown
Contributor

Praetorian Capability PR Review

PR: #184
Linear: https://linear.app/praetorianlabs/issue/LAB-4994
Head SHA: dfdaa94
Reviewed at: 2026-07-20T08:16:22-07:00

Recommendation: COMMENT

Totals critical high medium low nit
Count 0 0 0 0 1
Blockers 0 0 0 0 0

Non-blockers (1)
Quality (1)
QUAL-001 · nit · pkg/crawl/browser.go:65

Issue: The doc comment for vespasianEnablesNoSandbox describes it as a "pure helper", but the function reads process-global state via os.Getenv("VESPASIAN_NO_SANDBOX"). Its return value therefore depends on the environment, not solely on the opts argument, so it is not pure in the referential-transparency sense. The preceding comment line does mention the env var, so the meaning is recoverable, but the "pure" label could mislead a future reader into assuming no environment dependency. Not a behavior issue.

Recommendation: Reword "pure helper" to something accurate, e.g. "self-contained helper", or note it is "deterministic for a fixed environment." Comment-only change.

-// pure helper lets the test assert Vespasian's contribution directly, which
+// self-contained helper lets the test assert Vespasian's contribution directly, which

Review generated by capability-pr-review. Rerun against the same PR head SHA + Linear ticket state to reproduce this finding set.

santiago-praetorian and others added 2 commits July 21, 2026 01:49
Address capability-pr-review QUAL-001 (nit): the helper reads
os.Getenv("VESPASIAN_NO_SANDBOX"), so 'pure helper' was inaccurate.
Reword to 'self-contained helper'. Comment-only; no behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…994)

- QUAL-001: reword test comment 'pure helper' -> 'self-contained helper'
  to match browser.go (the helper reads an env var, so not pure).
- QUAL-002: rewrap browser.go helper doc comment to <=79 cols.
- TEST-001: document the load-bearing 'CI runs on a non-container VM'
  assumption behind the launcher-baseline assertion (vacuous in a
  container; the vespasianEnablesNoSandbox assertion is the
  environment-independent guard).

Comment/test-only; no production behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@santiago-praetorian

Copy link
Copy Markdown
Contributor Author

Review + test results (head ea0531c)

Addressed the prior capability-pr-review nit (QUAL-001, "pure helper" doc comment), then re-ran the review and the full test suite against the new head.

capability-pr-review — latest run

Re-ran on ea0531c. Result: 0 findings.

Lane Verdict
QUAL (code quality) ✅ no findings
TEST ✅ no findings
SEC-BE (backend security) ✅ no findings — refactor is token-for-token equivalent to the original inline condition
REQ (ticket alignment) ✅ both LAB-4994 acceptance criteria met
DOC n/a — comment/test-only change

The intermediate run (before this commit) surfaced 3 non-blocking items, all now fixed in ea0531c:

  • QUAL — the test comment still said "pure helper" (same wording corrected in browser.go) → reworded to "self-contained helper".
  • QUAL — the reworded doc line exceeded the comment block's wrap width → rewrapped to ≤79 cols.
  • TEST (low) — the launcher-baseline assertion want := tt.vespasianOn || baselineNoSandbox is vacuous in a container (it only exercises the configureLauncher wiring on CI's non-container VM) → documented that load-bearing assumption in-line; the vespasianEnablesNoSandbox assertion remains the environment-independent regression guard.

Static / dynamic / live tests — all green

Category Command Result
Static gofmt -l · go vet ./... · golangci-lint run clean · rc=0 · 0 issues
Dynamic go test -race ./... 18 packages ok, 0 failures / 0 races
Dynamic (PR target) go test -run TestConfigureLauncher/sandbox ./pkg/crawl ✅ passes fresh as uid 1000 and uid 0 in-container
Live — offline run-live-tests.sh --group offline 19 / 19 passed
Live — browser run-live-tests.sh --group live 7 / 7 passed (rest-api, soap-service, graphql-server, concat-spa, concat-spa-two-stage, edge-cases, crawl-depth)

Live browser tests ran with VESPASIAN_NO_SANDBOX=true (matching CI) against a real Chromium; the dev-container's /usr/bin/chromium-browser is a snap stub, so a runnable Chromium was put on PATH for the run.

🤖 Generated with Claude Code

@eli-wald eli-wald left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praetorian Capability PR Review

PR: #184
Linear: https://linear.app/praetorianlabs/issue/LAB-4994
Head SHA: ea0531c
Reviewed at: 2026-07-21T07:09:12-07:00

Recommendation: APPROVE

Totals critical high medium low nit
Count 0 0 0 0 0
Blockers 0 0 0 0 0

No findings. The prior review's QUAL-001 ("pure helper" doc comment) was addressed in commit 7685aede (reworded to "self-contained helper"), and the sandbox-test comment nits were addressed in ea0531cd. Both LAB-4994 acceptance criteria remain met; browser.go runtime behavior is unchanged (the vespasianEnablesNoSandbox extraction is byte-for-byte equivalent to the prior inline condition).


@santiago-praetorian
santiago-praetorian merged commit 9639878 into main Jul 21, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants