Skip to content

Fail fast on a bad CHROME_PATH, and drop a dead preconnect - #4

Merged
Sukarth merged 2 commits into
mainfrom
fix/og-tooling-nits
Jul 29, 2026
Merged

Fail fast on a bad CHROME_PATH, and drop a dead preconnect#4
Sukarth merged 2 commits into
mainfrom
fix/og-tooling-nits

Conversation

@Sukarth

@Sukarth Sukarth commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Two review findings from #3, both in dev-only tooling. No shipped output changes, and the committed PNGs are byte-identical after re-rendering.

  • og-render.mjs trusted CHROME_PATH without checking it. Pointed at a binary that is not there, it skipped detection and failed inside the render loop instead, as sixteen identical ENOENT errors naming the cards rather than the cause. It now exits 1 immediately, naming the path.
  • og-preview.mjs preconnected to fonts.googleapis.com and never requested a stylesheet from it. The cards use Inter from the system, so the connection was opened for nothing.

Verified all three paths: a bad CHROME_PATH exits 1 with the path in the message; a valid one still renders all 16; unset still auto-detects.

No version bump, since nothing user-facing changed.

Summary by Sourcery

Fail fast when CHROME_PATH points to a non-existent binary in OG rendering, and remove an unused font preconnect from the OG preview tooling.

Bug Fixes:

  • Detect and immediately abort when CHROME_PATH is set to a non-existent Chrome binary in the OG renderer.

Enhancements:

  • Simplify OG preview HTML by removing an unnecessary preconnect to fonts.googleapis.com, since system fonts are used.

Summary by CodeRabbit

  • Bug Fixes

    • Improved OG preview rendering by validating that the configured Chrome executable exists and is runnable.
    • Added clearer errors when the configured browser path is missing, points to a directory, or lacks execute permissions.
    • Improved automatic Chrome discovery across Windows and Unix-based systems.
  • Style

    • Removed an unnecessary external font connection from OG preview output.

CHROME_PATH was trusted without checking it. Pointed at a binary that is not
there, the script skipped detection and failed inside the render loop instead,
as sixteen identical ENOENT errors naming the cards rather than the cause.

The preview sheet preconnected to fonts.googleapis.com and then never requested
a stylesheet from it. The cards use Inter from the system, so the connection was
opened for nothing.

Both found by review on #3. Dev tooling only: no shipped output changes, and the
committed PNGs are byte-identical after re-rendering.
Copilot AI review requested due to automatic review settings July 29, 2026 10:52
@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ib-econgraph-ai Ready Ready Preview, Comment Jul 29, 2026 12:53pm

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The OG preview template removes the Google Fonts preconnect hint. Chrome rendering now validates discovered and environment-provided executable paths, classifies invalid overrides, and exits before rendering when necessary.

Changes

OG rendering updates

Layer / File(s) Summary
Preview HTML resource update
scripts/og-preview.mjs
Removes the Google Fonts preconnect link from the generated preview HTML head.
Chrome executable validation
scripts/og-render.mjs
Adds runnable-path checks for Chrome discovery and validates CHROME_PATH with specific failure messages before rendering.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main changes: stricter CHROME_PATH validation and removal of the unused preconnect.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/og-tooling-nits

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.

@sourcery-ai

sourcery-ai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

This PR hardens the OG rendering dev tooling by validating CHROME_PATH up front and simplifying the OG preview HTML by removing an unused font preconnect, with no changes to shipped output.

Sequence diagram for CHROME_PATH resolution and fail-fast behavior in og-render.mjs

sequenceDiagram
    participant og_render_mjs
    participant env
    participant filesystem
    participant console
    participant process

    og_render_mjs->>env: resolveChrome (read CHROME_PATH)
    alt [CHROME_PATH is unset]
        og_render_mjs->>og_render_mjs: findChrome
        og_render_mjs-->>og_render_mjs: chrome (auto-detected)
    else [CHROME_PATH is set]
        og_render_mjs->>filesystem: existsSync(override)
        alt [path exists]
            og_render_mjs-->>og_render_mjs: chrome = override
        else [path does not exist]
            og_render_mjs->>console: console.error
            og_render_mjs->>process: process.exit(1)
        end
    end
