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

feat: [OSM-1040] Added pnpm support under 'enablePnpmCli' feature flag #5181

Merged
merged 4 commits into from May 10, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
502 changes: 487 additions & 15 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -121,7 +121,8 @@
"snyk-gradle-plugin": "4.1.0",
"snyk-module": "3.1.0",
"snyk-mvn-plugin": "3.4.2",
"snyk-nodejs-lockfile-parser": "1.52.11",
"snyk-nodejs-lockfile-parser": "1.56.0",
"snyk-nodejs-plugin": "1.1.0",
"snyk-nuget-plugin": "2.4.5",
"snyk-php-plugin": "1.9.2",
"snyk-policy": "^1.25.0",
Expand Down
1 change: 1 addition & 0 deletions src/cli/args.ts
Expand Up @@ -44,6 +44,7 @@ const DEBUG_DEFAULT_NAMESPACES = [
'snyk-sbt-plugin',
'snyk-mvn-plugin',
'snyk-yarn-workspaces',
'snyk-pnpm-workspaces',
];

function dashToCamelCase(dash) {
Expand Down
27 changes: 21 additions & 6 deletions src/cli/commands/monitor/index.ts
Expand Up @@ -49,6 +49,7 @@ import { getEcosystem, monitorEcosystem } from '../../../lib/ecosystems';
import { getFormattedMonitorOutput } from '../../../lib/ecosystems/monitor';
import { processCommandArgs } from '../process-command-args';
import { hasFeatureFlag } from '../../../lib/feature-flags';
import { PNPM_FEATURE_FLAG } from '../../../lib/package-managers';

const SEPARATOR = '\n-------------------------------------------------------\n';
const debug = Debug('snyk');
Expand Down Expand Up @@ -158,6 +159,12 @@ export default async function monitor(...args0: MethodArgs): Promise<any> {
);
}

const hasPnpmSupport = await hasFeatureFlag(PNPM_FEATURE_FLAG, options);

const featureFlags = hasPnpmSupport
? new Set<string>([PNPM_FEATURE_FLAG])
: new Set<string>();

