@@ -20,12 +20,12 @@ export class ProjectCleanupService implements IProjectCleanupService {
2020 private $fs : IFileSystem ,
2121 private $logger : ILogger ,
2222 private $projectHelper : IProjectHelper ,
23- private $terminalSpinnerService : ITerminalSpinnerService
23+ private $terminalSpinnerService : ITerminalSpinnerService ,
2424 ) { }
2525
2626 public async clean (
2727 pathsToClean : string [ ] ,
28- options ?: IProjectCleanupOptions
28+ options ?: IProjectCleanupOptions ,
2929 ) : Promise < IProjectCleanupResult > {
3030 this . spinner = this . $terminalSpinnerService . createSpinner ( {
3131 isSilent : options ?. silent ,
@@ -39,10 +39,10 @@ export class ProjectCleanupService implements IProjectCleanupService {
3939 ( error ) => {
4040 this . $logger . trace (
4141 `Encountered error while cleaning. Error is: ${ error . message } .` ,
42- error
42+ error ,
4343 ) ;
4444 return { ok : false } ;
45- }
45+ } ,
4646 ) ;
4747 if ( stats && "size" in cleanRes ) {
4848 stats . set ( pathToClean , cleanRes . size ) ;
@@ -63,7 +63,7 @@ export class ProjectCleanupService implements IProjectCleanupService {
6363
6464 public async cleanPath (
6565 pathToClean : string ,
66- options ?: IProjectCleanupOptions
66+ options ?: IProjectCleanupOptions ,
6767 ) : Promise < IProjectPathCleanupResult > {
6868 const dryRun = options ?. dryRun ?? false ;
6969 const logPrefix = dryRun ? color . grey ( "(dry run) " ) : "" ;
@@ -77,9 +77,21 @@ export class ProjectCleanupService implements IProjectCleanupService {
7777 }
7878
7979 const filePath = path . resolve ( this . $projectHelper . projectDir , pathToClean ) ;
80- const displayPath = color . yellow (
81- `${ path . relative ( this . $projectHelper . projectDir , filePath ) } `
80+ const relativePath = path . relative (
81+ this . $projectHelper . projectDir ,
82+ filePath ,
8283 ) ;
84+ const displayPath = color . yellow ( `${ relativePath } ` ) ;
85+
86+ // Paths reach here from the project config - buildPath and
87+ // cli.pathsToClean among them - where a leading `..` resolves onto
88+ // directories the project does not own.
89+ if ( relativePath . startsWith ( ".." ) || path . isAbsolute ( relativePath ) ) {
90+ this . $logger . warn (
91+ `Skipping '${ filePath } ' because it is outside the project directory.` ,
92+ ) ;
93+ return { ok : false } ;
94+ }
8395
8496 this . $logger . trace ( `${ logPrefix } Trying to clean '${ filePath } '` ) ;
8597
@@ -93,13 +105,13 @@ export class ProjectCleanupService implements IProjectCleanupService {
93105
94106 if ( stat . isDirectory ( ) ) {
95107 this . $logger . trace (
96- `${ logPrefix } Path '${ filePath } ' is a directory, deleting.`
108+ `${ logPrefix } Path '${ filePath } ' is a directory, deleting.` ,
97109 ) ;
98110 ! dryRun && this . $fs . deleteDirectorySafe ( filePath ) ;
99111 fileType = "directory" ;
100112 } else {
101113 this . $logger . trace (
102- `${ logPrefix } Path '${ filePath } ' is a file, deleting.`
114+ `${ logPrefix } Path '${ filePath } ' is a file, deleting.` ,
103115 ) ;
104116 ! dryRun && this . $fs . deleteFile ( filePath ) ;
105117 fileType = "file" ;
@@ -122,7 +134,7 @@ export class ProjectCleanupService implements IProjectCleanupService {
122134
123135 this . $logger . trace ( `${ logPrefix } Path '${ filePath } ' not found, skipping.` ) ;
124136 this . spinner . info (
125- `${ logPrefix } Skipping ${ displayPath } because it doesn't exist.`
137+ `${ logPrefix } Skipping ${ displayPath } because it doesn't exist.` ,
126138 ) ;
127139
128140 if ( options ?. stats ) {
0 commit comments