Loading

File-Level Changes

Change Details Files
Fail fast when CHROME_PATH is set to a non-existent binary in the OG renderer.
  • Replaces direct environment-or-autodetect assignment with a resolveChrome helper that encapsulates CHROME_PATH handling.
  • Treats an unset CHROME_PATH as a signal to run the existing Chrome auto-detection logic.
  • Checks an explicitly set CHROME_PATH for existence before use, printing a clear error message and exiting with status 1 if the path is invalid.
  • Keeps the rest of the rendering flow unchanged, continuing to use the resolved chrome path.
scripts/og-render.mjs
Remove a dead preconnect to Google Fonts from the OG card preview dev page.
  • Deletes the tag from the preview HTML template.
  • Leaves styling and font-family declarations intact, continuing to rely on system-installed Inter rather than remote fonts.
  • Ensures the preview page no longer opens an unnecessary external connection during dev use.
scripts/og-preview.mjs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Fail fast on invalid CHROME_PATH; remove unused fonts preconnect

🐞 Bug fix ✨ Enhancement 🕐 Less than 10 minutes

Grey Divider

AI Description

• Validate CHROME_PATH early in OG renderer and exit with a clear error message.
• Remove an unused fonts.googleapis.com preconnect from OG preview HTML.
• Keep OG tooling behavior unchanged when CHROME_PATH is valid or unset.
Diagram

graph TD
  A["Env: CHROME_PATH"] --> B["scripts/og-render.mjs"] --> C["Chrome executable"] --> D["public/og/*.png"]
  E["scripts/og-preview.mjs"] --> F["og-preview.html"]
Loading
High-Level Assessment

The approach is appropriate for dev tooling: validate the CHROME_PATH override up front to surface the real misconfiguration cause, while keeping the existing auto-detection path unchanged. Removing the unused preconnect is the simplest correctness/perf cleanup for the preview sheet.

Files changed (2) +16 / -2

Enhancement (1) +0 / -1
og-preview.mjsRemove unused fonts.googleapis.com preconnect from preview HTML +0/-1

Remove unused fonts.googleapis.com preconnect from preview HTML

• Drops a preconnect link to fonts.googleapis.com that was never followed by a stylesheet request. Keeps the preview sheet relying on system fonts (Inter fallback chain) without opening unnecessary connections.

scripts/og-preview.mjs

Bug fix (1) +16 / -1
og-render.mjsFail fast when CHROME_PATH points to a missing Chrome binary +16/-1

Fail fast when CHROME_PATH points to a missing Chrome binary

• Introduces resolveChrome() to distinguish between an unset CHROME_PATH (auto-detect Chrome) and a misconfigured override. If CHROME_PATH is set to a non-existent path, the script now prints a direct error and exits 1 before entering the render loop.

scripts/og-render.mjs

@sourcery-ai sourcery-ai 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.

Hey - I've left some high level feedback:

  • Using process.exit(1) inside resolveChrome makes the helper harder to reuse and test; consider throwing an error and letting the top-level script handle process termination instead.
  • If CHROME_PATH is expected to be absolute, it might be worth normalizing or validating that assumption before existsSync, or clarifying in the error message that relative paths are resolved from the current working directory.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Using `process.exit(1)` inside `resolveChrome` makes the helper harder to reuse and test; consider throwing an error and letting the top-level script handle process termination instead.
- If `CHROME_PATH` is expected to be absolute, it might be worth normalizing or validating that assumption before `existsSync`, or clarifying in the error message that relative paths are resolved from the current working directory.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copilot AI 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.

Pull request overview

This PR improves developer-only OG card tooling by failing fast when CHROME_PATH is misconfigured and by removing an unused resource hint from the OG preview HTML.

Changes:

  • Add resolveChrome() to validate CHROME_PATH early and exit with a clearer error when invalid.
  • Remove an unused <link rel="preconnect"> to fonts.googleapis.com from the OG preview contact sheet.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
