From f2f5ba2811d49156016c0ce6ac7d180d40ef1efc Mon Sep 17 00:00:00 2001 From: Toni Date: Fri, 13 Mar 2026 15:02:44 +0000 Subject: [PATCH] fix: evaluate Go plugin feature flags early Co-Authored-By: Max --- src/cli/commands/monitor/index.ts | 32 ++- src/lib/package-managers.ts | 4 + src/lib/plugins/build-plugin-options.ts | 26 +-- src/lib/plugins/get-single-plugin-result.ts | 4 +- src/lib/snyk-test/index.js | 38 +++- src/lib/types.ts | 5 - .../plugins/get-single-plugin-result.spec.ts | 148 +++---------- .../unit/pnpm/snyk-test-pnpm-project.spec.ts | 148 +++---------- .../unit/python/snyk-test-pyproject.spec.ts | 206 +++--------------- test/tap/monitor-target.test.ts | 9 +- 10 files changed, 162 insertions(+), 458 deletions(-) diff --git a/src/cli/commands/monitor/index.ts b/src/cli/commands/monitor/index.ts index 0f71975cf2..98b12c8c11 100644 --- a/src/cli/commands/monitor/index.ts +++ b/src/cli/commands/monitor/index.ts @@ -67,6 +67,8 @@ import { PNPM_FEATURE_FLAG, UV_FEATURE_FLAG, MAVEN_DVERBOSE_EXHAUSTIVE_DEPS_FF, + INCLUDE_GO_STANDARD_LIBRARY_DEPS_FEATURE_FLAG, + DISABLE_GO_PACKAGE_URLS_IN_CLI_FEATURE_FLAG, } from '../../../lib/package-managers'; import { normalizeTargetFile } from '../../../lib/normalize-target-file'; import { getOrganizationID } from '../../../lib/organization'; @@ -201,19 +203,21 @@ export default async function monitor(...args0: MethodArgs): Promise { ); } - let hasPnpmSupport = false; - let enableMavenDverboseExhaustiveDeps = false; - try { - hasPnpmSupport = (await hasFeatureFlag( - PNPM_FEATURE_FLAG, - options, - )) as boolean; - } catch (err) { - hasPnpmSupport = false; - } - + const hasPnpmSupport = await hasFeatureFlagOrDefault( + PNPM_FEATURE_FLAG, + options, + ); const hasUvSupport = await hasFeatureFlagOrDefault(UV_FEATURE_FLAG, options); + const includeGoStandardLibraryDeps = await hasFeatureFlagOrDefault( + INCLUDE_GO_STANDARD_LIBRARY_DEPS_FEATURE_FLAG, + options, + ); + const disableGoPackageUrls = await hasFeatureFlagOrDefault( + DISABLE_GO_PACKAGE_URLS_IN_CLI_FEATURE_FLAG, + options, + ); + let enableMavenDverboseExhaustiveDeps = false; try { const args = options['_doubleDashArgs'] || []; const verboseEnabled = @@ -241,6 +245,12 @@ export default async function monitor(...args0: MethodArgs): Promise { if (hasUvSupport) { featureFlags.add(UV_FEATURE_FLAG); } + if (includeGoStandardLibraryDeps) { + featureFlags.add(INCLUDE_GO_STANDARD_LIBRARY_DEPS_FEATURE_FLAG); + } + if (disableGoPackageUrls) { + featureFlags.add(DISABLE_GO_PACKAGE_URLS_IN_CLI_FEATURE_FLAG); + } const showMavenScope = await isFeatureFlagSupportedForOrg( SHOW_MAVEN_BUILD_SCOPE, diff --git a/src/lib/package-managers.ts b/src/lib/package-managers.ts index 784c53f002..c05244364a 100644 --- a/src/lib/package-managers.ts +++ b/src/lib/package-managers.ts @@ -2,6 +2,10 @@ export const PNPM_FEATURE_FLAG = 'enablePnpmCli'; export const UV_FEATURE_FLAG = 'enableUvCLI'; export const MAVEN_DVERBOSE_EXHAUSTIVE_DEPS_FF = 'enableMavenDverboseExhaustiveDeps'; +export const INCLUDE_GO_STANDARD_LIBRARY_DEPS_FEATURE_FLAG = + 'includeGoStandardLibraryDeps'; +export const DISABLE_GO_PACKAGE_URLS_IN_CLI_FEATURE_FLAG = + 'disableGoPackageUrlsInCli'; export type SupportedPackageManagers = | 'rubygems' diff --git a/src/lib/plugins/build-plugin-options.ts b/src/lib/plugins/build-plugin-options.ts index 2126b9eb6b..52bb85c204 100644 --- a/src/lib/plugins/build-plugin-options.ts +++ b/src/lib/plugins/build-plugin-options.ts @@ -1,5 +1,8 @@ import { Options, TestOptions, MonitorOptions } from '../types'; -import { hasFeatureFlagOrDefault } from '../feature-flags'; +import { + DISABLE_GO_PACKAGE_URLS_IN_CLI_FEATURE_FLAG, + INCLUDE_GO_STANDARD_LIBRARY_DEPS_FEATURE_FLAG, +} from '../package-managers'; /** * Returns a shallow clone of the original `options` object with any @@ -7,6 +10,7 @@ import { hasFeatureFlagOrDefault } from '../feature-flags'; */ export async function buildPluginOptions( options: Options & (TestOptions | MonitorOptions), + featureFlags: Set = new Set(), ): Promise { const pluginOptions: any = { ...options }; @@ -15,22 +19,14 @@ export async function buildPluginOptions( options.packageManager === 'golangdep'; if (isGoPackageManager) { - const includeGoStandardLibraryDeps = await hasFeatureFlagOrDefault( - 'includeGoStandardLibraryDeps', - options, - false, - ); - - const disableGoPackageUrls = await hasFeatureFlagOrDefault( - 'disableGoPackageUrlsInCli', - options, - false, - ); - pluginOptions.configuration = { ...(pluginOptions.configuration || {}), - includeGoStandardLibraryDeps, - includePackageUrls: disableGoPackageUrls ? false : true, + includeGoStandardLibraryDeps: featureFlags.has( + INCLUDE_GO_STANDARD_LIBRARY_DEPS_FEATURE_FLAG, + ), + includePackageUrls: !featureFlags.has( + DISABLE_GO_PACKAGE_URLS_IN_CLI_FEATURE_FLAG, + ), // enable fix for replaced modules. useReplaceName: true, } as Options['configuration']; diff --git a/src/lib/plugins/get-single-plugin-result.ts b/src/lib/plugins/get-single-plugin-result.ts index c9122ba84d..ebd6420d1e 100644 --- a/src/lib/plugins/get-single-plugin-result.ts +++ b/src/lib/plugins/get-single-plugin-result.ts @@ -5,7 +5,7 @@ import { TestOptions, Options, MonitorOptions } from '../types'; import { snykHttpClient } from '../request/snyk-http-client'; import * as types from './types'; import { buildPluginOptions } from './build-plugin-options'; -const { SHOW_MAVEN_BUILD_SCOPE, SHOW_NPM_SCOPE } = require('../feature-flags'); +import { SHOW_MAVEN_BUILD_SCOPE, SHOW_NPM_SCOPE } from '../feature-flags'; export async function getSinglePluginResult( root: string, @@ -17,7 +17,7 @@ export async function getSinglePluginResult( const moduleInfo = ModuleInfo(plugin, options.policy); // Build final options with any ecosystem-specific configurations/flags injected - const pluginOptions = await buildPluginOptions(options); + const pluginOptions = await buildPluginOptions(options, featureFlags); const inspectRes: pluginApi.InspectResult = await moduleInfo.inspect( root, diff --git a/src/lib/snyk-test/index.js b/src/lib/snyk-test/index.js index 5faca35d05..f39684838b 100644 --- a/src/lib/snyk-test/index.js +++ b/src/lib/snyk-test/index.js @@ -10,10 +10,13 @@ const { SHOW_NPM_SCOPE, hasFeatureFlag, isFeatureFlagSupportedForOrg, + hasFeatureFlagOrDefault, } = require('../feature-flags'); const { PNPM_FEATURE_FLAG, MAVEN_DVERBOSE_EXHAUSTIVE_DEPS_FF, + INCLUDE_GO_STANDARD_LIBRARY_DEPS_FEATURE_FLAG, + DISABLE_GO_PACKAGE_URLS_IN_CLI_FEATURE_FLAG, } = require('../package-managers'); const { getOrganizationID } = require('../organization'); @@ -37,14 +40,20 @@ async function test(root, options, callback) { } async function executeTest(root, options) { - let hasPnpmSupport = false; - let enableMavenDverboseExhaustiveDeps = false; - try { - hasPnpmSupport = await hasFeatureFlag(PNPM_FEATURE_FLAG, options); - } catch (err) { - hasPnpmSupport = false; - } + const hasPnpmSupport = await hasFeatureFlagOrDefault( + PNPM_FEATURE_FLAG, + options, + ); + const includeGoStandardLibraryDeps = await hasFeatureFlagOrDefault( + INCLUDE_GO_STANDARD_LIBRARY_DEPS_FEATURE_FLAG, + options, + ); + const disableGoPackageUrls = await hasFeatureFlagOrDefault( + DISABLE_GO_PACKAGE_URLS_IN_CLI_FEATURE_FLAG, + options, + ); + let enableMavenDverboseExhaustiveDeps = false; try { const args = options['_doubleDashArgs'] || []; const verboseEnabled = @@ -66,9 +75,18 @@ async function executeTest(root, options) { } try { - const featureFlags = hasPnpmSupport - ? new Set([PNPM_FEATURE_FLAG]) - : new Set([]); + const featureFlags = new Set(); + if (hasPnpmSupport) { + featureFlags.add(PNPM_FEATURE_FLAG); + } + + if (includeGoStandardLibraryDeps) { + featureFlags.add(INCLUDE_GO_STANDARD_LIBRARY_DEPS_FEATURE_FLAG); + } + + if (disableGoPackageUrls) { + featureFlags.add(DISABLE_GO_PACKAGE_URLS_IN_CLI_FEATURE_FLAG); + } const showMavenScope = await isFeatureFlagSupportedForOrg( SHOW_MAVEN_BUILD_SCOPE, diff --git a/src/lib/types.ts b/src/lib/types.ts index 54ec677c8d..450841833f 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -134,11 +134,6 @@ export interface Options { // Plugin configuration options configuration?: { - // Used only with the Go plugin. When enabled, includes Go standard library packages in dependency graph. - includeGoStandardLibraryDeps?: boolean; - // Used only with the Go plugin. When enabled, includes PackageURL information in dep-graphs. - // TODO: remove once UNIFY-891 is done. - includePackageUrls?: boolean; // Used only with the Go plugin. // TODO: remove once UNIFY-891 is done. useReplaceName?: boolean; diff --git a/test/jest/unit/lib/plugins/get-single-plugin-result.spec.ts b/test/jest/unit/lib/plugins/get-single-plugin-result.spec.ts index 786f92c486..99e4a933a5 100644 --- a/test/jest/unit/lib/plugins/get-single-plugin-result.spec.ts +++ b/test/jest/unit/lib/plugins/get-single-plugin-result.spec.ts @@ -9,6 +9,10 @@ import * as pluginsModule from '../../../../../src/lib/plugins'; import { ModuleInfo } from '../../../../../src/lib/module-info'; import { hasFeatureFlagOrDefault } from '../../../../../src/lib/feature-flags'; import { snykHttpClient } from '../../../../../src/lib/request/snyk-http-client'; +import { + DISABLE_GO_PACKAGE_URLS_IN_CLI_FEATURE_FLAG, + INCLUDE_GO_STANDARD_LIBRARY_DEPS_FEATURE_FLAG, +} from '../../../../../src/lib/package-managers'; // Mock dependencies jest.mock('../../../../../src/lib/plugins', () => ({ @@ -47,19 +51,15 @@ describe('getSinglePluginResult', () => { packageManager: 'gomodules', showVulnPaths: 'some', }; + const featureFlags = new Set([ + INCLUDE_GO_STANDARD_LIBRARY_DEPS_FEATURE_FLAG, + ]); - (hasFeatureFlagOrDefault as jest.Mock).mockResolvedValue(true); - - await getSinglePluginResult('/test', options); + await getSinglePluginResult('/test', options, 'go.mod', featureFlags); - expect(hasFeatureFlagOrDefault).toHaveBeenCalledWith( - 'includeGoStandardLibraryDeps', - options, - false, - ); expect(mockModuleInfo.inspect).toHaveBeenCalledWith( '/test', - undefined, + 'go.mod', expect.objectContaining({ configuration: expect.objectContaining({ includeGoStandardLibraryDeps: true, @@ -75,19 +75,13 @@ describe('getSinglePluginResult', () => { packageManager: 'gomodules', showVulnPaths: 'some', }; + const featureFlags = new Set(); - (hasFeatureFlagOrDefault as jest.Mock).mockResolvedValue(false); + await getSinglePluginResult('/test', options, 'go.mod', featureFlags); - await getSinglePluginResult('/test', options); - - expect(hasFeatureFlagOrDefault).toHaveBeenCalledWith( - 'includeGoStandardLibraryDeps', - options, - false, - ); expect(mockModuleInfo.inspect).toHaveBeenCalledWith( '/test', - undefined, + 'go.mod', expect.objectContaining({ configuration: expect.objectContaining({ includeGoStandardLibraryDeps: false, @@ -103,45 +97,15 @@ describe('getSinglePluginResult', () => { packageManager: 'golangdep', showVulnPaths: 'some', }; + const featureFlags = new Set([ + INCLUDE_GO_STANDARD_LIBRARY_DEPS_FEATURE_FLAG, + ]); - (hasFeatureFlagOrDefault as jest.Mock).mockResolvedValue(true); - - await getSinglePluginResult('/test', options); - - expect(hasFeatureFlagOrDefault).toHaveBeenCalledWith( - 'includeGoStandardLibraryDeps', - options, - false, - ); - expect(mockModuleInfo.inspect).toHaveBeenCalledWith( - '/test', - undefined, - expect.objectContaining({ - configuration: expect.objectContaining({ - includeGoStandardLibraryDeps: true, - }), - }), - snykHttpClient, - ); - }); - - it('should preserve existing configuration properties when adding includeGoStandardLibraryDeps', async () => { - const options: Options & TestOptions = { - path: '/test', - packageManager: 'gomodules', - showVulnPaths: 'some', - configuration: { - includePackageUrls: true, - }, - }; - - (hasFeatureFlagOrDefault as jest.Mock).mockResolvedValue(true); - - await getSinglePluginResult('/test', options); + await getSinglePluginResult('/test', options, 'go.mod', featureFlags); expect(mockModuleInfo.inspect).toHaveBeenCalledWith( '/test', - undefined, + 'go.mod', expect.objectContaining({ configuration: expect.objectContaining({ includeGoStandardLibraryDeps: true, @@ -157,19 +121,13 @@ describe('getSinglePluginResult', () => { packageManager: 'gomodules', showVulnPaths: 'some', }; + const featureFlags = new Set(); - (hasFeatureFlagOrDefault as jest.Mock).mockResolvedValue(false); - - await getSinglePluginResult('/test', options); + await getSinglePluginResult('/test', options, 'go.mod', featureFlags); - expect(hasFeatureFlagOrDefault).toHaveBeenCalledWith( - 'disableGoPackageUrlsInCli', - options, - false, - ); expect(mockModuleInfo.inspect).toHaveBeenCalledWith( '/test', - undefined, + 'go.mod', expect.objectContaining({ configuration: expect.objectContaining({ includePackageUrls: true, @@ -185,19 +143,15 @@ describe('getSinglePluginResult', () => { packageManager: 'gomodules', showVulnPaths: 'some', }; + const featureFlags = new Set([ + DISABLE_GO_PACKAGE_URLS_IN_CLI_FEATURE_FLAG, + ]); - (hasFeatureFlagOrDefault as jest.Mock).mockResolvedValue(true); - - await getSinglePluginResult('/test', options); + await getSinglePluginResult('/test', options, 'go.mod', featureFlags); - expect(hasFeatureFlagOrDefault).toHaveBeenCalledWith( - 'disableGoPackageUrlsInCli', - options, - false, - ); expect(mockModuleInfo.inspect).toHaveBeenCalledWith( '/test', - undefined, + 'go.mod', expect.objectContaining({ configuration: expect.objectContaining({ includePackageUrls: false, @@ -292,31 +246,6 @@ describe('getSinglePluginResult', () => { snykHttpClient, ); }); - - it('should preserve existing configuration for non-Go package managers', async () => { - const options: Options & TestOptions = { - path: '/test', - packageManager: 'npm', - showVulnPaths: 'some', - configuration: { - includePackageUrls: true, - }, - }; - - await getSinglePluginResult('/test', options); - - expect(hasFeatureFlagOrDefault).not.toHaveBeenCalled(); - expect(mockModuleInfo.inspect).toHaveBeenCalledWith( - '/test', - undefined, - expect.objectContaining({ - configuration: { - includePackageUrls: true, - }, - }), - snykHttpClient, - ); - }); }); describe('MonitorOptions', () => { @@ -325,19 +254,17 @@ describe('getSinglePluginResult', () => { path: '/test', packageManager: 'gomodules', }; + const featureFlags = new Set([ + INCLUDE_GO_STANDARD_LIBRARY_DEPS_FEATURE_FLAG, + ]); (hasFeatureFlagOrDefault as jest.Mock).mockResolvedValue(true); - await getSinglePluginResult('/test', options); + await getSinglePluginResult('/test', options, 'go.mod', featureFlags); - expect(hasFeatureFlagOrDefault).toHaveBeenCalledWith( - 'includeGoStandardLibraryDeps', - options, - false, - ); expect(mockModuleInfo.inspect).toHaveBeenCalledWith( '/test', - undefined, + 'go.mod', expect.objectContaining({ configuration: expect.objectContaining({ includeGoStandardLibraryDeps: true, @@ -349,21 +276,6 @@ describe('getSinglePluginResult', () => { }); describe('Error handling', () => { - it('should propagate errors from hasFeatureFlagOrDefault', async () => { - const options: Options & TestOptions = { - path: '/test', - packageManager: 'gomodules', - showVulnPaths: 'some', - }; - - const error = new Error('Feature flag check failed'); - (hasFeatureFlagOrDefault as jest.Mock).mockRejectedValue(error); - - await expect(getSinglePluginResult('/test', options)).rejects.toThrow( - 'Feature flag check failed', - ); - }); - it('should propagate errors from moduleInfo.inspect', async () => { const options: Options & TestOptions = { path: '/test', diff --git a/test/jest/unit/pnpm/snyk-test-pnpm-project.spec.ts b/test/jest/unit/pnpm/snyk-test-pnpm-project.spec.ts index 5499b20d32..c1fc3ef359 100644 --- a/test/jest/unit/pnpm/snyk-test-pnpm-project.spec.ts +++ b/test/jest/unit/pnpm/snyk-test-pnpm-project.spec.ts @@ -31,47 +31,7 @@ describe('snyk test for pnpm project', () => { it('should scan pnpm vulnerabilities when enablePnpmCli feature flag is enabled', async () => { const fixturePath = getFixturePath('pnpm-app'); - // this is for 'enablePnpmCli' feature flag - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: true, - }, - }); - }); - - // this is for 'show-maven-build-scope' and 'show-npm-scope' feature flags - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: true, - }, - }); - }); - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: true, - }, - }); - }); - - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - result: { issuesData: {}, affectedPkgs: {} }, - meta: { org: 'test-org', isPublic: false }, - filesystemPolicy: false, - }, - }); - }); + mockRequests(true); const result: CommandResult = await test(fixturePath, { json: true, @@ -79,7 +39,7 @@ describe('snyk test for pnpm project', () => { _doubleDashArgs: [], }); - expect(mockedMakeRequest).toHaveBeenCalledTimes(4); + expect(mockedMakeRequest).toHaveBeenCalledTimes(6); expect(mockedMakeRequest).toHaveBeenCalledWith( expect.objectContaining({ body: expect.objectContaining({ @@ -120,47 +80,7 @@ describe('snyk test for pnpm project', () => { it('should scan pnpm vulnerabilities as npm project when enablePnpmCli feature flag is not enabled', async () => { const fixturePath = getFixturePath('pnpm-app'); - // this is for 'enablePnpmCli' feature flag - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: false, - }, - }); - }); - - // this is for 'show-maven-build-scope' and 'show-npm-scope' feature flags - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: false, - }, - }); - }); - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: false, - }, - }); - }); - - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - result: { issuesData: {}, affectedPkgs: {} }, - meta: { org: 'test-org', isPublic: false }, - filesystemPolicy: false, - }, - }); - }); + mockRequests(false); const result: CommandResult = await test(fixturePath, { json: true, @@ -168,7 +88,7 @@ describe('snyk test for pnpm project', () => { _doubleDashArgs: [], }); - expect(mockedMakeRequest).toHaveBeenCalledTimes(4); + expect(mockedMakeRequest).toHaveBeenCalledTimes(6); const expectedResultObject = { vulnerabilities: [], @@ -206,27 +126,7 @@ describe('snyk test for pnpm project', () => { it('should scan pnpm workspace vulnerabilities', async () => { const fixturePath = getFixturePath('workspace-multi-type'); - // this is for 'enablePnpmCli' feature flag - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: true, - }, - }); - }); - - mockedMakeRequest.mockImplementation(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - result: { issuesData: {}, affectedPkgs: {} }, - meta: { org: 'test-org', isPublic: false }, - filesystemPolicy: false, - }, - }); - }); + mockRequests(true); const result: CommandResult = await test(fixturePath, { allProjects: true, @@ -235,7 +135,7 @@ describe('snyk test for pnpm project', () => { _doubleDashArgs: [], }); - expect(mockedMakeRequest).toHaveBeenCalledTimes(13); + expect(mockedMakeRequest).toHaveBeenCalledTimes(15); const parsedResult = JSON.parse(result.getDisplayResults()); const pnpmResult = parsedResult.filter( @@ -249,16 +149,7 @@ describe('snyk test for pnpm project', () => { it('should not scan pnpm workspace vulnerabilities, only npm and yarn', async () => { const fixturePath = getFixturePath('workspace-multi-type'); - // this is for 'enablePnpmCli' feature flag - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: false, - }, - }); - }); + mockRequests(false); mockedMakeRequest.mockImplementation(() => { return Promise.resolve({ @@ -278,7 +169,7 @@ describe('snyk test for pnpm project', () => { _doubleDashArgs: [], }); - expect(mockedMakeRequest).toHaveBeenCalledTimes(9); + expect(mockedMakeRequest).toHaveBeenCalledTimes(11); const parsedResult = JSON.parse(result.getDisplayResults()); const pnpmResult = parsedResult.filter( @@ -289,3 +180,26 @@ describe('snyk test for pnpm project', () => { }); }); }); + +function mockRequests(enablePnpm = true): void { + mockedMakeRequest.mockImplementation(async (req) => { + // Responses for feature flags + if (req.url.includes('/feature-flags/')) { + const ok = req.url.includes('enablePnpmCli') ? enablePnpm : true; + return { + res: { statusCode: 200 } as NeedleResponse, + body: { code: 200, ok }, + }; + } + + // default response + return { + res: { statusCode: 200 } as NeedleResponse, + body: { + result: { issuesData: {}, affectedPkgs: {} }, + meta: { org: 'test-org', isPublic: false }, + filesystemPolicy: false, + }, + }; + }); +} diff --git a/test/jest/unit/python/snyk-test-pyproject.spec.ts b/test/jest/unit/python/snyk-test-pyproject.spec.ts index 6ac34ecc04..6c022a8730 100644 --- a/test/jest/unit/python/snyk-test-pyproject.spec.ts +++ b/test/jest/unit/python/snyk-test-pyproject.spec.ts @@ -49,49 +49,11 @@ describe('snyk test for python project', () => { }, }; - // this is for 'enablePnpmCli' feature flag - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: false, - }, - }); - }); - // this is for 'show-maven-build-scope' and 'show-npm-scope' feature flags - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: true, - }, - }); - }); - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: true, - }, - }); - }); + mockRequests(); mockedLoadPlugin.mockImplementationOnce(() => { return plugin; }); - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - result: { issuesData: {}, affectedPkgs: {} }, - meta: { org: 'test-org', isPublic: false }, - filesystemPolicy: false, - }, - }); - }); const result: CommandResult = await test(fixturePath, { json: true, @@ -102,7 +64,7 @@ describe('snyk test for python project', () => { expect(mockedLoadPlugin).toHaveBeenCalledTimes(1); expect(mockedLoadPlugin).toHaveBeenCalledWith('poetry'); - expect(mockedMakeRequest).toHaveBeenCalledTimes(4); + expect(mockedMakeRequest).toHaveBeenCalledTimes(6); expect(mockedMakeRequest).toHaveBeenCalledWith( expect.objectContaining({ body: expect.objectContaining({ @@ -156,49 +118,11 @@ describe('snyk test for python project', () => { }, }; - // this is for 'enablePnpmCli' feature flag - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: false, - }, - }); - }); - // this is for 'show-maven-build-scope' and 'show-npm-scope' feature flags - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: true, - }, - }); - }); - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: true, - }, - }); - }); + mockRequests(); mockedLoadPlugin.mockImplementationOnce(() => { return plugin; }); - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - result: { issuesData: {}, affectedPkgs: {} }, - meta: { org: 'test-org', isPublic: false }, - filesystemPolicy: false, - }, - }); - }); const result: CommandResult = await test(fixturePath, { json: true, @@ -209,7 +133,7 @@ describe('snyk test for python project', () => { expect(mockedLoadPlugin).toHaveBeenCalledTimes(1); expect(mockedLoadPlugin).toHaveBeenCalledWith('poetry'); - expect(mockedMakeRequest).toHaveBeenCalledTimes(4); + expect(mockedMakeRequest).toHaveBeenCalledTimes(6); expect(mockedMakeRequest).toHaveBeenCalledWith( expect.objectContaining({ body: expect.objectContaining({ @@ -267,49 +191,11 @@ describe('snyk test for python project', () => { }, }; - // this is for 'enablePnpmCli' feature flag - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: false, - }, - }); - }); - // this is for 'show-maven-build-scope' and 'show-npm-scope' feature flags - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: false, - }, - }); - }); - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: false, - }, - }); - }); + mockRequests(); mockedLoadPlugin.mockImplementationOnce(() => { return plugin; }); - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - result: { issuesData: {}, affectedPkgs: {} }, - meta: { org: 'test-org', isPublic: false }, - filesystemPolicy: false, - }, - }); - }); const result: CommandResult = await test(fixturePath, { allProjects: true, @@ -321,7 +207,7 @@ describe('snyk test for python project', () => { expect(mockedLoadPlugin).toHaveBeenCalledTimes(1); expect(mockedLoadPlugin).toHaveBeenCalledWith('pip'); - expect(mockedMakeRequest).toHaveBeenCalledTimes(4); + expect(mockedMakeRequest).toHaveBeenCalledTimes(6); expect(mockedMakeRequest).toHaveBeenCalledWith( expect.objectContaining({ body: expect.objectContaining({ @@ -389,40 +275,11 @@ describe('snyk test for python project', () => { }, }; - // this is for 'enablePnpmCli' feature flag - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: false, - }, - }); - }); - // this is for 'show-maven-build-scope' and 'show-npm-scope' feature flags - mockedMakeRequest.mockImplementation(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: true, - }, - }); - }); + mockRequests(); mockedLoadPlugin .mockImplementationOnce(() => pipfilePythonPluginResponse) .mockImplementationOnce(() => pyprojectPythonPluginResponse); - mockedMakeRequest.mockImplementation(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - result: { issuesData: {}, affectedPkgs: {} }, - meta: { org: 'test-org', isPublic: false }, - filesystemPolicy: false, - }, - }); - }); const result: CommandResult = await test(fixturePath, { allProjects: true, @@ -435,7 +292,7 @@ describe('snyk test for python project', () => { expect(mockedLoadPlugin).toHaveBeenCalledWith('pip'); expect(mockedLoadPlugin).toHaveBeenCalledWith('poetry'); - expect(mockedMakeRequest).toHaveBeenCalledTimes(5); + expect(mockedMakeRequest).toHaveBeenCalledTimes(7); expect(mockedMakeRequest).toHaveBeenCalledWith( expect.objectContaining({ body: expect.objectContaining({ @@ -532,33 +389,10 @@ describe('snyk test for python project', () => { }, }; - // Stub feature flag request (enablePnpmCli) - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - code: 200, - ok: false, - }, - }); - }); - mockedLoadPlugin.mockImplementationOnce(() => { return plugin; }); - // Stub vulnerability request - mockedMakeRequest.mockImplementationOnce(() => { - return Promise.resolve({ - res: { statusCode: 200 } as NeedleResponse, - body: { - result: { issuesData: {}, affectedPkgs: {} }, - meta: { org: 'test-org', isPublic: false }, - filesystemPolicy: false, - }, - }); - }); - const result: CommandResult = await test(fixturePath, { dev: true, json: true, @@ -569,7 +403,7 @@ describe('snyk test for python project', () => { expect(mockedLoadPlugin).toHaveBeenCalledTimes(1); expect(mockedLoadPlugin).toHaveBeenCalledWith('poetry'); - expect(mockedMakeRequest).toHaveBeenCalledTimes(4); + expect(mockedMakeRequest).toHaveBeenCalledTimes(6); expect(mockedMakeRequest).toHaveBeenCalledWith( expect.objectContaining({ body: expect.objectContaining({ @@ -610,3 +444,25 @@ describe('snyk test for python project', () => { }); }); }); + +function mockRequests(): void { + mockedMakeRequest.mockImplementation(async (req) => { + // Responses for feature flags + if (req.url.includes('/feature-flags/')) { + return { + res: { statusCode: 200 } as NeedleResponse, + body: { code: 200, ok: true }, + }; + } + + // default response + return { + res: { statusCode: 200 } as NeedleResponse, + body: { + result: { issuesData: {}, affectedPkgs: {} }, + meta: { org: 'test-org', isPublic: false }, + filesystemPolicy: false, + }, + }; + }); +} diff --git a/test/tap/monitor-target.test.ts b/test/tap/monitor-target.test.ts index 64cd849491..7c6d84d1c4 100644 --- a/test/tap/monitor-target.test.ts +++ b/test/tap/monitor-target.test.ts @@ -1,7 +1,6 @@ import { test } from 'tap'; import * as requestLib from 'needle'; - -const isEmpty = require('lodash.isempty'); +import * as isEmpty from 'lodash.isempty'; import * as sinon from 'sinon'; import * as cli from '../../src/cli/commands'; @@ -49,7 +48,7 @@ test('Make sure that target is sent correctly', async (t) => { const { data } = await getFakeServerRequestBody(); t.equal( requestSpy.callCount, - 5, + 7, `needle.request was called ${requestSpy.callCount} times`, ); t.ok(!isEmpty(data.target), 'target passed to request'); @@ -80,7 +79,7 @@ test("Make sure it's not failing monitor for non git projects", async (t) => { t.equal( requestSpy.callCount, - 5, + 7, `needle.request was called ${requestSpy.callCount} times`, ); t.ok(isEmpty(data.target), 'empty target passed to request'); @@ -101,7 +100,7 @@ test("Make sure it's not failing if there is no remote configured", async (t) => t.equal( requestSpy.callCount, - 5, + 7, `needle.request was called ${requestSpy.callCount} times`, ); t.ok(isEmpty(data.target), 'empty target passed to request');