diff --git a/packages/core/src/utils/gitIgnoreParser.test.ts b/packages/core/src/utils/gitIgnoreParser.test.ts index 19903320913..63be94ca026 100644 --- a/packages/core/src/utils/gitIgnoreParser.test.ts +++ b/packages/core/src/utils/gitIgnoreParser.test.ts @@ -130,6 +130,12 @@ src/*.tmp expect(parser.isIgnored(outsidePath)).toBe(false); }); + it('should still evaluate files whose names start with two dots', async () => { + await createTestFile('.gitignore', '..secret.log'); + + expect(parser.isIgnored('..secret.log')).toBe(true); + }); + it('should handle relative paths correctly', () => { expect(parser.isIgnored(path.join('node_modules', 'some-package'))).toBe( true, diff --git a/packages/core/src/utils/gitIgnoreParser.ts b/packages/core/src/utils/gitIgnoreParser.ts index 21d83651a5c..ad70544b1d1 100644 --- a/packages/core/src/utils/gitIgnoreParser.ts +++ b/packages/core/src/utils/gitIgnoreParser.ts @@ -7,6 +7,7 @@ import * as fs from 'node:fs'; import * as path from 'node:path'; import ignore from 'ignore'; +import { isPathWithinRoot } from './workspaceContext.js'; export interface GitIgnoreFilter { isIgnored(filePath: string): boolean; @@ -102,16 +103,14 @@ export class GitIgnoreParser implements GitIgnoreFilter { return false; } - const absoluteFilePath = path.resolve(this.projectRoot, filePath); - if (!absoluteFilePath.startsWith(this.projectRoot)) { - return false; - } - try { const resolved = path.resolve(this.projectRoot, filePath); const relativePath = path.relative(this.projectRoot, resolved); - if (relativePath === '' || relativePath.startsWith('..')) { + if ( + relativePath === '' || + !isPathWithinRoot(resolved, this.projectRoot) + ) { return false; } diff --git a/packages/core/src/utils/qwenIgnoreParser.test.ts b/packages/core/src/utils/qwenIgnoreParser.test.ts index 8216d71f044..7324e962703 100644 --- a/packages/core/src/utils/qwenIgnoreParser.test.ts +++ b/packages/core/src/utils/qwenIgnoreParser.test.ts @@ -56,6 +56,20 @@ describe('QwenIgnoreParser', () => { false, ); }); + + it('should still evaluate files whose names start with two dots', async () => { + await createTestFile('.qwenignore', '..secret.log'); + + const parser = new QwenIgnoreParser(projectRoot); + + expect(parser.isIgnored('..secret.log')).toBe(true); + }); + + it('should not evaluate paths outside the project root', () => { + const parser = new QwenIgnoreParser(projectRoot); + + expect(parser.isIgnored(path.join('..', '..secret.log'))).toBe(false); + }); }); describe('when .qwenignore does not exist', () => { diff --git a/packages/core/src/utils/qwenIgnoreParser.ts b/packages/core/src/utils/qwenIgnoreParser.ts index 9ae5ab04cfe..81020c88654 100644 --- a/packages/core/src/utils/qwenIgnoreParser.ts +++ b/packages/core/src/utils/qwenIgnoreParser.ts @@ -7,6 +7,7 @@ import * as fs from 'node:fs'; import * as path from 'node:path'; import ignore from 'ignore'; +import { isPathWithinRoot } from './workspaceContext.js'; export interface QwenIgnoreFilter { isIgnored(filePath: string): boolean; @@ -61,7 +62,7 @@ export class QwenIgnoreParser implements QwenIgnoreFilter { const resolved = path.resolve(this.projectRoot, filePath); const relativePath = path.relative(this.projectRoot, resolved); - if (relativePath === '' || relativePath.startsWith('..')) { + if (relativePath === '' || !isPathWithinRoot(resolved, this.projectRoot)) { return false; }