---
title: "Validate GitHub URLs"
description: "Add input validation to the CLI so we never spin up a Sandbox for a URL that isn't a real GitHub repo. A small regex check upfront saves a lot of confused failures downstream."
canonical_url: "https://vercel.com/academy/vercel-sandbox/validate-github-urls"
md_url: "https://vercel.com/academy/vercel-sandbox/validate-github-urls.md"
docset_id: "vercel-academy"
doc_version: "1.0"
last_updated: "2026-05-17T10:02:32.502Z"
content_type: "lesson"
course: "vercel-sandbox"
course_title: "Vercel Sandbox"
prerequisites:  []
---

<agent-instructions>
Vercel Academy — structured learning, not reference docs.
Lessons are sequenced.
Adapt commands to the human's actual environment (OS, package manager, shell, editor) — detect from project context or ask, don't assume.
The lesson shows one path; if the human's project diverges, adapt concepts to their setup.
Preserve the learning goal over literal steps.
Quizzes are pedagogical — engage, don't spoil.
Quiz answers are included for your reference.
</agent-instructions>

# Validate GitHub URLs

# Validate GitHub URLs Before Spending Money

A CLI without input validation is a vending machine that accepts expired coupons, parking tickets, and emotional support receipts. It still tries to do the work, then fails in weird ways.

Worse, in our case "tries to do the work" means spinning up a Sandbox. That costs real time and real money. We'd rather catch a typo before we boot a microVM.

## Outcome

Add a URL validator to the CLI that rejects anything that isn't a GitHub repo URL, and exit early when validation fails.

## Fast Track

1. Write `isValidGitHubRepoUrl(input)` that returns a boolean.
2. Call it at the top of the `action` callback.
3. On failure, log a clear error and `return` before any Sandbox call.

## Hands-on exercise

Open `src/cli.ts` and add a validator above the program setup:

```ts
import { Command } from 'commander';

function isValidGitHubRepoUrl(input: string): boolean {
  return /^https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/?$/.test(input);
}

const program = new Command();

program
  .name('repo-review')
  .description('Clone and review a GitHub repository in a Sandbox')
  .version('0.1.0');

program
  .command('review <repoUrl>')
  .description('Run a Sandbox review against a GitHub repository URL')
  .action(async (repoUrl: string) => {
    if (!isValidGitHubRepoUrl(repoUrl)) {
      console.error(`Invalid GitHub repository URL: ${repoUrl}`);
      console.error('Expected format: https://github.com/<owner>/<repo>');
      return;
    }

    console.log(`Would review: ${repoUrl}`);
  });

program.parse();
```

The regex is intentionally narrow. It matches the standard GitHub web URL (`https://github.com/owner/repo` with an optional trailing slash) and nothing else. We're not trying to support every Git URL format on earth, we're trying to keep junk out of our pipeline.

We're also returning early instead of throwing. Throwing would crash the Node process with an unhandled rejection, which is loud but not helpful. We'll wire up real exit codes in lesson 2.4. For now, "log and return" is enough.

\*\*Warning: Troubleshooting: valid URLs being rejected\*\*

If a real repo URL fails validation, try it with and without a trailing slash. The regex allows both, but typos like `https://github.com//owner/repo` (double slash) or `http://` (no `s`) will be rejected. That's the regex doing its job.

\*\*Note: Troubleshooting: pattern too strict\*\*

If you want to support GitHub Enterprise URLs (`https://github.mycompany.com/...`), you'll need a different regex. For this course, public GitHub only.

## Try It

Run an invalid URL:

```bash
pnpm review not-a-url
```

Expected output:

```txt
Invalid GitHub repository URL: not-a-url
Expected format: https://github.com/<owner>/<repo>
```

Then a valid one:

```bash
pnpm review https://github.com/vercel/examples
```

Expected output:

```txt
Would review: https://github.com/vercel/examples
```

Same valid output as last lesson, plus a guardrail at the front door.

## Commit

```bash
git add src/cli.ts
git commit -m "feat(cli): validate GitHub repository URLs before sandbox work"
```

## Done-When

- [ ] `isValidGitHubRepoUrl` returns `true` for `https://github.com/owner/repo` (with or without trailing slash)
- [ ] `isValidGitHubRepoUrl` returns `false` for plain strings, non-GitHub hosts, and malformed URLs
- [ ] Invalid URLs print a clear error message
- [ ] Valid URLs reach the `console.log` line

## Solution

```ts title="src/cli.ts"
import { Command } from 'commander';

function isValidGitHubRepoUrl(input: string): boolean {
  return /^https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/?$/.test(input);
}

const program = new Command();

program
  .name('repo-review')
  .description('Clone and review a GitHub repository in a Sandbox')
  .version('0.1.0');

program
  .command('review <repoUrl>')
  .description('Run a Sandbox review against a GitHub repository URL')
  .action(async (repoUrl: string) => {
    if (!isValidGitHubRepoUrl(repoUrl)) {
      console.error(`Invalid GitHub repository URL: ${repoUrl}`);
      console.error('Expected format: https://github.com/<owner>/<repo>');
      return;
    }

    console.log(`Would review: ${repoUrl}`);
  });

program.parse();
```


---

[Full course index](/academy/llms.txt) · [Sitemap](/academy/sitemap.md)