scripts/og-render.mjs Adds early CHROME_PATH resolution to surface misconfiguration before the render loop.
scripts/og-preview.mjs Removes an unused preconnect to a font host that isn’t actually referenced.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/og-render.mjs Outdated
Comment on lines +59 to +63
if (!existsSync(override)) {
console.error(`og-render: CHROME_PATH is set to "${override}", which does not exist.`);
process.exit(1);
}
return override;
@qodo-code-review

qodo-code-review Bot commented Jul 29, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. CHROME_PATH insufficiently validated ✓ Resolved 🐞 Bug ☼ Reliability
Description
resolveChrome() only checks existsSync(CHROME_PATH), so an existing but non-executable path (e.g., a
directory or non-executable file) will still be accepted and then fail later when execFileAsync()
tries to run it inside the per-card loop, recreating the repeated/noisy failures this change aims to
avoid.
Code

scripts/og-render.mjs[R56-64]

+function resolveChrome() {
+    const override = process.env.CHROME_PATH;
+    if (!override) return findChrome();
+    if (!existsSync(override)) {
+        console.error(`og-render: CHROME_PATH is set to "${override}", which does not exist.`);
+        process.exit(1);
+    }
+    return override;
+}
Evidence
The new logic only checks path existence, but the returned chrome value is invoked by
execFileAsync() inside the loop over OG_CARDS, so a non-runnable-but-existing override will
still cause failures during rendering rather than at startup.

scripts/og-render.mjs[51-66]
scripts/og-render.mjs[88-109]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`scripts/og-render.mjs` now fails fast only when `CHROME_PATH` does not exist. If `CHROME_PATH` points to an existing *non-runnable* target (directory, non-executable file, etc.), `resolveChrome()` will accept it and the script will still fail later during the per-card rendering loop.

### Issue Context
The code path returned by `resolveChrome()` is used as the executable passed to `execFileAsync()` once per card.

### Fix Focus Areas
- scripts/og-render.mjs[56-66]
- scripts/og-render.mjs[88-109]

### Suggested fix
In `resolveChrome()`, strengthen validation of `override` before returning it:
- Use `statSync(override)` and require `isFile()`.
- Optionally use `accessSync(override, fs.constants.X_OK)` where supported.
- Or perform a one-time execution probe before entering the card loop (e.g., `await execFileAsync(override, ['--version'])`) and exit with a clear message if it fails.
This preserves the “fail fast” intent for more invalid-but-existing values of `CHROME_PATH`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread scripts/og-render.mjs

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 2 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread scripts/og-render.mjs Outdated
existsSync accepted a directory, and on Windows any readable file, so a wrong
CHROME_PATH still reached the render loop and failed sixteen times over. Check
that it is a file, and that it looks executable: the x bit on unix, an .exe
extension on Windows, where X_OK degrades to a read check that package.json
would pass.

Not a --version probe, which was the obvious alternative: on Windows Chrome
prints no version for it and hands the arguments to the running browser
instead, which opens a tab.

Raised by cubic, Copilot and qodo on #4.
@Sukarth
Sukarth merged commit 000507f into main Jul 29, 2026
4 of 5 checks passed

@coderabbitai coderabbitai 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.

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 `@scripts/og-render.mjs`:
- Around line 46-58: The path inspection in isRunnable and the CHROME_PATH
diagnostics must be exception-safe against files disappearing or becoming
inaccessible between filesystem checks. Guard the combined existence, stat, and
relevant permission inspection in a single try/catch, return false from
isRunnable on any inspection failure, and reuse the guarded result in the
CHROME_PATH diagnostic flow so it still prints the intended message without
propagating filesystem exceptions.
🪄 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: f26aa495-5653-4894-a779-c9ef63a27280

📥 Commits

Reviewing files that changed from the base of the PR and between 486078f and be29dc0.

📒 Files selected for processing (2)
  • scripts/og-preview.mjs
  • scripts/og-render.mjs
💤 Files with no reviewable changes (1)
  • scripts/og-preview.mjs

