Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: handle broken symlinks #1329

Merged
merged 2 commits into from
Aug 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/cli/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ alias.t = 'test';
const DEBUG_DEFAULT_NAMESPACES = [
'snyk-test',
'snyk',
'snyk:find-files',
'snyk:run-test',
'snyk:prune',
'snyk-gradle-plugin',
'snyk-sbt-plugin',
'snyk-mvn-plugin',
Expand Down
39 changes: 24 additions & 15 deletions src/lib/find-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as pathLib from 'path';
import * as _ from '@snyk/lodash';
import { detectPackageManagerFromFile } from './detect';
import * as debugModule from 'debug';
const debug = debugModule('snyk');
const debug = debugModule('snyk:find-files');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like this, we should do this for more debugs


// TODO: use util.promisify once we move to node 8

Expand Down Expand Up @@ -78,6 +78,7 @@ export async function find(
found.push(fileFound);
}
}

return filterForDefaultManifests(found);
} catch (err) {
throw new Error(`Error finding files in path '${path}'.\n${err.message}`);
Expand Down Expand Up @@ -107,6 +108,10 @@ async function findInDirectory(
.filter((file) => !ignore.includes(file))
.map((file) => {
const resolvedPath = pathLib.resolve(path, file);
if (!fs.existsSync(resolvedPath)) {
debug('File does not seem to exist, skipping: ', file);
return [];
}
return find(resolvedPath, ignore, filter, levelsDeep);
});
const found = await Promise.all(toFind);
Expand All @@ -124,6 +129,7 @@ function filterForDefaultManifests(files: string[]): string[] {

const foundFiles = _(files)
.filter(Boolean)
.filter((p) => fs.existsSync(p))
.map((p) => ({
path: p,
...pathLib.parse(p),
Expand All @@ -136,6 +142,7 @@ function filterForDefaultManifests(files: string[]): string[] {
for (const directory of Object.keys(foundFiles)) {
const filesInDirectory = foundFiles[directory];
const groupedFiles = _(filesInDirectory)
.filter((p) => !!p.packageManager)
.groupBy('packageManager')
.value();

Expand Down Expand Up @@ -217,52 +224,54 @@ function chooseBestManifest(
const lockFile = files.filter((path) =>
['package-lock.json', 'yarn.lock'].includes(path.base),
)[0];
debug(
`Encountered multiple node lockfiles files, defaulting to ${lockFile.path}`,
);
if (lockFile) {
debug(
'Encountered multiple npm manifest files, defaulting to package-lock.json / yarn.lock',
);
return lockFile.path;
}
const packageJson = files.filter((path) =>
['package.json'].includes(path.base),
)[0];
debug(
'Encountered multiple npm manifest files, defaulting to package.json',
`Encountered multiple npm manifest files, defaulting to ${packageJson.path}`,
);
return packageJson.path;
}
case 'rubygems': {
debug(
'Encountered multiple gem manifest files, defaulting to Gemfile.lock',
);
const defaultManifest = files.filter((path) =>
['Gemfile.lock'].includes(path.base),
)[0];
debug(
`Encountered multiple gem manifest files, defaulting to ${defaultManifest.path}`,
);
return defaultManifest.path;
}
case 'cocoapods': {
debug(
'Encountered multiple cocoapods manifest files, defaulting to Podfile',
);
const defaultManifest = files.filter((path) =>
['Podfile'].includes(path.base),
)[0];
debug(
`Encountered multiple cocoapods manifest files, defaulting to ${defaultManifest.path}`,
);
return defaultManifest.path;
}
case 'pip': {
debug('Encountered multiple pip manifest files, defaulting to Pipfile');
const defaultManifest = files.filter((path) =>
['Pipfile'].includes(path.base),
)[0];
debug(
`Encountered multiple pip manifest files, defaulting to ${defaultManifest.path}`,
);
return defaultManifest.path;
}
case 'gradle': {
debug(
'Encountered multiple gradle manifest files, defaulting to build.gradle',
);
const defaultManifest = files.filter((path) =>
['build.gradle'].includes(path.base),
)[0];
debug(
`Encountered multiple gradle manifest files, defaulting to ${defaultManifest.path}`,
);
return defaultManifest.path;
}
default: {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/snyk-test/run-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ import * as alerts from '../alerts';
import { abridgeErrorMessage } from '../error-format';
import { getDockerToken } from '../api-token';

const debug = debugModule('snyk');
const debug = debugModule('snyk:run-test');

const ANALYTICS_PAYLOAD_MAX_LENGTH = 1024;

Expand Down
39 changes: 14 additions & 25 deletions test/find-files.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ test('find all files in test fixture', async (t) => {
// six levels deep to find all
const result = await find(testFixture, [], [], 6);
const expected = [
path.join(testFixture, 'README.md'),
path.join(
testFixture,
'golang',
Expand All @@ -17,32 +16,27 @@ test('find all files in test fixture', async (t) => {
'vendor.json',
),
path.join(testFixture, 'golang', 'golang-app', 'Gopkg.lock'),
path.join(testFixture, 'golang', 'golang-app', 'Gopkg.toml'),
path.join(testFixture, 'golang', 'golang-gomodules', 'go.mod'),
path.join(testFixture, 'gradle', 'build.gradle'),
path.join(testFixture, 'gradle-kts', 'build.gradle.kts'),
path.join(testFixture, 'gradle-and-kotlin', 'build.gradle'),
path.join(testFixture, 'gradle-multiple', 'gradle/build.gradle'),
path.join(testFixture, 'gradle-multiple', 'gradle-another/build.gradle'),
path.join(testFixture, 'maven', 'pom.xml'),
path.join(testFixture, 'maven', 'test.txt'),
path.join(testFixture, 'npm-with-lockfile', 'package-lock.json'),
path.join(testFixture, 'mvn', 'pom.xml'),
path.join(testFixture, 'mvn', 'test.txt'),
path.join(testFixture, 'npm', 'package.json'),
path.join(testFixture, 'npm', 'test.txt'),
path.join(testFixture, 'ruby', 'Gemfile.lock'),
path.join(testFixture, 'ruby', 'test.txt'),
path.join(testFixture, 'yarn', 'yarn.lock'),
].sort();
t.same(result.sort(), expected, 'should return all files');
];
t.same(result.length, expected.length, 'should be the same length');
t.same(result.sort(), expected.sort(), 'should return all files');
});

test('find all files in test fixture ignoring node_modules', async (t) => {
// six levels deep to ensure node_modules is tested
const result = await find(testFixture, ['node_modules'], [], 6);
const expected = [
path.join(testFixture, 'README.md'),
path.join(
testFixture,
'golang',
Expand All @@ -51,33 +45,28 @@ test('find all files in test fixture ignoring node_modules', async (t) => {
'vendor.json',
),
path.join(testFixture, 'golang', 'golang-app', 'Gopkg.lock'),
path.join(testFixture, 'golang', 'golang-app', 'Gopkg.toml'),
path.join(testFixture, 'golang', 'golang-gomodules', 'go.mod'),
path.join(testFixture, 'gradle', 'build.gradle'),
path.join(testFixture, 'gradle-kts', 'build.gradle.kts'),
path.join(testFixture, 'gradle-and-kotlin', 'build.gradle'),
path.join(testFixture, 'gradle-multiple', 'gradle/build.gradle'),
path.join(testFixture, 'gradle-multiple', 'gradle-another/build.gradle'),
path.join(testFixture, 'maven', 'pom.xml'),
path.join(testFixture, 'maven', 'test.txt'),
path.join(testFixture, 'mvn', 'pom.xml'),
path.join(testFixture, 'mvn', 'test.txt'),
path.join(testFixture, 'npm-with-lockfile', 'package-lock.json'),
path.join(testFixture, 'npm', 'package.json'),
path.join(testFixture, 'npm', 'test.txt'),
path.join(testFixture, 'ruby', 'Gemfile.lock'),
path.join(testFixture, 'ruby', 'test.txt'),
path.join(testFixture, 'yarn', 'yarn.lock'),
].sort();
t.same(result.sort(), expected, 'should return expected files');
];
t.same(result.sort(), expected.sort(), 'should return expected files');
});

test('find package.json file in test fixture ignoring node_modules', async (t) => {
// six levels deep to ensure node_modules is tested
const nodeModulesPath = path.join(testFixture, 'node_modules');
const result = await find(nodeModulesPath, [], ['package.json'], 6);
const expected = [];
t.same(result, expected, 'should return expected file');
t.same(result.sort(), expected.sort(), 'should return expected file');
});

test('find package.json file in test fixture (by default ignoring node_modules)', async (t) => {
Expand All @@ -88,7 +77,7 @@ test('find package.json file in test fixture (by default ignoring node_modules)'
path.join(testFixture, 'npm-with-lockfile', 'package.json'),
path.join(testFixture, 'yarn', 'package.json'),
];
t.same(result, expected, 'should return expected file');
t.same(result.sort(), expected.sort(), 'should return expected file');
});

test('find package-lock.json file in test fixture (ignore package.json in the same folder)', async (t) => {
Expand All @@ -101,7 +90,7 @@ test('find package-lock.json file in test fixture (ignore package.json in the sa
1,
);
const expected = [path.join(npmLockfilePath, 'package-lock.json')];
t.same(result, expected, 'should return expected file');
t.same(result.sort(), expected.sort(), 'should return expected file');
});

test('find build.gradle file in test fixture (ignore build.gradle in the same folder)', async (t) => {
Expand All @@ -114,7 +103,7 @@ test('find build.gradle file in test fixture (ignore build.gradle in the same fo
1,
);
const expected = [path.join(buildGradle, 'build.gradle')];
t.same(result, expected, 'should return expected file');
t.same(result.sort(), expected.sort(), 'should return expected file');
});

test('find Gemfile.lock file in test fixture (ignore Gemfile in the same folder)', async (t) => {
Expand All @@ -127,7 +116,7 @@ test('find Gemfile.lock file in test fixture (ignore Gemfile in the same folder)
1,
);
const expected = [path.join(npmLockfilePath, 'Gemfile.lock')];
t.same(result, expected, 'should return expected file');
t.same(result.sort(), expected.sort(), 'should return expected file');
});

test('find yarn.lock file in test fixture (ignore package.json in the same folder)', async (t) => {
Expand All @@ -140,7 +129,7 @@ test('find yarn.lock file in test fixture (ignore package.json in the same folde
1,
);
const expected = [path.join(yarnLockfilePath, 'yarn.lock')];
t.same(result, expected, 'should return expected file');
t.same(result.sort(), expected.sort(), 'should return expected file');
});

test('find package.json file in test fixture (by default ignoring node_modules)', async (t) => {
Expand All @@ -151,21 +140,21 @@ test('find package.json file in test fixture (by default ignoring node_modules)'
path.join(testFixture, 'npm-with-lockfile', 'package.json'),
path.join(testFixture, 'yarn', 'package.json'),
];
t.same(result, expected, 'should return expected file');
t.same(result.sort(), expected.sort(), 'should return expected file');
});

test('find Gemfile file in test fixture', async (t) => {
const result = await find(testFixture, [], ['Gemfile']);
const expected = [path.join(testFixture, 'ruby', 'Gemfile')];
t.same(result, expected, 'should return expected file');
t.same(result.sort(), expected.sort(), 'should return expected file');
});

test('find pom.xml files in test fixture', async (t) => {
const result = await find(testFixture, [], ['pom.xml']);
const expected = [
path.join(testFixture, 'maven', 'pom.xml'),
path.join(testFixture, 'mvn', 'pom.xml'),
].sort();
];
t.same(result.sort(), expected, 'should return expected files');
});

Expand Down
1 change: 1 addition & 0 deletions test/fixtures/find-files/broken-symlink