// Part 1: every argument is a scan target; process them sequentially
for (const path of paths) {
debug(`Processing ${path}...`);
Expand All @@ -170,7 +177,11 @@ export default async function monitor(...args0: MethodArgs): Promise<any> {
} else if (options.docker) {
analysisType = 'docker';
} else {
packageManager = detect.detectPackageManager(path, options);
packageManager = detect.detectPackageManager(
path,
options,
featureFlags,
);
}
const unsupportedPackageManagers: Array<{
label: string;
Expand All @@ -185,7 +196,7 @@ export default async function monitor(...args0: MethodArgs): Promise<any> {
const targetFile =
!options.scanAllUnmanaged && options.docker && !options.file // snyk monitor --docker (without --file)
? undefined
: options.file || detect.detectPackageFile(path);
: options.file || detect.detectPackageFile(path, featureFlags);

const displayPath = pathUtil.relative(
'.',
Expand All @@ -206,11 +217,15 @@ export default async function monitor(...args0: MethodArgs): Promise<any> {
// each plugin will be asked to scan once per path
// some return single InspectResult & newer ones return Multi
const inspectResult = await promiseOrCleanup(
getDepsFromPlugin(path, {
...options,
getDepsFromPlugin(
path,
packageManager,
}),
{
...options,
path,
packageManager,
},
featureFlags,
),
spinner.clear(analyzingDepsSpinnerLabel),
);
analytics.add('pluginName', inspectResult.plugin.name);
Expand Down
54 changes: 47 additions & 7 deletions src/lib/detect.ts
Expand Up @@ -5,11 +5,13 @@ import { NoSupportedManifestsFoundError } from './errors';
import {
SupportedPackageManagers,
SUPPORTED_MANIFEST_FILES,
PNPM_FEATURE_FLAG,
} from './package-managers';

const debug = debugLib('snyk-detect');

const DETECTABLE_FILES: string[] = [
'pnpm-lock.yaml',
'yarn.lock',
'package-lock.json',
'package.json',
Expand Down Expand Up @@ -38,6 +40,7 @@ const DETECTABLE_FILES: string[] = [
];

export const AUTO_DETECTABLE_FILES: string[] = [
'pnpm-lock.yaml',
'package-lock.json',
'yarn.lock',
'package.json',
Expand Down Expand Up @@ -81,6 +84,7 @@ const DETECTABLE_PACKAGE_MANAGERS: {
[SUPPORTED_MANIFEST_FILES.BUILD_GRADLE_KTS]: 'gradle',
[SUPPORTED_MANIFEST_FILES.BUILD_SBT]: 'sbt',
[SUPPORTED_MANIFEST_FILES.YARN_LOCK]: 'yarn',
[SUPPORTED_MANIFEST_FILES.PNPM_LOCK]: 'pnpm',
[SUPPORTED_MANIFEST_FILES.PACKAGE_JSON]: 'npm',
[SUPPORTED_MANIFEST_FILES.PIPFILE]: 'pip',
[SUPPORTED_MANIFEST_FILES.SETUP_PY]: 'pip',
Expand All @@ -102,16 +106,26 @@ const DETECTABLE_PACKAGE_MANAGERS: {
[SUPPORTED_MANIFEST_FILES.PACKAGE_SWIFT]: 'swift',
};

export function isPathToPackageFile(path: string) {
export function isPathToPackageFile(
path: string,
featureFlags: Set<string> = new Set<string>(),
) {
for (const fileName of DETECTABLE_FILES) {
if (path.endsWith(fileName)) {
if (!isFileCompatible(fileName, featureFlags)) {
continue;
}
return true;
}
}
return false;
}

export function detectPackageManager(root: string, options) {
export function detectPackageManager(
root: string,
options,
featureFlags: Set<string> = new Set<string>(),
) {
// If user specified a package manager let's use it.
if (options.packageManager) {
return options.packageManager;
Expand All @@ -133,14 +147,14 @@ export function detectPackageManager(root: string, options) {
);
}
file = options.file;
packageManager = detectPackageManagerFromFile(file);
packageManager = detectPackageManagerFromFile(file, featureFlags);
} else if (options.scanAllUnmanaged) {
packageManager = 'maven';
} else {
debug('no file specified. Trying to autodetect in base folder ' + root);
file = detectPackageFile(root);
file = detectPackageFile(root, featureFlags);
if (file) {
packageManager = detectPackageManagerFromFile(file);
packageManager = detectPackageManagerFromFile(file, featureFlags);
}
}
} else {
Expand Down Expand Up @@ -169,19 +183,41 @@ export function isLocalFolder(root: string) {
}
}

export function detectPackageFile(root) {
function isFileCompatible(
file: string,
featureFlags: Set<string> = new Set<string>(),
) {
if (
file === SUPPORTED_MANIFEST_FILES.PNPM_LOCK &&
!featureFlags.has(PNPM_FEATURE_FLAG)
) {
return false;
}
return true;
}

export function detectPackageFile(
root: string,
featureFlags: Set<string> = new Set<string>(),
) {
for (const file of DETECTABLE_FILES) {
if (fs.existsSync(pathLib.resolve(root, file))) {
if (!isFileCompatible(file, featureFlags)) {
debug(
`found pnpm lockfile ${file} in ${root}, but ${PNPM_FEATURE_FLAG} not enabled`,
);
continue;
}
debug('found package file ' + file + ' in ' + root);
return file;
}
}

debug('no package file found in ' + root);
}

export function detectPackageManagerFromFile(
file: string,
featureFlags: Set<string> = new Set<string>(),
): SupportedPackageManagers {
let key = pathLib.basename(file);

Expand All @@ -204,6 +240,10 @@ export function detectPackageManagerFromFile(
throw new Error('Could not detect package manager for file: ' + file);
}

if (!isFileCompatible(key, featureFlags)) {
throw new Error('Could not detect package manager for file: ' + file);
}

return DETECTABLE_PACKAGE_MANAGERS[key];
}

Expand Down