Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
Original file line number Diff line number Diff line change
Expand Up @@ -2,143 +2,38 @@
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

import assert from 'assert'
import * as vscode from 'vscode'
import * as sinon from 'sinon'
import * as assert from 'assert'
import * as semver from 'semver'
import { DefaultCodeWhispererClient } from '../../../codewhisperer/client/codewhisperer'
import * as startSecurityScan from '../../../codewhisperer/commands/startSecurityScan'
import { SecurityPanelViewProvider } from '../../../codewhisperer/views/securityPanelViewProvider'
import { FakeExtensionContext } from '../../fakeExtensionContext'
import * as diagnosticsProvider from '../../../codewhisperer/service/diagnosticsProvider'
import { getTestWorkspaceFolder } from '../../../testInteg/integrationTestsUtilities'
import { join } from 'path'
import {
assertTelemetry,
closeAllEditors,
createTestWorkspaceFolder,
getFetchStubWithResponse,
toFile,
} from '../../testUtil'
import { stub } from '../../utilities/stubber'
import { AWSError, HttpResponse } from 'aws-sdk'
import { getTestWindow } from '../../shared/vscode/window'
import { SeverityLevel } from '../../shared/vscode/message'
import { cancel } from '../../../shared/localizedText'
import * as model from '../../codewhisperer/models/model'
import * as timeoutUtils from '../../shared/utilities/timeoutUtils'
import * as diagnosticsProvider from '../../codewhisperer/service/diagnosticsProvider'
import * as startSecurityScan from '../../codewhisperer/commands/startSecurityScan'
import * as errors from '../../shared/errors'
import {
showScannedFilesMessage,
SecurityPanelViewProvider,
stopScanMessage,
CodeAnalysisScope,
showScannedFilesMessage,
projectScansLimitReached,
} from '../../../codewhisperer/models/constants'
import * as model from '../../../codewhisperer/models/model'
import { CodewhispererSecurityScan } from '../../../shared/telemetry/telemetry.gen'
import * as errors from '../../../shared/errors'
import * as timeoutUtils from '../../../shared/utilities/timeoutUtils'
import { performanceTest } from '../../../shared/performance/performance'

const mockCreateCodeScanResponse = {
$response: {
data: {
jobId: 'jobId',
status: 'Pending',
},
requestId: 'requestId',
hasNextPage: () => false,
error: undefined,
nextPage: () => undefined,
redirectCount: 0,
retryCount: 0,
httpResponse: new HttpResponse(),
},
jobId: 'jobId',
status: 'Pending',
}

const mockCreateUploadUrlResponse = {
$response: {
data: {
uploadId: 'uploadId',
uploadUrl: 'uploadUrl',
},
requestId: 'requestId',
hasNextPage: () => false,
error: undefined,
nextPage: () => undefined,
redirectCount: 0,
retryCount: 0,
httpResponse: new HttpResponse(),
},
uploadId: 'uploadId',
uploadUrl: 'https://test.com',
}

const mockGetCodeScanResponse = {
$response: {
data: {
status: 'Completed',
},
requestId: 'requestId',
hasNextPage: () => false,
error: undefined,
nextPage: () => undefined,
redirectCount: 0,
retryCount: 0,
httpResponse: new HttpResponse(),
},
status: 'Completed',
}

const mockCodeScanFindings = JSON.stringify([
{
filePath: 'workspaceFolder/python3.7-plain-sam-app/hello_world/app.py',
startLine: 1,
endLine: 1,
title: 'title',
description: {
text: 'text',
markdown: 'markdown',
},
detectorId: 'detectorId',
detectorName: 'detectorName',
findingId: 'findingId',
relatedVulnerabilities: [],
severity: 'High',
remediation: {
recommendation: {
text: 'text',
url: 'url',
},
suggestedFixes: [],
},
codeSnippet: [],
} satisfies model.RawCodeScanIssue,
])

const mockListCodeScanFindingsResponse = {
$response: {
data: {
codeScanFindings: mockCodeScanFindings,
},
requestId: 'requestId',
hasNextPage: () => false,
error: undefined,
nextPage: () => undefined,
redirectCount: 0,
retryCount: 0,
httpResponse: new HttpResponse(),
},
codeScanFindings: mockCodeScanFindings,
}

