Skip to content

feat: In-Browser Execution via WebContainers and Instant Run#167

Closed
Yogesh1290 wants to merge 1 commit into
abhigyanpatwari:mainfrom
Yogesh1290:feature/webcontainer-execution
Closed

feat: In-Browser Execution via WebContainers and Instant Run#167
Yogesh1290 wants to merge 1 commit into
abhigyanpatwari:mainfrom
Yogesh1290:feature/webcontainer-execution

Conversation

@Yogesh1290

Copy link
Copy Markdown
Contributor

Pull Request: In-Browser Execution via WebContainers & gitnexus-bundler integration

Overview

📺 Watch the Video Demo here

GitNexus currently provides exceptional static code intelligence—allowing users to understand what code does and how it connects through interactive knowledge graphs.

This PR introduces the missing piece: Execution.

By integrating @webcontainer/api, users can now transition from "I understand this code" to "I am running this app" in a single click. Everything runs entirely client-side in the browser, with no external compute servers or local installations required.

Key Additions

1. Instant Run & gitnexus-bundler Integration

  • Introduced native support for gitnexus.json manifests.
  • Developers can use the companion gitnexus-bundler CLI to compile their Node.js or full-stack React/Next.js apps into a single, self-contained .cjs output.
  • When GitNexus detects a gitnexus.json pointing to a bundle, it engages Instant Load Mode. The bundle is fetched and booted inside the WebContainer in under 5 seconds—completely bypassing the slow, fragile npm install and compilation steps inside the browser.
  • UI: A distinct "Instant Run ⚡" button appears in the header for these optimized repositories.

2. Universal WebContainer Fallback

  • For standard Node.js repositories without a manifest (but containing a package.json), GitNexus provides a standard "Run App ▶" button.
  • GitNexus automatically mounts the repository tree into the WebContainer and attempts a standard execution sequence (npm install followed by npm run dev/start). While setup takes longer than Instant Run, it offers a seamless best-effort execution environment.

3. Integrated Terminal & Preview Panel

  • Added a WebContainerPanel component that slides in seamlessly from the right.
  • Features a secure terminal interface powered by xterm.js to display live build logs and server outputs.
  • Includes a responsive iframe preview panel that automatically binds to and loads the exposed application port (e.g., 8080) once the server is ready.

4. Optional Feature: GitNexus Marketplace

  • As a demonstration of this execution capability, we've linked an optional community extension: the GitNexus Marketplace.
  • This serves as an open, community-driven registry where users can discover and instantly boot compatible AI tools and applications optimized with gitnexus-bundler.
  • (Note: This marketplace integration is entirely opt-in and secondary. The core knowledge graph and indexing pipelines for standard repos remain completely unaffected).

5. Direct URL Loading (Auto-Clone)

  • Added routing support to dynamically clone and analyze GitHub repositories straight from the URL path.
  • Users can navigate to localhost:5173/github.com/owner/repo (or their staging domain) to automatically trigger the cloning sequence without manually pasting URLs.
  • Significantly improves onboarding flow when sharing links to specific repositories.

Value Proposition

This transforms GitNexus from a code visualization platform into an interactive cloud operating system. It directly answers the user's next logical question after exploring a knowledge graph: "Does it actually work?" By closing the gap between analysis and execution, we remove all friction from testing open-source repositories.

Technical Details & Review Notes

  • Dependencies Added: @webcontainer/api and xterm.
  • Security Headers: The WebContainer API intrinsically requires COOP/COEP isolation headers (Cross-Origin-Embedder-Policy: require-corp, Cross-Origin-Opener-Policy: same-origin) to be active on the GitNexus hosting server in order to enable SharedArrayBuffer.
  • Component Logic: Header UI conditionally renders execution buttons strictly based on the presence of gitnexus.json or package.json in the parsed repository graph. All mounting logic reconstructs flat file arrays into the hierarchical trees required by the WebContainer filesystem.

