import { describe, it, expect } from 'vitest';
import { validateUrl } from './skills-git-install.js';

describe('validateUrl', () => {
  it('accepts a normal https git URL', () => {
    expect(validateUrl('https://github.com/owner/repo')).toBeNull();
    expect(validateUrl('https://gitea.example.com/team/skills.git')).toBeNull();
  });

  it('rejects non-https schemes', () => {
    expect(validateUrl('http://github.com/o/r')).toMatch(/https/);
    expect(validateUrl('ssh://git@github.com/o/r')).toMatch(/https/);
    expect(validateUrl('file:///etc/passwd')).toMatch(/https/);
    expect(validateUrl('git://github.com/o/r')).toMatch(/https/);
  });

  it('rejects empty / non-string input', () => {
    expect(validateUrl('')).toMatch(/required/);
    // @ts-expect-error intentional bad input
    expect(validateUrl(undefined)).toMatch(/required/);
  });

  // Regression: shell command injection via the git URL.
  // Previously only [;&|`$] were blocked, so a double-quote + newline could
  // break out of `git clone "${url}"` and run an arbitrary command.
  it('rejects newline + quote command-injection payloads', () => {
    expect(validateUrl('https://x"\nid #')).toMatch(/disallowed|control/);
    expect(validateUrl('https://x"\r\ntouch /tmp/pwned')).toMatch(/disallowed|control/);
    expect(validateUrl('https://github.com/o/r"; rm -rf ~ #')).toMatch(/disallowed/);
  });

  it('rejects shell metacharacters and whitespace', () => {
    for (const bad of ['https://x;id', 'https://x|id', 'https://x&&id', 'https://x`id`', 'https://x$(id)', "https://x'", 'https://a b', 'https://x<y']) {
      expect(validateUrl(bad)).toMatch(/disallowed/);
    }
  });

  it('rejects control characters', () => {
    expect(validateUrl('https://x\x00y')).toMatch(/control|disallowed/);
  });

  it('rejects strings that pass the prefix but are not valid URLs', () => {
    // No host after the scheme.
    expect(validateUrl('https://')).not.toBeNull();
  });
});
