Vercel Logo

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:

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.

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.

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:

pnpm review not-a-url

Expected output:

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

Then a valid one:

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

Expected output:

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

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

Commit

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

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();

Was this helpful?

supported.