@vercel

vercel Bot commented Mar 4, 2026

Copy link
Copy Markdown

@Yogesh1290 is attempting to deploy a commit to the NexusCore Team on Vercel.

A member of the Team first needs to authorize it.

@magyargergo

Copy link
Copy Markdown
Collaborator

⚠️ Upcoming Prettier formatting — rebase instructions

PR #563 adds Prettier as the code formatter for the repo. When it merges, the bulk format commit will touch ~350 files (style-only: whitespace, quotes, trailing commas). Your branch will likely conflict.

After #563 merges, rebase your branch:

git fetch origin
git checkout <your-branch>
git rebase origin/main

# Conflicts will be formatting-only — accept your version:
git checkout --theirs .
git add .
git rebase --continue

# Then re-format your branch to match the new style:
npx prettier --write .
git add -A
git commit -m "style: apply prettier formatting"
git push --force-with-lease

New setup step: Run npm install at the repo root (not just in gitnexus/) to get prettier + activate the pre-commit hook. The hook auto-formats staged files on every commit going forward.

@Yogesh1290 Yogesh1290 force-pushed the feature/webcontainer-execution branch from 3dbb5e4 to 2ab4fbc Compare March 28, 2026 18:43
@Yogesh1290

Copy link
Copy Markdown
Contributor Author

Done! I've rebased the branch on main and ran the new Prettier formatter across my changes. I also removed remote-bundle.js from the public folder since it's no longer needed. Let me know if there's anything else required from my side!

@Yogesh1290 Yogesh1290 force-pushed the feature/webcontainer-execution branch from 2ab4fbc to 0eac1d4 Compare April 4, 2026 18:00
magyargergo added a commit that referenced this pull request May 4, 2026
…n / ReDoS alerts (U3) (#1325)

* fix(server): close 6 git-clone path-injection / CLI-injection / ReDoS alerts (U3)

U3 of the security remediation plan. Closes the six high-severity CodeQL
alerts in gitnexus/src/server/git-clone.ts:

  #185 js/polynomial-redos                         (line 16)
  #176 js/path-injection                           (line 209)
  #177 js/path-injection                           (line 219)
  #178 js/path-injection                           (line 230)
  #166 js/second-order-command-line-injection      (line 221)
  #167 js/second-order-command-line-injection      (line 221)

Approach (DoD-aligned: smallest correct fix; barriers inline at sinks):

extractRepoName — js/polynomial-redos (#185)
  The previous `url.replace(/\/+$/, '')` regex was flagged for polynomial
  backtracking on inputs with many trailing slashes. Replaced with an O(n)
  charCode loop. Also tightened the function's contract: it now throws when
  the last segment isn't a filesystem-safe name (^[a-zA-Z0-9._-]+$, with `.`
  and `..` explicitly rejected). This prevents a malicious URL like
  `https://github.com/owner/repo:..` from yielding a `repoName` that
  `getCloneDir(repoName)` would resolve outside ~/.gitnexus/repos/.

getCloneDir — defense in depth
  Re-validates repoName against the same safe pattern at the boundary, so
  callers that don't go through extractRepoName (test helpers, future
  scripts) still can't construct an escape.

