Skip to content

Commit 2c6273d

Browse files
authored
@W-21567855 fix: allowing a leading slash to the output dir (#1711)
* fix: allowing a leading slash to the output dir * fix: allowing a leading slash to the output dir Made-with: Cursor
1 parent 3c998a9 commit 2c6273d

2 files changed

Lines changed: 15 additions & 9 deletions

File tree

src/resolve/adapters/webApplicationValidation.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ const MAX_WEBAPPLICATION_JSON_BYTES = 102_400; // 100 KB
7878
// Matches ".." as a standalone path segment.
7979
const DOT_DOT_SEGMENT = /(?:^|[/\\])\.\.[/\\]|(?:^|[/\\])\.\.$/;
8080

81-
/** Strip leading separators so "/index.html" resolves relative to outputDir. */
81+
/** Strip leading forward slashes so "/index.html" resolves relative to outputDir. Only strips '/', not backslashes. */
8282
function stripLeadingSep(p: string): string {
83-
return p.replace(new RegExp(`^[${sep.replace(/\\/g, '\\\\')}/]+`), '');
83+
return p.replace(/^\/+/, '');
8484
}
8585

8686
/** Returns a reason string if the path contains unsafe patterns, undefined otherwise. */
@@ -233,13 +233,14 @@ function validateOutputDir(value: unknown): string {
233233
'Set outputDir to a directory path like "dist" or "build".',
234234
]);
235235
}
236-
if (value.length === 0) {
236+
const stripped = stripLeadingSep(value);
237+
if (stripped.length === 0) {
237238
throw createConfigError(msgs.getMessage('webapp_empty_value', ['outputDir']), [
238239
'Provide a directory name, e.g. "dist".',
239240
]);
240241
}
241-
assertSafePath(value, 'outputDir');
242-
return value;
242+
assertSafePath(stripped, 'outputDir');
243+
return stripped;
243244
}
244245

245246
function validateRouting(value: unknown): void {

test/resolve/adapters/webApplicationValidation.test.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,13 +180,18 @@ describe('validateWebApplicationJson (direct unit tests)', () => {
180180
);
181181
});
182182

183-
it('throws for absolute path starting with /', () => {
184-
expectConfigError(
185-
() => validateWebApplicationJson(toBuffer({ outputDir: '/etc/passwd' }), DESCRIPTOR_PATH, CONTENT_PATH, tree),
186-
'absolute'
183+
it('strips leading / from outputDir and validates the rest', () => {
184+
expectFileError(() =>
185+
validateWebApplicationJson(toBuffer({ outputDir: '/etc/passwd' }), DESCRIPTOR_PATH, CONTENT_PATH, tree)
187186
);
188187
});
189188

189+
it('succeeds when outputDir starts with / and directory exists', () => {
190+
expect(() =>
191+
validateWebApplicationJson(toBuffer({ outputDir: '/dist' }), DESCRIPTOR_PATH, CONTENT_PATH, tree)
192+
).to.not.throw();
193+
});
194+
190195
it('throws for absolute path starting with backslash', () => {
191196
expectConfigError(() =>
192197
validateWebApplicationJson(toBuffer({ outputDir: '\\Windows' }), DESCRIPTOR_PATH, CONTENT_PATH, tree)

0 commit comments

Comments
 (0)