Repository navigation
Review: agent-browser-plugin-firecrawl (full repo) - #1
rakshith48 wants to merge 1 commit into
Conversation
📝 WalkthroughWalkthroughThis PR introduces the initial implementation of ChangesFirecrawl agent-browser plugin
Sequence Diagram(s)sequenceDiagram
participant Caller as Caller (stdin/stdout)
participant Plugin as bin/plugin.js
participant Firecrawl as Firecrawl /v2 API
rect rgba(70, 130, 180, 0.5)
note over Caller,Plugin: browser.launch
Caller->>Plugin: { type: "browser.launch", launchOptions: { ttl, profile } }
Plugin->>Firecrawl: POST /v2/browser (ttl, profile, activityTtl)
Firecrawl-->>Plugin: { cdpUrl, id, ... }
Plugin-->>Caller: { cdpUrl, metadata, cleanup: { sessionId } }
end
rect rgba(60, 179, 113, 0.5)
note over Caller,Plugin: command.run
Caller->>Plugin: { type: "command.run", command: "firecrawl.scrape", payload }
Plugin->>Firecrawl: POST /v2/scrape (payload)
Firecrawl-->>Plugin: { data }
Plugin-->>Caller: { success: true, data }
end
rect rgba(205, 92, 92, 0.5)
note over Caller,Plugin: browser.close
Caller->>Plugin: { type: "browser.close", sessionId }
Plugin->>Firecrawl: DELETE /v2/browser/:sessionId
Firecrawl-->>Plugin: 200 OK
Plugin-->>Caller: { success: true }
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai full review |
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 @.github/workflows/ci.yml:
- Around line 15-16: Replace the tag-based action references
(actions/checkout@v4 and actions/setup-node@v4) with pinned full commit SHAs
instead of version tags to prevent supply-chain attacks. Additionally, add the
persist-credentials: false configuration option to the checkout action to
disable credential persistence and reduce token exposure risk. Both actions
should reference their specific commit SHA rather than relying on floating
version tags.
In `@bin/plugin.js`:
- Around line 127-140: The code validates that session.cdpUrl exists before
returning the browser metadata, but does not validate that session.id exists,
even though session.id is used in the cleanup object on line 139. Add a
validation check for session.id immediately after or in conjunction with the
existing cdpUrl validation to ensure that both required properties are present
before returning the ok() response. If session.id is missing, throw an error
with a descriptive message similar to the cdpUrl validation, preventing the
plugin from reporting success when it cannot properly track the session for
later cleanup.
- Around line 58-67: The fetch call in the api function lacks a timeout
mechanism, which can cause the plugin to hang indefinitely if a network request
stalls. Add an AbortController with a timeout to the fetch invocation: create an
AbortController instance, set up a timeout that calls abort() on the controller
after a reasonable duration (e.g., 30 seconds), pass the controller's signal in
the fetch options, and ensure the timeout is cleared if the fetch completes
successfully to avoid memory leaks.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: b237836f-1f8f-4c1a-87fd-8972ae7d104a
📒 Files selected for processing (7)
.github/workflows/ci.yml.gitignoreLICENSEREADME.mdbin/plugin.jspackage.jsontest/plugin.test.js
| - uses: actions/checkout@v4 | ||
| - uses: actions/setup-node@v4 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify workflow actions are SHA-pinned and checkout disables persisted credentials.
set -euo pipefail
echo "== action refs in workflow =="
rg -n 'uses:\s*actions/(checkout|setup-node)@' .github/workflows/ci.yml
echo
echo "== check for full SHA pins (40-hex) =="
rg -nP 'uses:\s*actions/(checkout|setup-node)@[0-9a-f]{40}\b' .github/workflows/ci.yml || true
echo
echo "== check checkout persist-credentials setting =="
rg -n 'persist-credentials:\s*false' .github/workflows/ci.yml || true
echo
echo "Expected:"
echo "1) checkout/setup-node lines use @<40-hex-sha>"
echo "2) checkout step includes 'persist-credentials: false'"Repository: rakshith48/agent-browser-plugin-firecrawl
Length of output: 394
Pin action SHAs and disable credential persistence in checkout.
Lines 15–16 use tag-based action refs (@v4). Pin both actions to full commit SHAs and set persist-credentials: false on checkout to mitigate supply-chain and token-exposure risk.
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 15-15: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 15-15: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 16-16: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 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 @.github/workflows/ci.yml around lines 15 - 16, Replace the tag-based action
references (actions/checkout@v4 and actions/setup-node@v4) with pinned full
commit SHAs instead of version tags to prevent supply-chain attacks.
Additionally, add the persist-credentials: false configuration option to the
checkout action to disable credential persistence and reduce token exposure
risk. Both actions should reference their specific commit SHA rather than
relying on floating version tags.
Source: Linters/SAST tools
| async function api(method, path, body) { | ||
| if (!API_KEY) throw new Error("FIRECRAWL_API_KEY is not set"); | ||
| const res = await fetch(`${API_BASE}${path}`, { | ||
| method, | ||
| headers: { | ||
| Authorization: `Bearer ${API_KEY}`, | ||
| ...(body ? { "Content-Type": "application/json" } : {}), | ||
| }, | ||
| body: body ? JSON.stringify(body) : undefined, | ||
| }); |
There was a problem hiding this comment.
Add a timeout to Firecrawl API calls to prevent hangs.
Line 60 performs fetch without an abort/timeout, so a stuck network call can block the plugin from ever emitting its single response.
Suggested fix
async function api(method, path, body) {
if (!API_KEY) throw new Error("FIRECRAWL_API_KEY is not set");
- const res = await fetch(`${API_BASE}${path}`, {
+ const controller = new AbortController();
+ const timeoutMs = Number(process.env.FIRECRAWL_HTTP_TIMEOUT_MS || 30000);
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
+ let res;
+ try {
+ res = await fetch(`${API_BASE}${path}`, {
method,
headers: {
Authorization: `Bearer ${API_KEY}`,
...(body ? { "Content-Type": "application/json" } : {}),
},
body: body ? JSON.stringify(body) : undefined,
- });
+ signal: controller.signal,
+ });
+ } finally {
+ clearTimeout(timer);
+ }
const text = await res.text();📝 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.
| async function api(method, path, body) { | |
| if (!API_KEY) throw new Error("FIRECRAWL_API_KEY is not set"); | |
| const res = await fetch(`${API_BASE}${path}`, { | |
| method, | |
| headers: { | |
| Authorization: `Bearer ${API_KEY}`, | |
| ...(body ? { "Content-Type": "application/json" } : {}), | |
| }, | |
| body: body ? JSON.stringify(body) : undefined, | |
| }); | |
| async function api(method, path, body) { | |
| if (!API_KEY) throw new Error("FIRECRAWL_API_KEY is not set"); | |
| const controller = new AbortController(); | |
| const timeoutMs = Number(process.env.FIRECRAWL_HTTP_TIMEOUT_MS || 30000); | |
| const timer = setTimeout(() => controller.abort(), timeoutMs); | |
| let res; | |
| try { | |
| res = await fetch(`${API_BASE}${path}`, { | |
| method, | |
| headers: { | |
| Authorization: `Bearer ${API_KEY}`, | |
| ...(body ? { "Content-Type": "application/json" } : {}), | |
| }, | |
| body: body ? JSON.stringify(body) : undefined, | |
| signal: controller.signal, | |
| }); | |
| } finally { | |
| clearTimeout(timer); | |
| } |
🤖 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 `@bin/plugin.js` around lines 58 - 67, The fetch call in the api function lacks
a timeout mechanism, which can cause the plugin to hang indefinitely if a
network request stalls. Add an AbortController with a timeout to the fetch
invocation: create an AbortController instance, set up a timeout that calls
abort() on the controller after a reasonable duration (e.g., 30 seconds), pass
the controller's signal in the fetch options, and ensure the timeout is cleared
if the fetch completes successfully to avoid memory leaks.
| if (!session.cdpUrl) throw new Error("Firecrawl did not return a cdpUrl"); | ||
| return ok({ | ||
| browser: { | ||
| cdpUrl: session.cdpUrl, | ||
| directPage: false, | ||
| metadata: { | ||
| sessionId: session.id, | ||
| liveViewUrl: session.liveViewUrl, | ||
| interactiveLiveViewUrl: session.interactiveLiveViewUrl, | ||
| expiresAt: session.expiresAt, | ||
| }, | ||
| // Sent back to us as the browser.close request if connect fails. | ||
| cleanup: { sessionId: session.id }, | ||
| }, |
There was a problem hiding this comment.
Validate session.id before returning browser metadata/cleanup.
Line 139 uses session.id for cleanup, but only session.cdpUrl is validated. If Firecrawl returns a cdpUrl without id, the plugin reports success but cannot close the session later.
Suggested fix
if (type === "browser.launch") {
const session = await api("POST", "/v2/browser", browserCreateBody(input.request));
if (!session.cdpUrl) throw new Error("Firecrawl did not return a cdpUrl");
+ if (!session.id) throw new Error("Firecrawl did not return a session id");
return ok({
browser: {
cdpUrl: session.cdpUrl,🤖 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 `@bin/plugin.js` around lines 127 - 140, The code validates that session.cdpUrl
exists before returning the browser metadata, but does not validate that
session.id exists, even though session.id is used in the cleanup object on line
139. Add a validation check for session.id immediately after or in conjunction
with the existing cdpUrl validation to ensure that both required properties are
present before returning the ok() response. If session.id is missing, throw an
error with a descriptive message similar to the cdpUrl validation, preventing
the plugin from reporting success when it cannot properly track the session for
later cleanup.
|
Closing: full-repo review surfaced 3 findings, addressed in #2 (merged). |
Full plugin as a single diff against an empty baseline so CodeRabbit reviews the entire codebase.
Scope:
bin/plugin.js(agent-browser.plugin.v1 — browser.provider + command.run),test/plugin.test.js(9 hermetic tests),.github/workflows/ci.yml, README, packaging.Review-only — not intended to merge.
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Chores