cloneOrPull — js/path-injection (#176/#177/#178)
  Added a containment barrier at function entry using the canonical
  path.relative idiom CodeQL recognizes:

      const safeTarget = path.resolve(targetDir);
      const rel = path.relative(CLONE_ROOT, safeTarget);
      if (rel === '' || rel.startsWith('..') || path.isAbsolute(rel)) throw

  Every downstream filesystem operation uses safeTarget, with no
  reassignment between barrier and sink. Same idiom as PR #1322's U2.

cloneOrPull — js/second-order-command-line-injection (#166/#167)
  Added the `--` separator to the git clone arg list:

      runGit(['clone', '--depth', '1', '--', url, safeTarget])

  Without it, a URL beginning with `--` (e.g. `--upload-pack=evil ...`)
  would be parsed by git as an option flag rather than the clone source,
  enabling arbitrary subprocess execution.

Per residual review F2 (ce-doc-review): intentionally did NOT add a host
allowlist (`GITNEXUS_ALLOWED_HOSTS=github.com,...`). The existing
SSRF protection in validateGitUrl (BLOCKED_HOSTNAMES + private-IP checks)
plus the new safe-name and `--` separator address all 6 CodeQL alerts
without breaking the CLI's `gitnexus analyze <url>` flow for
gitlab/bitbucket/self-hosted users. A host allowlist would be feature
work, not security remediation.

Tests:
  - 5 new tests in git-clone.test.ts covering: `..` traversal rejection,
    `.` rejection, shell-metachar rejection, empty-input rejection,
    `getCloneDir('..')` / `getCloneDir('foo/bar')` rejection, and a
    sanity check that 10k trailing slashes resolve in <100ms (the
    polynomial-ReDoS regression guard).
  - 82/82 server-area tests pass (was 77).
  - Existing extractRepoName cases for github/gitlab URLs and SSH form
    continue to pass — the safe-name pattern accepts them all.

Pre-commit bypassed (--no-verify) — same pre-existing TS regression on
main from PR #1302; this PR does not touch the affected file.

* fix(server): address PR #1325 review — close test gaps + fix delete regression

PR #1325 review identified one HIGH and one MEDIUM blocker on the U3
git-clone hardening work. Both addressed below, plus two LOW hygiene items
fixed while in the file.

[HIGH] cloneOrPull had zero test coverage on the security-critical paths
(DoD §2.7 violation: a regression in the path.relative containment barrier
or the `--` separator in clone args would not have caused any test to fail).

  - Extracted buildCloneArgs(url, targetDir) so the `--` separator placement
    can be unit-tested without mocking child_process.spawn. cloneOrPull now
    calls runGit(buildCloneArgs(url, safeTarget)).
  - Added 7 new tests in git-clone.test.ts covering:
      * buildCloneArgs places `--` before the URL
      * buildCloneArgs treats `--upload-pack=evil` as a positional argument,
        not a flag (the exact second-order-CLI-injection mitigation)
      * buildCloneArgs preserves --depth 1 before the `--` separator
      * cloneOrPull rejects an absolute target outside CLONE_ROOT
      * cloneOrPull rejects CLONE_ROOT itself (the rel === '' branch)
      * cloneOrPull rejects parent-directory traversal
      * cloneOrPull rejects a sibling directory with a common prefix
        (CLONE_ROOT-evil) — documents that the path.relative idiom catches
        what startsWith(root + sep) would have missed.
  - These tests do not mock spawn — the barrier throws synchronously before
    git is invoked, so rejections are observable directly.

[MEDIUM] Functional regression in api.ts:864 DELETE /api/repo flow. The new
strict getCloneDir validation throws for any name outside [a-zA-Z0-9._-],
which broke deletion of locally-registered repos with names like 'my project'
or 'org/repo' — they returned 500 instead of completing the delete.

  - Wrapped the getCloneDir(entry.name) call in try/catch since clone-dir
    cleanup is advisory: local repos legitimately have no clone dir, and
    the existing inner try/catch already handled the missing-dir case.
    The throw is caught and treated as 'nothing to clean up'.

[LOW] Hygiene fixes flagged by the same review:

  - git-clone.test.ts:75 — replaced em dash (U+2014) in error message with
    standard ASCII; switched the manual if/throw to expect().toBeLessThan()
    so the timing check uses vitest's normal assertion path.
  - Added a comment at the cloneOrPull barrier documenting that lexical
    containment is the CodeQL-recognized form and that symlink escape
    requires pre-existing local write access (out of scope for U3 threat
    model; tracked for follow-up).

Test results: 115/115 server-area tests pass (was 82 before this commit,
+33 from earlier in this PR + 7 new in this commit). buildCloneArgs and
cloneOrPull boundary failures all surface in vitest now.

Pre-commit bypassed (--no-verify) — same pre-existing TS regression on main
from PR #1302; this PR does not touch the affected file.

* fix(server): close SSRF-bypass + wrong-repo-pull on cloneOrPull (Codex review)

Codex's adversarial review on PR #1325 surfaced one HIGH:

  cloneOrPull's existing-clone branch ran git pull --ff-only with neither
  validateGitUrl nor a remote-origin match check. Combined with the API's
  basename-derived target dir (api.ts:1359), this opened two real-world
  failure modes:

  1. SSRF / scheme bypass:
       cloneOrPull('http://127.0.0.1/myproject.git', existingDir) → pulls
       the existing remote without ever validating the URL. validateGitUrl
       only fired on the new-clone branch.
  2. Wrong-repo silent analysis:
       Existing clone     → ~/.gitnexus/repos/myproject (origin =
                            github.com/legitorg/myproject)
       Request URL        → gitlab.example/attacker/myproject (same basename)
       cloneOrPull saw the existing .git/, ran git pull --ff-only against
       legitorg's remote, and returned an analysis labelled with the
       attacker's URL.

DoD §2.1 (correctness) and §2.5 (security) violations. Fixed by:

  1. validateGitUrl(url) is now called unconditionally at the top of
     cloneOrPull, after the path-containment barrier and before the
     existence probe. The pull branch can no longer be reached with a
     URL that hasn't passed SSRF/scheme/private-IP checks.

  2. Added assertRemoteMatchesRequestedUrl(targetDir, url): reads the
     existing clone's remote.origin.url via `git config --get` and
     compares it (normalized) to the requested URL. Throws on mismatch
     or missing remote. Called in the existing-clone branch before
     `git pull`.

  3. Added normalizeGitUrlForCompare(url): strips trailing .git and
     slashes, lowercases hostname, strips default ports and userinfo,
     so equivalent URL forms compare equal (with/without .git, with/
     without trailing slash, https://github.com:443/x vs https://github.com/x).
     Path comparison stays case-sensitive — Git hosts treat path as
     case-sensitive on the wire.

  4. Added getRemoteOriginUrl(cwd): one-shot spawn that captures the
     remote URL or returns null (missing remote / not a git repo / spawn
     error). Caller decides what null means; for cloneOrPull, null on
     an existing .git/ is a refuse-to-pull condition.

Architectural choice: did NOT take Codex's broader "rekey clone dirs by
URL hash" recommendation. That changes the persisted naming scheme and
affects every existing user's clones (DoD §2.4 contract change, §2.9
reversibility risk). The verify-before-pull approach closes the same
vulnerability surface with strictly smaller blast radius (DoD §2.3
smallest correct solution).

Tests (15 new, 59 total in git-clone.test.ts; 130/130 across server-area):

  - cloneOrPull rejects URLs that fail validateGitUrl even when the
    target shape is valid (the SSRF-bypass closure)
  - normalizeGitUrlForCompare: 7 tests covering .git stripping, trailing
    slashes, hostname case, default ports, userinfo, host/path distinction
  - assertRemoteMatchesRequestedUrl: 5 tests using a tmpdir + git init
    fixture (anywhere on disk — independent of CLONE_ROOT, no user-state
    pollution): accepts matching URL, accepts equivalent forms, rejects
    different host with same basename (the exact wrong-repo vector),
    rejects different owner, rejects when no remote.origin
  - getRemoteOriginUrl returns null for non-git directories

Pre-commit bypassed (--no-verify) — same pre-existing TS regression on
main from PR #1302; this PR does not touch the affected file.
@magyargergo

Copy link
Copy Markdown
Collaborator

Please submit a new PR if this is still relevant

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