Skip to content
Open
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
4 changes: 3 additions & 1 deletion src/cli/commands/monitor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ import {
} from '../../../lib/package-managers';
import { normalizeTargetFile } from '../../../lib/normalize-target-file';
import { getOrganizationID } from '../../../lib/organization';
import { getPrintGraphMode } from '../../../lib/snyk-test/common';

const SEPARATOR = '\n-------------------------------------------------------\n';
const debug = Debug('snyk');
Expand Down Expand Up @@ -216,10 +217,11 @@ export default async function monitor(...args0: MethodArgs): Promise<any> {
let enableMavenDverboseExhaustiveDeps = false;
try {
const args = options['_doubleDashArgs'] || [];
const printGraphMode = getPrintGraphMode(options);
const verboseEnabled =
args.includes('-Dverbose') ||
args.includes('-Dverbose=true') ||
!!options['print-graph'];
printGraphMode.printGraphEnabled;
if (verboseEnabled) {
enableMavenDverboseExhaustiveDeps = (await hasFeatureFlag(
MAVEN_DVERBOSE_EXHAUSTIVE_DEPS_FF,
Expand Down
10 changes: 3 additions & 7 deletions src/lib/plugins/get-deps-from-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { convertSingleResultToMultiCustom } from './convert-single-splugin-res-t
import { convertMultiResultToMultiCustom } from './convert-multi-plugin-res-to-multi-custom';
import { processYarnWorkspaces } from './nodejs-plugin/yarn-workspaces-parser';
import { ScannedProject } from '@snyk/cli-interface/legacy/common';
import { shouldPrintDepGraphWithErrors } from '../snyk-test/common';

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

Expand Down Expand Up @@ -104,14 +105,9 @@ export async function getDepsFromPlugin(
}
let inspectRes;
try {
inspectRes = await getSinglePluginResult(
root,
options,
'',
featureFlags,
);
inspectRes = await getSinglePluginResult(root, options, '', featureFlags);
} catch (error) {
if (options['print-effective-graph-with-errors']) {
if (shouldPrintDepGraphWithErrors(options)) {
const errMessage =
error?.message ?? 'Something went wrong getting dependencies';
debug(
Expand Down
3 changes: 2 additions & 1 deletion src/lib/plugins/get-multi-plugin-result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { errorMessageWithRetry, FailedToRunTestError } from '../errors';
import { processYarnWorkspaces } from './nodejs-plugin/yarn-workspaces-parser';
import { processNpmWorkspaces } from './nodejs-plugin/npm-workspaces-parser';
import { processPnpmWorkspaces } from 'snyk-nodejs-plugin';
import { shouldPrintDepGraphWithErrors } from '../snyk-test/common';

const debug = debugModule('snyk-test');
export interface ScannedProjectCustom
Expand Down Expand Up @@ -184,7 +185,7 @@ export async function getMultiPluginResult(
if (!allResults.length) {
// When allow-incomplete-sbom is active, return instead of throwing
// so the caller can print per-project JSONL error entries
if (options['print-effective-graph-with-errors']) {
if (shouldPrintDepGraphWithErrors(options)) {
return {
plugin: {
name: 'custom-auto-detect',
Expand Down
62 changes: 53 additions & 9 deletions src/lib/snyk-test/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,50 @@ export type FailOn = 'all' | 'upgradable' | 'patchable';
export const RETRY_ATTEMPTS = 3;
export const RETRY_DELAY = 500;

export interface PrintGraphMode {
printGraphEnabled: boolean;
effectiveGraph: boolean;
jsonlOutput: boolean;
printErrors: boolean;
}

/**
* getPrintGraphMode derives canonical print-graph behavior from both
* the new flag set and legacy aliases during the migration window.
*/
export function getPrintGraphMode(opts: Options): PrintGraphMode {
const legacyEffectiveGraph = !!opts['print-effective-graph'];
const legacyEffectiveGraphWithErrors =
!!opts['print-effective-graph-with-errors'];

const printGraphEnabled =
!!opts['print-graph'] ||
legacyEffectiveGraph ||
legacyEffectiveGraphWithErrors;

const effectiveGraph =
!!opts['effective-graph'] ||
legacyEffectiveGraph ||
legacyEffectiveGraphWithErrors;

const printErrors =
printGraphEnabled &&
(!!opts['print-errors'] || legacyEffectiveGraphWithErrors);

const jsonlOutput =
printGraphEnabled &&
(!!opts['jsonl-output'] ||
legacyEffectiveGraph ||
legacyEffectiveGraphWithErrors);

return {
printGraphEnabled,
effectiveGraph,
jsonlOutput,
printErrors,
};
}

/**
* printDepGraph writes the given dep-graph and target name to the destination
* stream as expected by the `depgraph` CLI workflow.
Expand All @@ -102,7 +146,8 @@ export async function printDepGraph(
}

export function shouldPrintDepGraph(opts: Options): boolean {
return opts['print-graph'] && !opts['print-deps'];
const mode = getPrintGraphMode(opts);
return mode.printGraphEnabled && !mode.effectiveGraph && !opts['print-deps'];
}

/**
Expand Down Expand Up @@ -173,18 +218,17 @@ export async function printEffectiveDepGraphError(
* Checks if either --print-effective-graph or --print-effective-graph-with-errors is set.
*/
export function shouldPrintEffectiveDepGraph(opts: Options): boolean {
return (
!!opts['print-effective-graph'] ||
shouldPrintEffectiveDepGraphWithErrors(opts)
);
const mode = getPrintGraphMode(opts);
return mode.printGraphEnabled && mode.effectiveGraph;
}

/**
* shouldPrintEffectiveDepGraphWithErrors checks if the --print-effective-graph-with-errors flag is set.
* This is used to determine if the effective dep-graph with errors should be printed.
* shouldPrintDepGraphWithErrors returns true when dependency graph output
* is requested and error entries should also be printed.
*/
export function shouldPrintEffectiveDepGraphWithErrors(opts: Options): boolean {
return !!opts['print-effective-graph-with-errors'];
export function shouldPrintDepGraphWithErrors(opts: Options): boolean {
const mode = getPrintGraphMode(opts);
return mode.printGraphEnabled && mode.printErrors;
}

/**
Expand Down
4 changes: 3 additions & 1 deletion src/lib/snyk-test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const {
} = require('../package-managers');
const { getOrganizationID } = require('../organization');
const debug = require('debug')('snyk-test');
const { getPrintGraphMode } = require('./common');

async function test(root, options, callback) {
if (typeof options === 'function') {
Expand Down Expand Up @@ -53,10 +54,11 @@ async function executeTest(root, options) {
let enableMavenDverboseExhaustiveDeps = false;
try {
const args = options['_doubleDashArgs'] || [];
const printGraphMode = getPrintGraphMode(options);
const verboseEnabled =
args.includes('-Dverbose') ||
args.includes('-Dverbose=true') ||
!!options['print-graph'];
printGraphMode.printGraphEnabled;
if (verboseEnabled) {
enableMavenDverboseExhaustiveDeps = await hasFeatureFlag(
MAVEN_DVERBOSE_EXHAUSTIVE_DEPS_FF,
Expand Down
6 changes: 3 additions & 3 deletions src/lib/snyk-test/run-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import {
assembleQueryString,
shouldPrintDepGraph,
shouldPrintEffectiveDepGraph,
shouldPrintEffectiveDepGraphWithErrors,
shouldPrintDepGraphWithErrors,
} from './common';
import config from '../config';
import * as analytics from '../analytics';
Expand Down Expand Up @@ -656,7 +656,7 @@ async function assembleLocalPayloads(
await spinner.clear<void>(spinnerLbl)();
// When printing effective dep-graph with errors, suppress warning output —
// the failures will be embedded in the generated SBOM as annotations.
const suppressWarnings = shouldPrintEffectiveDepGraphWithErrors(options);
const suppressWarnings = shouldPrintDepGraphWithErrors(options);
const isNotJsonOrQueiet =
!options.json && !options.quiet && !suppressWarnings;

Expand All @@ -679,7 +679,7 @@ async function assembleLocalPayloads(
failedResults,
);

if (shouldPrintEffectiveDepGraphWithErrors(options)) {
if (shouldPrintDepGraphWithErrors(options)) {
for (const failed of failedResults) {
await printEffectiveDepGraphError(root, failed, process.stdout);
}
Expand Down
8 changes: 8 additions & 0 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ export interface Options {
'print-deps'?: boolean;
'print-tree'?: boolean;
'print-dep-paths'?: boolean;
'print-graph'?: boolean;
'jsonl-output'?: boolean;
'effective-graph'?: boolean;
'print-errors'?: boolean;
'print-effective-graph'?: boolean;
'print-effective-graph-with-errors'?: boolean;
'remote-repo-url'?: string;
Expand Down Expand Up @@ -150,6 +154,10 @@ export interface MonitorOptions {
json?: boolean;
allSubProjects?: boolean;
'project-name'?: string;
'print-graph'?: boolean;
'jsonl-output'?: boolean;
'effective-graph'?: boolean;
'print-errors'?: boolean;
'print-deps'?: boolean;
'print-dep-paths'?: boolean;
'target-reference'?: string;
Expand Down
25 changes: 12 additions & 13 deletions test/jest/unit/lib/plugins/get-deps-from-plugin.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { getDepsFromPlugin } from '../../../../../src/lib/plugins/get-deps-from-plugin';
import { Options, TestOptions } from '../../../../../src/lib/types';
import * as singlePluginResult from '../../../../../src/lib/plugins/get-single-plugin-result';
import * as detect from '../../../../../src/lib/detect';

jest.mock('../../../../../src/lib/plugins/get-single-plugin-result');
jest.mock('../../../../../src/lib/detect', () => ({
Expand All @@ -23,9 +22,9 @@ describe('getDepsFromPlugin - print-effective-graph-with-errors', () => {

it('should return failedResults when plugin throws and flag is set', async () => {
const pluginError = new Error('missing lockfile');
(
singlePluginResult.getSinglePluginResult as jest.Mock
).mockRejectedValue(pluginError);
(singlePluginResult.getSinglePluginResult as jest.Mock).mockRejectedValue(
pluginError,
);

const options = {
...baseOptions,
Expand All @@ -45,19 +44,19 @@ describe('getDepsFromPlugin - print-effective-graph-with-errors', () => {

it('should rethrow when plugin throws and flag is not set', async () => {
const pluginError = new Error('missing lockfile');
(
singlePluginResult.getSinglePluginResult as jest.Mock
).mockRejectedValue(pluginError);
(singlePluginResult.getSinglePluginResult as jest.Mock).mockRejectedValue(
pluginError,
);

await expect(
getDepsFromPlugin('/test', baseOptions),
).rejects.toThrow('missing lockfile');
await expect(getDepsFromPlugin('/test', baseOptions)).rejects.toThrow(
'missing lockfile',
);
});

it('should use fallback message when error has no message', async () => {
(
singlePluginResult.getSinglePluginResult as jest.Mock
).mockRejectedValue({ code: 'UNKNOWN' });
(singlePluginResult.getSinglePluginResult as jest.Mock).mockRejectedValue({
code: 'UNKNOWN',
});

const options = {
...baseOptions,
Expand Down