diff --git a/package.json b/package.json index 240b6a4d1c..f1b0e29d77 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,6 @@ "cli-spinner": "0.2.10", "debug": "^3.1.0", "diff": "^4.0.1", - "git-url-parse": "11.1.2", "glob": "^7.1.3", "needle": "^2.2.4", "open": "^7.0.3", diff --git a/src/lib/project-metadata/target-builders/git.ts b/src/lib/project-metadata/target-builders/git.ts index d36e2618c1..a2238958ff 100644 --- a/src/lib/project-metadata/target-builders/git.ts +++ b/src/lib/project-metadata/target-builders/git.ts @@ -1,10 +1,12 @@ -import gitUrlParse = require('git-url-parse'); - +import * as url from 'url'; import subProcess = require('../../sub-process'); import { DepTree } from '../../types'; import { GitTarget } from '../types'; import { ScannedProject } from '@snyk/cli-interface/legacy/common'; +// for scp-like syntax [user@]server:project.git +const originRegex = /(.+@)?(.+):(.+$)/; + export async function getInfo( scannedProject: ScannedProject, packageInfo: DepTree, @@ -23,8 +25,21 @@ export async function getInfo( ).trim(); if (origin) { - const parsedOrigin = gitUrlParse(origin); - target.remoteUrl = parsedOrigin.toString('http'); + const { protocol, host, pathname = '' } = url.parse(origin); + + // Not handling git:// as it has no connection options + if (host && protocol && ['ssh:', 'http:', 'https:'].includes(protocol)) { + // same format for parseable URLs + target.remoteUrl = `http://${host}${pathname}`; + } else { + const originRes = originRegex.exec(origin); + if (originRes && originRes[2] && originRes[3]) { + target.remoteUrl = `http://${originRes[2]}/${originRes[3]}`; + } else { + // else keep the original + target.remoteUrl = origin; + } + } } } catch (err) { // Swallowing exception since we don't want to break the monitor if there is a problem diff --git a/test/get-remote-url.test.ts b/test/get-remote-url.test.ts new file mode 100644 index 0000000000..ebde2e3979 --- /dev/null +++ b/test/get-remote-url.test.ts @@ -0,0 +1,123 @@ +import { test } from 'tap'; +import * as Proxyquire from 'proxyquire'; +const proxyquire = Proxyquire.noPreserveCache(); + +test('getInfo returns null for isFromContainer=true', async (t) => { + const { + getInfo, + } = require('../src/lib/project-metadata/target-builders/git'); + const gitInfo = await getInfo(null as any, null as any, true); + t.same(gitInfo, null); +}); + +test('getInfo handles provided https remote url as http', async (t) => { + const providedUrl = 'https://myserver.local/myproject.git'; + const { getInfo } = proxyquire( + '../src/lib/project-metadata/target-builders/git', + { + '../../sub-process': { + execute() { + return providedUrl; + }, + }, + }, + ); + const gitInfo = await getInfo(null as any, null as any, false); + t.same(gitInfo.remoteUrl, 'http://myserver.local/myproject.git'); +}); + +test('getInfo handles provided http remote url', async (t) => { + const providedUrl = 'http://github.com/snyk/snyk.git'; + const { getInfo } = proxyquire( + '../src/lib/project-metadata/target-builders/git', + { + '../../sub-process': { + execute() { + return providedUrl; + }, + }, + }, + ); + const gitInfo = await getInfo(null as any, null as any, false); + t.same(gitInfo.remoteUrl, providedUrl); +}); + +test('getInfo handles provided ssh remote url as http', async (t) => { + const providedUrl = 'ssh://git@myserver.local/myproject.git'; + const { getInfo } = proxyquire( + '../src/lib/project-metadata/target-builders/git', + { + '../../sub-process': { + execute() { + return providedUrl; + }, + }, + }, + ); + const gitInfo = await getInfo(null as any, null as any, false); + t.same(gitInfo.remoteUrl, 'http://myserver.local/myproject.git'); +}); + +test('getInfo handles provided scp-like syntax with user in remote url', async (t) => { + const providedUrl = 'git@myserver.local:myproject.git'; + const { getInfo } = proxyquire( + '../src/lib/project-metadata/target-builders/git', + { + '../../sub-process': { + execute() { + return providedUrl; + }, + }, + }, + ); + const gitInfo = await getInfo(null as any, null as any, false); + t.same(gitInfo.remoteUrl, 'http://myserver.local/myproject.git'); +}); + +test('getInfo handles provided scp-like syntax without user in remote url', async (t) => { + const providedUrl = 'myserver.local:folder/myproject.git'; + const { getInfo } = proxyquire( + '../src/lib/project-metadata/target-builders/git', + { + '../../sub-process': { + execute() { + return providedUrl; + }, + }, + }, + ); + const gitInfo = await getInfo(null as any, null as any, false); + t.same(gitInfo.remoteUrl, 'http://myserver.local/folder/myproject.git'); +}); + +test('getInfo handles invalid URL by keeping it as is', async (t) => { + const providedUrl = 'nonce'; + const { getInfo } = proxyquire( + '../src/lib/project-metadata/target-builders/git', + { + '../../sub-process': { + execute() { + return providedUrl; + }, + }, + }, + ); + const gitInfo = await getInfo(null as any, null as any, false); + t.same(gitInfo.remoteUrl, providedUrl); +}); + +test('getInfo handles undefined by returning undefined', async (t) => { + const providedUrl = undefined; + const { getInfo } = proxyquire( + '../src/lib/project-metadata/target-builders/git', + { + '../../sub-process': { + execute() { + return providedUrl; + }, + }, + }, + ); + const gitInfo = await getInfo(null as any, null as any, false); + t.same(gitInfo.remoteUrl, undefined); +});