let extensionContext: FakeExtensionContext
let mockSecurityPanelViewProvider: SecurityPanelViewProvider
let appRoot: string
let appCodePath: string
let editor: vscode.TextEditor
} from '../../codewhisperer'
import { getTestWorkspaceFolder } from '../../testInteg/integrationTestsUtilities'
import { FakeExtensionContext } from '../fakeExtensionContext'
import { join } from 'path'
import { assertTelemetry, closeAllEditors, getFetchStubWithResponse } from '../testUtil'
import { AWSError } from 'aws-sdk'
import { CodeAnalysisScope } from '../../codewhisperer'
import { getTestWindow } from '../shared/vscode/window'
import { SeverityLevel } from '../../test/shared/vscode/message'
import { cancel, CodewhispererSecurityScan } from '../../shared'
import { createMockClient, mockGetCodeScanResponse } from './utils'

describe('startSecurityScan', function () {
let extensionContext: FakeExtensionContext
let mockSecurityPanelViewProvider: SecurityPanelViewProvider
let appRoot: string
let appCodePath: string
let editor: vscode.TextEditor
const workspaceFolder = getTestWorkspaceFolder()
beforeEach(async function () {
extensionContext = await FakeExtensionContext.create()
Expand All @@ -155,15 +50,6 @@ describe('startSecurityScan', function () {
after(async function () {
await closeAllEditors()
})
const createClient = () => {
const mockClient = stub(DefaultCodeWhispererClient)

mockClient.createCodeScan.resolves(mockCreateCodeScanResponse)
mockClient.createUploadUrl.resolves(mockCreateUploadUrlResponse)
mockClient.getCodeScan.resolves(mockGetCodeScanResponse)
mockClient.listCodeScanFindings.resolves(mockListCodeScanFindingsResponse)
return mockClient
}

const openTestFile = async (filePath: string) => {
const doc = await vscode.workspace.openTextDocument(filePath)
Expand All @@ -180,7 +66,7 @@ describe('startSecurityScan', function () {
await startSecurityScan.startSecurityScan(
mockSecurityPanelViewProvider,
editor,
createClient(),
createMockClient(),
extensionContext,
CodeAnalysisScope.PROJECT
)
Expand All @@ -199,7 +85,7 @@ describe('startSecurityScan', function () {
await startSecurityScan.startSecurityScan(
mockSecurityPanelViewProvider,
editor,
createClient(),
createMockClient(),
extensionContext,
CodeAnalysisScope.FILE
)
Expand Down Expand Up @@ -227,7 +113,7 @@ describe('startSecurityScan', function () {
const scanPromise = startSecurityScan.startSecurityScan(
mockSecurityPanelViewProvider,
editor,
createClient(),
createMockClient(),
extensionContext,
CodeAnalysisScope.PROJECT
)
Expand All @@ -253,7 +139,7 @@ describe('startSecurityScan', function () {
const scanPromise = startSecurityScan.startSecurityScan(
mockSecurityPanelViewProvider,
editor,
createClient(),
createMockClient(),
extensionContext,
CodeAnalysisScope.PROJECT
)
Expand All @@ -273,7 +159,7 @@ describe('startSecurityScan', function () {
const scanPromise = startSecurityScan.startSecurityScan(
mockSecurityPanelViewProvider,
editor,
createClient(),
createMockClient(),
extensionContext,
CodeAnalysisScope.FILE
)
Expand All @@ -297,7 +183,7 @@ describe('startSecurityScan', function () {
await startSecurityScan.startSecurityScan(
mockSecurityPanelViewProvider,
editor,
createClient(),
createMockClient(),
extensionContext,
CodeAnalysisScope.PROJECT
)
Expand All @@ -316,14 +202,14 @@ describe('startSecurityScan', function () {
const scanPromise = startSecurityScan.startSecurityScan(
mockSecurityPanelViewProvider,
editor,
createClient(),
createMockClient(),
extensionContext,
CodeAnalysisScope.FILE
)
await startSecurityScan.startSecurityScan(
mockSecurityPanelViewProvider,
editor,
createClient(),
createMockClient(),
extensionContext,
CodeAnalysisScope.FILE
)
Expand All @@ -347,14 +233,14 @@ describe('startSecurityScan', function () {
const scanPromise = startSecurityScan.startSecurityScan(
mockSecurityPanelViewProvider,
editor,
createClient(),
createMockClient(),
extensionContext,
CodeAnalysisScope.PROJECT
)
await startSecurityScan.startSecurityScan(
mockSecurityPanelViewProvider,
editor,
createClient(),
createMockClient(),
extensionContext,
CodeAnalysisScope.FILE
)
Expand All @@ -374,7 +260,7 @@ describe('startSecurityScan', function () {
it('Should handle failed scan job status', async function () {
getFetchStubWithResponse({ status: 200, statusText: 'testing stub' })

const mockClient = createClient()
const mockClient = createMockClient()
mockClient.getCodeScan.resolves({
...mockGetCodeScanResponse,
status: 'Failed',
Expand All @@ -397,7 +283,7 @@ describe('startSecurityScan', function () {

it('Should show notification when throttled for project scans', async function () {
getFetchStubWithResponse({ status: 200, statusText: 'testing stub' })
const mockClient = createClient()
const mockClient = createMockClient()
mockClient.createCodeScan.throws({
code: 'ThrottlingException',
time: new Date(),
Expand Down Expand Up @@ -426,7 +312,7 @@ describe('startSecurityScan', function () {
it('Should set monthly quota exceeded when throttled for file scans', async function () {
getFetchStubWithResponse({ status: 200, statusText: 'testing stub' })
await model.CodeScansState.instance.setScansEnabled(true)
const mockClient = createClient()
const mockClient = createMockClient()
mockClient.createCodeScan.throws({
code: 'ThrottlingException',
time: new Date(),
Expand Down Expand Up @@ -454,78 +340,3 @@ describe('startSecurityScan', function () {
} as unknown as CodewhispererSecurityScan)
})
})

describe('startSecurityScanPerformanceTest', function () {
beforeEach(async function () {
extensionContext = await FakeExtensionContext.create()
mockSecurityPanelViewProvider = new SecurityPanelViewProvider(extensionContext)
const folder = await createTestWorkspaceFolder()
const mockFilePath = join(folder.uri.fsPath, 'app.py')
await toFile('hello_world', mockFilePath)
appCodePath = mockFilePath
editor = await openTestFile(appCodePath)
await model.CodeScansState.instance.setScansEnabled(false)
sinon.stub(timeoutUtils, 'sleep')
})

afterEach(function () {
sinon.restore()
})

after(async function () {
await closeAllEditors()
})

const createClient = () => {
const mockClient = stub(DefaultCodeWhispererClient)
mockClient.createCodeScan.resolves(mockCreateCodeScanResponse)
mockClient.createUploadUrl.resolves(mockCreateUploadUrlResponse)
mockClient.getCodeScan.resolves(mockGetCodeScanResponse)
mockClient.listCodeScanFindings.resolves(mockListCodeScanFindingsResponse)
return mockClient
}

const openTestFile = async (filePath: string) => {
const doc = await vscode.workspace.openTextDocument(filePath)
return await vscode.window.showTextDocument(doc, {
selection: new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 1)),
})
}

performanceTest({}, 'Should calculate cpu and memory usage for file scans', function () {
return {
setup: async () => {
getFetchStubWithResponse({ status: 200, statusText: 'testing stub' })
const commandSpy = sinon.spy(vscode.commands, 'executeCommand')
const securityScanRenderSpy = sinon.spy(diagnosticsProvider, 'initSecurityScanRender')
await model.CodeScansState.instance.setScansEnabled(true)
return { commandSpy, securityScanRenderSpy }
},
execute: async () => {
await startSecurityScan.startSecurityScan(
mockSecurityPanelViewProvider,
editor,
createClient(),
extensionContext,
CodeAnalysisScope.FILE
)
},
verify: ({
commandSpy,
securityScanRenderSpy,
}: {
commandSpy: sinon.SinonSpy
securityScanRenderSpy: sinon.SinonSpy
}) => {
assert.ok(commandSpy.neverCalledWith('workbench.action.problems.focus'))
assert.ok(securityScanRenderSpy.calledOnce)
const warnings = getTestWindow().shownMessages.filter((m) => m.severity === SeverityLevel.Warning)
assert.strictEqual(warnings.length, 0)
assertTelemetry('codewhisperer_securityScan', {
codewhispererCodeScanScope: 'FILE',
passive: true,
})
},
}
})
})
Loading
Loading