@@ -16,38 +16,45 @@ export interface ScriptInfo {
1616}
1717
1818export class ScriptManager {
19- private scriptsDir : string ;
20- private allowedExtensions : string [ ] ;
21- private allowedPaths : string [ ] ;
22- private maxExecutionTime : number ;
19+ private scriptsDir : string | null = null ;
20+ private allowedExtensions : string [ ] | null = null ;
21+ private allowedPaths : string [ ] | null = null ;
22+ private maxExecutionTime : number | null = null ;
2323
2424 constructor ( ) {
25- // Handle both absolute and relative paths for testing
26- this . scriptsDir = env . SCRIPTS_DIRECTORY . startsWith ( '/' )
27- ? env . SCRIPTS_DIRECTORY
28- : join ( process . cwd ( ) , env . SCRIPTS_DIRECTORY ) ;
29- this . allowedExtensions = env . ALLOWED_SCRIPT_EXTENSIONS . split ( ',' ) . map ( ext => ext . trim ( ) ) ;
30- this . allowedPaths = env . ALLOWED_SCRIPT_PATHS . split ( ',' ) . map ( path => path . trim ( ) ) ;
31- this . maxExecutionTime = parseInt ( env . MAX_SCRIPT_EXECUTION_TIME , 10 ) ;
25+ // Initialize lazily to avoid accessing env vars during module load
26+ }
27+
28+ private initializeConfig ( ) {
29+ if ( this . scriptsDir === null ) {
30+ // Handle both absolute and relative paths for testing
31+ this . scriptsDir = env . SCRIPTS_DIRECTORY . startsWith ( '/' )
32+ ? env . SCRIPTS_DIRECTORY
33+ : join ( process . cwd ( ) , env . SCRIPTS_DIRECTORY ) ;
34+ this . allowedExtensions = env . ALLOWED_SCRIPT_EXTENSIONS . split ( ',' ) . map ( ext => ext . trim ( ) ) ;
35+ this . allowedPaths = env . ALLOWED_SCRIPT_PATHS . split ( ',' ) . map ( path => path . trim ( ) ) ;
36+ this . maxExecutionTime = parseInt ( env . MAX_SCRIPT_EXECUTION_TIME , 10 ) ;
37+ }
3238 }
3339
3440 /**
3541 * Get all available scripts in the scripts directory
3642 */
3743 async getScripts ( ) : Promise < ScriptInfo [ ] > {
44+ this . initializeConfig ( ) ;
3845 try {
39- const files = await readdir ( this . scriptsDir ) ;
46+ const files = await readdir ( this . scriptsDir ! ) ;
4047 const scripts : ScriptInfo [ ] = [ ] ;
4148
4249 for ( const file of files ) {
43- const filePath = join ( this . scriptsDir , file ) ;
50+ const filePath = join ( this . scriptsDir ! , file ) ;
4451 const stats = await stat ( filePath ) ;
4552
4653 if ( stats . isFile ( ) ) {
4754 const extension = extname ( file ) ;
4855
4956 // Check if file extension is allowed
50- if ( this . allowedExtensions . includes ( extension ) ) {
57+ if ( this . allowedExtensions ! . includes ( extension ) ) {
5158 // Check if file is executable
5259 const executable = await this . isExecutable ( filePath ) ;
5360
@@ -74,8 +81,9 @@ export class ScriptManager {
7481 * Get all available scripts in the ct subdirectory
7582 */
7683 async getCtScripts ( ) : Promise < ScriptInfo [ ] > {
84+ this . initializeConfig ( ) ;
7785 try {
78- const ctDir = join ( this . scriptsDir , 'ct' ) ;
86+ const ctDir = join ( this . scriptsDir ! , 'ct' ) ;
7987 const files = await readdir ( ctDir ) ;
8088 const scripts : ScriptInfo [ ] = [ ] ;
8189
@@ -87,7 +95,7 @@ export class ScriptManager {
8795 const extension = extname ( file ) ;
8896
8997 // Check if file extension is allowed
90- if ( this . allowedExtensions . includes ( extension ) ) {
98+ if ( this . allowedExtensions ! . includes ( extension ) ) {
9199 // Check if file is executable
92100 const executable = await this . isExecutable ( filePath ) ;
93101
@@ -143,8 +151,9 @@ export class ScriptManager {
143151 * Validate if a script path is allowed to be executed
144152 */
145153 validateScriptPath ( scriptPath : string ) : { valid : boolean ; message ?: string } {
154+ this . initializeConfig ( ) ;
146155 const resolvedPath = resolve ( scriptPath ) ;
147- const scriptsDirResolved = resolve ( this . scriptsDir ) ;
156+ const scriptsDirResolved = resolve ( this . scriptsDir ! ) ;
148157
149158 // Check if the script is within the allowed directory
150159 if ( ! resolvedPath . startsWith ( scriptsDirResolved ) ) {
@@ -158,7 +167,7 @@ export class ScriptManager {
158167 const relativePath = resolvedPath . replace ( scriptsDirResolved , '' ) . replace ( / \\ / g, '/' ) ;
159168 const normalizedRelativePath = relativePath . startsWith ( '/' ) ? relativePath : '/' + relativePath ;
160169
161- const isAllowed = this . allowedPaths . some ( allowedPath => {
170+ const isAllowed = this . allowedPaths ! . some ( allowedPath => {
162171 const normalizedAllowedPath = allowedPath . startsWith ( '/' ) ? allowedPath : '/' + allowedPath ;
163172 // For root path '/', allow files directly in the scripts directory (no subdirectories)
164173 if ( normalizedAllowedPath === '/' ) {
@@ -177,10 +186,10 @@ export class ScriptManager {
177186
178187 // Check file extension
179188 const extension = extname ( scriptPath ) ;
180- if ( ! this . allowedExtensions . includes ( extension ) ) {
189+ if ( ! this . allowedExtensions ! . includes ( extension ) ) {
181190 return {
182191 valid : false ,
183- message : `File extension '${ extension } ' is not allowed. Allowed extensions: ${ this . allowedExtensions . join ( ', ' ) } `
192+ message : `File extension '${ extension } ' is not allowed. Allowed extensions: ${ this . allowedExtensions ! . join ( ', ' ) } `
184193 } ;
185194 }
186195
@@ -227,7 +236,7 @@ export class ScriptManager {
227236
228237 // Spawn the process
229238 const childProcess = spawn ( command , args , {
230- cwd : this . scriptsDir ,
239+ cwd : this . scriptsDir ! ,
231240 stdio : [ 'pipe' , 'pipe' , 'pipe' ] ,
232241 shell : true
233242 } ) ;
@@ -237,7 +246,7 @@ export class ScriptManager {
237246 if ( ! childProcess . killed ) {
238247 childProcess . kill ( 'SIGTERM' ) ;
239248 }
240- } , this . maxExecutionTime ) ;
249+ } , this . maxExecutionTime ! ) ;
241250
242251 // Clean up timeout when process exits
243252 childProcess . on ( 'exit' , ( ) => {
@@ -268,11 +277,12 @@ export class ScriptManager {
268277 allowedPaths : string [ ] ;
269278 maxExecutionTime : number ;
270279 } {
280+ this . initializeConfig ( ) ;
271281 return {
272- path : this . scriptsDir ,
273- allowedExtensions : this . allowedExtensions ,
274- allowedPaths : this . allowedPaths ,
275- maxExecutionTime : this . maxExecutionTime
282+ path : this . scriptsDir ! ,
283+ allowedExtensions : this . allowedExtensions ! ,
284+ allowedPaths : this . allowedPaths ! ,
285+ maxExecutionTime : this . maxExecutionTime !
276286 } ;
277287 }
278288}
0 commit comments