Skip to content

Commit 7a8d0ab

Browse files
committed
fix(featureDev): Prevent crash on large repos or unsupported encoding during file collection
1 parent 881b70b commit 7a8d0ab

File tree

2 files changed

+14
-3
lines changed

2 files changed

+14
-3
lines changed

packages/core/src/amazonqFeatureDev/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ export const featureDevChat = 'featureDevChat'
1414

1515
export const featureName = 'Amazon Q feature development'
1616

17+
// Max allowed size for file collection
18+
export const maxRepoSize = 200 * 1024 * 1024
19+
1720
// License text that's used in codewhisperer reference log
1821
export const referenceLogText = (reference: CodeReference) =>
1922
`[${new Date().toLocaleString()}] Accepted recommendation from Amazon Q. Code provided with reference under <a href="${LicenseUtil.getLicenseHtml(

packages/core/src/amazonqFeatureDev/util/files.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { Uri } from 'vscode'
1212
import { GitIgnoreFilter } from './gitignore'
1313

1414
import AdmZip from 'adm-zip'
15-
import { PrepareRepoFailedError } from '../errors'
15+
import { ContentLengthError, PrepareRepoFailedError } from '../errors'
1616
import { getLogger } from '../../shared/logger/logger'
1717
import { maxFileSizeBytes } from '../limits'
1818
import { createHash } from 'crypto'
@@ -21,6 +21,7 @@ import { ToolkitError } from '../../shared/errors'
2121
import { AmazonqCreateUpload, Metric } from '../../shared/telemetry/telemetry'
2222
import { TelemetryHelper } from './telemetryHelper'
2323
import { sanitizeFilename } from '../../shared/utilities/textUtilities'
24+
import { maxRepoSize } from '../constants'
2425

2526
export function getExcludePattern(additionalPatterns: string[] = []) {
2627
const globAlwaysExcludedDirs = getGlobDirExcludedPatterns().map(pattern => `**/${pattern}/*`)
@@ -94,6 +95,8 @@ export async function collectFiles(
9495
return prefix === '' ? path : `${prefix}/${path}`
9596
}
9697

98+
let totalSize = 0
99+
const decoder = new TextDecoder('utf8')
97100
for (const rootPath of sourcePaths) {
98101
const allFiles = await vscode.workspace.findFiles(
99102
new vscode.RelativePattern(rootPath, '**'),
@@ -103,7 +106,8 @@ export async function collectFiles(
103106

104107
for (const file of files) {
105108
try {
106-
const fileContent = await SystemUtilities.readFile(file, new TextDecoder('utf8', { fatal: true }))
109+
const fileStat = await vscode.workspace.fs.stat(file)
110+
const fileContent = await SystemUtilities.readFile(file, decoder)
107111
const relativePath = getWorkspaceRelativePath(file.fsPath, { workspaceFolders })
108112

109113
if (relativePath) {
@@ -115,9 +119,13 @@ export async function collectFiles(
115119
zipFilePath: prefixWithFolderPrefix(relativePath.workspaceFolder, relativePath.relativePath),
116120
})
117121
}
122+
totalSize += fileStat.size
123+
if (totalSize > maxRepoSize) {
124+
throw new ContentLengthError()
125+
}
118126
} catch (error) {
119127
getLogger().debug(
120-
`featureDev: Failed to read file ${file.fsPath} when collecting repository: ${error}. Skipping the file`
128+
`featureDev: Failed to read file ${file.fsPath} when collecting repository. Skipping the file`
121129
)
122130
}
123131
}

0 commit comments

Comments
 (0)