Comment thread scripts/og-render.mjs
Comment on lines +46 to +58
function isRunnable(path) {
if (!existsSync(path) || !statSync(path).isFile()) return false;
// The executable bit only means something on unix. Windows does not set it,
// and X_OK there degrades to a read check that any readable file passes, so
// go by extension instead: it is the nearest thing Windows has to "this can
// be run", and it is what rejects a path like package.json.
if (process.platform === 'win32') return extname(path).toLowerCase() === '.exe';
try {
accessSync(path, constants.X_OK);
return true;
} catch {
return false;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file excerpt =="
sed -n '1,140p' scripts/og-render.mjs | cat -n

echo
echo "== relevant symbols =="
rg -n "existsSync|statSync|accessSync|function isRunnable|function resolveChrome|CHROME_PATH|CHROME" scripts/og-render.mjs

Repository: Sukarth/IB-EconGraph-AI

Length of output: 7592


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Node filesystem access APIs availability =="
node - <<'JS'
const fs = require('node:fs');
console.log('version:', process.version);
console.log('existsSync:', typeof fs.existsSync);
console.log('existsSyncSync:', typeof fs.existsSyncSync ?? 'undefined');
try {
  fs.existsSyncSync('/tmp');
} catch (err) {
  console.log('existsSyncSync throws:', err.constructor.name);
}
JS

echo
echo "== deterministic probe: separate statSync calls can throw after a path race =="
node - <<'JS'
const { mkdtempSync, writeFileSync, rmSync } = require('node:fs');
const { join } = require('node:path');
const { tmpdir } = require('node:os');

const dir = mkdtempSync(join(tmpdir(), 'crab-race-'));
const file = join(dir, 'probe');
writeFileSync(file, 'x');

function isRunnable(path) {
  if (!fs.existsSync(path) || !fs.statSync(path).isFile()) return false;
  try {
    fs.accessSync(path, fs.constants.X_OK);
    return true;
  } catch {
    return false;
  }
}

try {
  const result = fs.existsSyncSync && isRunnable(file);
  console.log('existsSyncSync-isRunnable result:', result);
} catch (err) {
  console.log('existsSyncSync-isRunnable threw:', err.code, err.message.split('\n')[0]);
}

rmSync(dir, { recursive: true, force: true });
JS

Repository: Sukarth/IB-EconGraph-AI

Length of output: 447


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== deterministic Node probe with current module-scope imports =="
node - <<'JS'
const { existsSync, statSync } = require('node:fs');

function isRunnable(path) {
  if (!existsSync(path) || !statSync(path).isFile()) return false;
  return true;
}

const { mkdtempSync, writeFileSync, rmSync } = require('node:fs');
const { join } = require('node:path');
const { tmpdir } = require('node:os');

const dir = mkdtempSync(join(tmpdir(), 'crab-race-'));
const file = join(dir, 'probe');
writeFileSync(file, 'x');

try {
  const result = isRunnable(file);
  console.log('existsSync-statSync-isRunnable result:', result);
} catch (err) {
  console.log('existsSync-statSync-isRunnable threw:', err.code, err.message.split('\n')[0]);
}

rmSync(dir, { recursive: true, force: true });
JS

echo
echo "== relevant statSync call sites after line 140 =="
sed -n '140,190p' scripts/og-render.mjs | cat -n

Repository: Sukarth/IB-EconGraph-AI

Length of output: 1047


Make path inspection exception-safe.

isRunnable() and the CHROME_PATH diagnostics use separate existsSync()/statSync() checks. If the file disappears or becomes inaccessible between checks, Node throws instead of returning false or printing the intended CHROME_PATH diagnostic. Use a guarded filesystem inspection and reuse that result/reason.

Also applies to lines 81-88.

🤖 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 `@scripts/og-render.mjs` around lines 46 - 58, The path inspection in
isRunnable and the CHROME_PATH diagnostics must be exception-safe against files
disappearing or becoming inaccessible between filesystem checks. Guard the
combined existence, stat, and relevant permission inspection in a single
try/catch, return false from isRunnable on any inspection failure, and reuse the
guarded result in the CHROME_PATH diagnostic flow so it still prints the
intended message without propagating filesystem exceptions.

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