@@ -18,16 +18,24 @@ jest.mock('fs', () => ({
1818jest . mock ( 'js-yaml' ) ;
1919
2020describe ( 'paths-ignore' , ( ) => {
21+ const savedCodeqlConfigPath = process . env . CODEQL_CONFIG_PATH ;
22+
2123 beforeEach ( ( ) => {
2224 jest . resetAllMocks ( ) ;
2325 clearPathsIgnoreCache ( ) ;
26+ delete process . env . CODEQL_CONFIG_PATH ;
2427 jest . spyOn ( console , 'log' ) . mockImplementation ( ( ) => { } ) ;
2528 jest . spyOn ( console , 'warn' ) . mockImplementation ( ( ) => { } ) ;
2629 jest . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } ) ;
2730 } ) ;
2831
2932 afterEach ( ( ) => {
3033 jest . restoreAllMocks ( ) ;
34+ if ( savedCodeqlConfigPath !== undefined ) {
35+ process . env . CODEQL_CONFIG_PATH = savedCodeqlConfigPath ;
36+ } else {
37+ delete process . env . CODEQL_CONFIG_PATH ;
38+ }
3139 } ) ;
3240
3341 describe ( 'findCodeqlConfigFile' , ( ) => {
@@ -62,6 +70,61 @@ describe('paths-ignore', () => {
6270 const result = findCodeqlConfigFile ( '/source' ) ;
6371 expect ( result ) . toBeUndefined ( ) ;
6472 } ) ;
73+
74+ it ( 'should use CODEQL_CONFIG_PATH when set and file exists' , ( ) => {
75+ process . env . CODEQL_CONFIG_PATH = 'default-codeql-config.yml' ;
76+ ( existsSync as jest . Mock ) . mockImplementation (
77+ ( p : string ) => p === '/source/default-codeql-config.yml' ,
78+ ) ;
79+
80+ const result = findCodeqlConfigFile ( '/source' ) ;
81+ expect ( result ) . toBe ( '/source/default-codeql-config.yml' ) ;
82+ } ) ;
83+
84+ it ( 'should use CODEQL_CONFIG_PATH for nested paths under source root' , ( ) => {
85+ process . env . CODEQL_CONFIG_PATH = 'config/my-codeql-config.yml' ;
86+ ( existsSync as jest . Mock ) . mockImplementation (
87+ ( p : string ) => p === '/source/config/my-codeql-config.yml' ,
88+ ) ;
89+
90+ const result = findCodeqlConfigFile ( '/source' ) ;
91+ expect ( result ) . toBe ( '/source/config/my-codeql-config.yml' ) ;
92+ } ) ;
93+
94+ it ( 'should return undefined when CODEQL_CONFIG_PATH file does not exist' , ( ) => {
95+ process . env . CODEQL_CONFIG_PATH = 'nonexistent-config.yml' ;
96+ ( existsSync as jest . Mock ) . mockReturnValue ( false ) ;
97+
98+ const result = findCodeqlConfigFile ( '/source' ) ;
99+ expect ( result ) . toBeUndefined ( ) ;
100+ } ) ;
101+
102+ it ( 'should reject CODEQL_CONFIG_PATH that resolves outside source root' , ( ) => {
103+ process . env . CODEQL_CONFIG_PATH = '../../etc/passwd' ;
104+ ( existsSync as jest . Mock ) . mockReturnValue ( true ) ;
105+
106+ const result = findCodeqlConfigFile ( '/source' ) ;
107+ expect ( result ) . toBeUndefined ( ) ;
108+ } ) ;
109+
110+ it ( 'should not fall back to default paths when CODEQL_CONFIG_PATH is set but missing' , ( ) => {
111+ process . env . CODEQL_CONFIG_PATH = 'missing-config.yml' ;
112+ ( existsSync as jest . Mock ) . mockImplementation (
113+ ( p : string ) => p === '/source/.github/codeql/codeql-config.yml' ,
114+ ) ;
115+
116+ const result = findCodeqlConfigFile ( '/source' ) ;
117+ // Should NOT find the default config when CODEQL_CONFIG_PATH is explicitly set
118+ expect ( result ) . toBeUndefined ( ) ;
119+ } ) ;
120+
121+ it ( 'should take precedence over default paths when CODEQL_CONFIG_PATH is set' , ( ) => {
122+ process . env . CODEQL_CONFIG_PATH = 'custom-config.yml' ;
123+ ( existsSync as jest . Mock ) . mockReturnValue ( true ) ;
124+
125+ const result = findCodeqlConfigFile ( '/source' ) ;
126+ expect ( result ) . toBe ( '/source/custom-config.yml' ) ;
127+ } ) ;
65128 } ) ;
66129
67130 describe ( 'getPathsIgnorePatterns' , ( ) => {
@@ -192,6 +255,20 @@ describe('paths-ignore', () => {
192255 const result = getPathsIgnorePatterns ( '/source' ) ;
193256 expect ( result ) . toEqual ( [ ] ) ;
194257 } ) ;
258+
259+ it ( 'should read patterns from custom config via CODEQL_CONFIG_PATH' , ( ) => {
260+ process . env . CODEQL_CONFIG_PATH = 'default-codeql-config.yml' ;
261+ ( existsSync as jest . Mock ) . mockImplementation (
262+ ( p : string ) => p === '/source/default-codeql-config.yml' ,
263+ ) ;
264+ ( readFileSync as jest . Mock ) . mockReturnValue ( 'yaml-content' ) ;
265+ ( yamlLoad as jest . Mock ) . mockReturnValue ( {
266+ 'paths-ignore' : [ 'third_party' , 'generated/**' ] ,
267+ } ) ;
268+
269+ const result = getPathsIgnorePatterns ( '/source' ) ;
270+ expect ( result ) . toEqual ( [ 'third_party' , 'generated/**' ] ) ;
271+ } ) ;
195272 } ) ;
196273
197274 describe ( 'shouldIgnorePath' , ( ) => {
0 commit comments