-
Bug
-
Resolution: Fixed
-
High
-
10.1.0, 9.2.20, 9.6.8, 10.0.3
-
None
-
1
-
Severity 2 - Major
-
4
-
Problem
Bamboo Specs scan fails when publishing Projects permissions showing a message similar to the one below in the logs:
2024-11-15 16:52:18,592 DEBUG [23-BAM::SpecsDetection:pool-24-thread-3] [AllTypesSpecsImporter] Processing /var/atlassian/application-data/bamboo/local-working-dir/serverSide/REPOSITORY_STORED_SPECS/repository-7077889-master/internal-yamls/project-permissions/00001-4bc1d750-project-permissions-for-project-PRO1.yaml 2024-11-15 16:52:18,603 INFO [23-BAM::SpecsDetection:pool-24-thread-3] [RssExecutionDirectoryManagerImpl] Cleaning all RSS execution cache for repository 7077889 2024-11-15 16:52:18,603 DEBUG [23-BAM::SpecsDetection:pool-24-thread-3] [RssExecutionDirectoryManagerImpl] Removing RSS cache repository /var/atlassian/application-data/bamboo/local-working-dir/serverSide/REPOSITORY_STORED_SPECS/repository-7077889-master 2024-11-15 16:52:18,606 WARN [23-BAM::SpecsDetection:pool-24-thread-3] [AllTypesSpecsImporter] java.nio.file.NoSuchFileException: /var/atlassian/application-data/bamboo/local-working-dir/serverSide/REPOSITORY_STORED_SPECS/repository-7077889-master/internal-yamls/project-permissions/00003-b0fb92b8-project-permissions-for-project-PRO3.yaml at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92) ~[?:?] at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:106) ~[?:?] at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111) ~[?:?] at java.base/sun.nio.fs.UnixPath.toRealPath(UnixPath.java:825) ~[?:?] at com.atlassian.bamboo.configuration.external.rss.AllTypesSpecsImporter.importBambooYamlsWithImporter(AllTypesSpecsImporter.java:128) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.configuration.external.rss.AllTypesSpecsImporter.importBambooYamlsOfAllTypes(AllTypesSpecsImporter.java:69) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.configuration.external.rss.JavaSpecsImportServiceImpl.lambda$processSpecs$2(JavaSpecsImportServiceImpl.java:88) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.configuration.external.rss.SpecsOptimizeProcessor.processSpecs(SpecsOptimizeProcessor.java:43) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.configuration.external.rss.JavaSpecsImportServiceImpl.processSpecs(JavaSpecsImportServiceImpl.java:101) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.configuration.external.RepositoryStoredSpecsServiceImpl.runBambooSpecs(RepositoryStoredSpecsServiceImpl.java:204) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.configuration.external.RssDetectionServiceImpl.runRssDetection(RssDetectionServiceImpl.java:374) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.configuration.external.detection.RssDetectionRunnable.run(RssDetectionRunnable.java:51) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[?:?] at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[?:?] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[?:?] at com.atlassian.bamboo.utils.BambooRunnables$1.run(BambooRunnables.java:46) ~[atlassian-bamboo-api-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.security.ImpersonationHelper.runWith(ImpersonationHelper.java:26) ~[atlassian-bamboo-api-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.security.ImpersonationHelper.runWithSystemAuthority(ImpersonationHelper.java:17) ~[atlassian-bamboo-api-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.security.ImpersonationHelper.lambda$makeRunnableWithSystemAuthority$0(ImpersonationHelper.java:38) ~[atlassian-bamboo-api-10.1.0-SNAPSHOT.jar:?] at java.base/java.lang.Thread.run(Thread.java:840) [?:?]
Environment
- Bamboo Data Center
- Repository Stored Specs / Java Specs
Steps to Reproduce
There are multiple conditions that may trigger this same bug such as modifying user/groups but this requires more randomness and reproducing it is hard. This issue is caused by four possible "triggers" in the code:
- RssPermissionManagerImpl#removeRepository
- RssPermissionManagerImpl#revokeProjectAccess
- RssPermissionManagerImpl#revokeDeploymentProjectAccess
- RssPermissionManagerImpl#revokeRepositoryAccess
The steps below demonstrate only one of the possible reproduction avenues, which is modifying the Project's Specs repository permissions.
- Add 4 Projects (BAM, PRO1, PRO2, PRO3)
- Add various users and groups - Check the specs code below for reference
- Create a "Dragons" Specs repository in Bamboo
- Use the following Specs code in the Dragons repository. The code below will make changes to the Projects by changing users and groups permissions randomly (to force changes on evey run). It also adds the "Dragons" repository to multiple projects as an allowed Specs repository:
bamboo-specs/src/main/java/tutorial/ProjectPermissionsSpec.java
package tutorial; import com.atlassian.bamboo.specs.api.BambooSpec; import com.atlassian.bamboo.specs.api.builders.permission.PermissionType; import com.atlassian.bamboo.specs.api.builders.permission.Permissions; import com.atlassian.bamboo.specs.api.builders.permission.ProjectPermissions; import com.atlassian.bamboo.specs.util.BambooServer; import java.util.ArrayList; import java.util.List; import java.util.Random; @BambooSpec public class ProjectPermissionsSpec { private final List<String> projectStaticAdmins = new ArrayList<>(); private final List<String> projectKeys = new ArrayList<>(); private final List<String> users = new ArrayList<>(); private final List<String> groups = new ArrayList<>(); private final List<PermissionType> permissions = new ArrayList<>(); private final List<String> specsRepositories = new ArrayList<>(); private final Random random = new Random(); public ProjectPermissionsSpec() { // Initialize with the static admin users projectStaticAdmins.add("ealvarenga"); projectStaticAdmins.add("bamboo"); // Initialize with the project keys projectKeys.add("BAM"); projectKeys.add("PRO1"); projectKeys.add("PRO2"); projectKeys.add("PRO3"); // Initialize with example users users.add("ship"); users.add("gearbox"); users.add("integration"); users.add("sonar"); // Initialize with example groups groups.add("fisheye-users"); groups.add("bitbucket-users"); groups.add("paymentsART"); groups.add("ship-group"); // Initialize with permission types permissions.add(PermissionType.VIEW); permissions.add(PermissionType.CREATE); permissions.add(PermissionType.ADMIN); permissions.add(PermissionType.CREATE_REPOSITORY); // Add SpecsRepositories specsRepositories.add("Dragons"); } /** * Generates and returns a ProjectPermissions object for a given project key, * representing the user/group permissions for this project. * * @param projectKey the key of the project * @return Generic permissions for the project */ public ProjectPermissions generateProjectPermissions(String projectKey) { Permissions projectPermissions = new Permissions(); // Randomly decide to add each user for (String user : users) { if (random.nextBoolean()) { // 50% chance to add the user PermissionType randomPermission = permissions.get(random.nextInt(permissions.size())); projectPermissions.userPermissions(user, randomPermission); System.out.println("User " + user + " assigned " + randomPermission + " permission to project " + projectKey); } } // Randomly decide to add each group for (String group : groups) { if (random.nextBoolean()) { // 50% chance to add the group PermissionType randomPermission = permissions.get(random.nextInt(permissions.size())); projectPermissions.groupPermissions(group, randomPermission); System.out.println("Group " + group + " assigned " + randomPermission + " permission to project " + projectKey); } } // Assign static admin permissions to static users for (String admin : projectStaticAdmins) { projectPermissions.userPermissions(admin, PermissionType.ADMIN); System.out.println("Static admin " + admin + " assigned ADMIN permission to project " + projectKey); } ProjectPermissions projectPermissionsObject = new ProjectPermissions(projectKey) .projectPermissions(projectPermissions); // Add specs repositories to the project for (String specsRepository : specsRepositories) { projectPermissionsObject.specsRepositories(specsRepository); System.out.println("Specs Repository " + specsRepository + " added to the project " + projectKey); } return projectPermissionsObject; } public static void main(String... argv) { BambooServer bambooServer = new BambooServer("https://bamboo1000.osalva.net"); ProjectPermissionsSpec projectPermissionsSpec = new ProjectPermissionsSpec(); // Iterate over each project key and publish the permissions for (String projectKey : projectPermissionsSpec.projectKeys) { ProjectPermissions projectPermissions = projectPermissionsSpec.generateProjectPermissions(projectKey); bambooServer.publish(projectPermissions); System.out.println("Published permissions for project: " + projectKey); } } }
- Push the change/Scan the repository for specs. It should work on the first time
- Commend the following Block from the Specs code and commit it:
// Add specs repositories to the project for (String specsRepository : specsRepositories) { projectPermissionsObject.specsRepositories(specsRepository); System.out.println("Specs Repository " + specsRepository + " added to the project " + projectKey); }
- Push the change/Scan the repository for specs. It fails with a message such as:
[RssExecutionDirectoryManagerImpl] Cleaning all RSS execution cache for repository 7077889 [AllTypesSpecsImporter] java.nio.file.NoSuchFileException:
Expected Results
Bamboo should process the Java Specs changes via RSS normally and modify the permissions as requested. Any cleanups triggered by RssPermissionManagerImpl should be carried over to the end of the process or be actioned on a per-object basis; meaning remove one object at a time on demand and not the complete <bamboo-home>/local-working-dir/serverSide/REPOSITORY_STORED_SPECS/repository-123456-master/internal-yamls/ folder.
Actual Results
Bamboo gets into a race condition which will call RssPermissionManagerImpl#scheduleFullSpecsUpdate in the middle of Specs processing. scheduleFullSpecsUpdate will call cleanExecutionCacheDirectory which will remove all the files in the temporary YAML folder and generate the following:
2024-11-15 16:52:18,603 INFO [23-BAM::SpecsDetection:pool-24-thread-3] [RssExecutionDirectoryManagerImpl] Cleaning all RSS execution cache for repository 7077889 2024-11-15 16:52:18,603 DEBUG [23-BAM::SpecsDetection:pool-24-thread-3] [RssExecutionDirectoryManagerImpl] Removing RSS cache repository /var/atlassian/application-data/bamboo/local-working-dir/serverSide/REPOSITORY_STORED_SPECS/repository-7077889-master 2024-11-15 16:52:18,606 WARN [23-BAM::SpecsDetection:pool-24-thread-3] [AllTypesSpecsImporter] java.nio.file.NoSuchFileException: /var/atlassian/application-data/bamboo/local-working-dir/serverSide/REPOSITORY_STORED_SPECS/repository-7077889-master/internal-yamls/project-permissions/00003-b0fb92b8-project-permissions-for-project-PRO3.yaml
Workaround
Isolate the Project Permissions change and push them either from:
- Move the Project Permissions to a dedicated Specs repository which does not share the same Specs repository used to set Plan/Deployment Specs
or - Publish the changes using Maven over mvn -Ppublish - That will still make Bamboo call the cleanup but it will not remove any YAML files as the files are generated locally on the machine that executed Maven
or - Adjust the Project permissions manually
Notes
Bamboo Specs scan fails when changing Project permissions due to race condition
-
Bug
-
Resolution: Fixed
-
High
-
10.1.0, 9.2.20, 9.6.8, 10.0.3
-
None
-
1
-
Severity 2 - Major
-
4
-
Problem
Bamboo Specs scan fails when publishing Projects permissions showing a message similar to the one below in the logs:
2024-11-15 16:52:18,592 DEBUG [23-BAM::SpecsDetection:pool-24-thread-3] [AllTypesSpecsImporter] Processing /var/atlassian/application-data/bamboo/local-working-dir/serverSide/REPOSITORY_STORED_SPECS/repository-7077889-master/internal-yamls/project-permissions/00001-4bc1d750-project-permissions-for-project-PRO1.yaml 2024-11-15 16:52:18,603 INFO [23-BAM::SpecsDetection:pool-24-thread-3] [RssExecutionDirectoryManagerImpl] Cleaning all RSS execution cache for repository 7077889 2024-11-15 16:52:18,603 DEBUG [23-BAM::SpecsDetection:pool-24-thread-3] [RssExecutionDirectoryManagerImpl] Removing RSS cache repository /var/atlassian/application-data/bamboo/local-working-dir/serverSide/REPOSITORY_STORED_SPECS/repository-7077889-master 2024-11-15 16:52:18,606 WARN [23-BAM::SpecsDetection:pool-24-thread-3] [AllTypesSpecsImporter] java.nio.file.NoSuchFileException: /var/atlassian/application-data/bamboo/local-working-dir/serverSide/REPOSITORY_STORED_SPECS/repository-7077889-master/internal-yamls/project-permissions/00003-b0fb92b8-project-permissions-for-project-PRO3.yaml at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92) ~[?:?] at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:106) ~[?:?] at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111) ~[?:?] at java.base/sun.nio.fs.UnixPath.toRealPath(UnixPath.java:825) ~[?:?] at com.atlassian.bamboo.configuration.external.rss.AllTypesSpecsImporter.importBambooYamlsWithImporter(AllTypesSpecsImporter.java:128) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.configuration.external.rss.AllTypesSpecsImporter.importBambooYamlsOfAllTypes(AllTypesSpecsImporter.java:69) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.configuration.external.rss.JavaSpecsImportServiceImpl.lambda$processSpecs$2(JavaSpecsImportServiceImpl.java:88) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.configuration.external.rss.SpecsOptimizeProcessor.processSpecs(SpecsOptimizeProcessor.java:43) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.configuration.external.rss.JavaSpecsImportServiceImpl.processSpecs(JavaSpecsImportServiceImpl.java:101) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.configuration.external.RepositoryStoredSpecsServiceImpl.runBambooSpecs(RepositoryStoredSpecsServiceImpl.java:204) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.configuration.external.RssDetectionServiceImpl.runRssDetection(RssDetectionServiceImpl.java:374) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.configuration.external.detection.RssDetectionRunnable.run(RssDetectionRunnable.java:51) ~[atlassian-bamboo-import-export-10.1.0-SNAPSHOT.jar:?] at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[?:?] at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[?:?] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[?:?] at com.atlassian.bamboo.utils.BambooRunnables$1.run(BambooRunnables.java:46) ~[atlassian-bamboo-api-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.security.ImpersonationHelper.runWith(ImpersonationHelper.java:26) ~[atlassian-bamboo-api-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.security.ImpersonationHelper.runWithSystemAuthority(ImpersonationHelper.java:17) ~[atlassian-bamboo-api-10.1.0-SNAPSHOT.jar:?] at com.atlassian.bamboo.security.ImpersonationHelper.lambda$makeRunnableWithSystemAuthority$0(ImpersonationHelper.java:38) ~[atlassian-bamboo-api-10.1.0-SNAPSHOT.jar:?] at java.base/java.lang.Thread.run(Thread.java:840) [?:?]
Environment
- Bamboo Data Center
- Repository Stored Specs / Java Specs
Steps to Reproduce
There are multiple conditions that may trigger this same bug such as modifying user/groups but this requires more randomness and reproducing it is hard. This issue is caused by four possible "triggers" in the code:
- RssPermissionManagerImpl#removeRepository
- RssPermissionManagerImpl#revokeProjectAccess
- RssPermissionManagerImpl#revokeDeploymentProjectAccess
- RssPermissionManagerImpl#revokeRepositoryAccess
The steps below demonstrate only one of the possible reproduction avenues, which is modifying the Project's Specs repository permissions.
- Add 4 Projects (BAM, PRO1, PRO2, PRO3)
- Add various users and groups - Check the specs code below for reference
- Create a "Dragons" Specs repository in Bamboo
- Use the following Specs code in the Dragons repository. The code below will make changes to the Projects by changing users and groups permissions randomly (to force changes on evey run). It also adds the "Dragons" repository to multiple projects as an allowed Specs repository:
bamboo-specs/src/main/java/tutorial/ProjectPermissionsSpec.java
package tutorial; import com.atlassian.bamboo.specs.api.BambooSpec; import com.atlassian.bamboo.specs.api.builders.permission.PermissionType; import com.atlassian.bamboo.specs.api.builders.permission.Permissions; import com.atlassian.bamboo.specs.api.builders.permission.ProjectPermissions; import com.atlassian.bamboo.specs.util.BambooServer; import java.util.ArrayList; import java.util.List; import java.util.Random; @BambooSpec public class ProjectPermissionsSpec { private final List<String> projectStaticAdmins = new ArrayList<>(); private final List<String> projectKeys = new ArrayList<>(); private final List<String> users = new ArrayList<>(); private final List<String> groups = new ArrayList<>(); private final List<PermissionType> permissions = new ArrayList<>(); private final List<String> specsRepositories = new ArrayList<>(); private final Random random = new Random(); public ProjectPermissionsSpec() { // Initialize with the static admin users projectStaticAdmins.add("ealvarenga"); projectStaticAdmins.add("bamboo"); // Initialize with the project keys projectKeys.add("BAM"); projectKeys.add("PRO1"); projectKeys.add("PRO2"); projectKeys.add("PRO3"); // Initialize with example users users.add("ship"); users.add("gearbox"); users.add("integration"); users.add("sonar"); // Initialize with example groups groups.add("fisheye-users"); groups.add("bitbucket-users"); groups.add("paymentsART"); groups.add("ship-group"); // Initialize with permission types permissions.add(PermissionType.VIEW); permissions.add(PermissionType.CREATE); permissions.add(PermissionType.ADMIN); permissions.add(PermissionType.CREATE_REPOSITORY); // Add SpecsRepositories specsRepositories.add("Dragons"); } /** * Generates and returns a ProjectPermissions object for a given project key, * representing the user/group permissions for this project. * * @param projectKey the key of the project * @return Generic permissions for the project */ public ProjectPermissions generateProjectPermissions(String projectKey) { Permissions projectPermissions = new Permissions(); // Randomly decide to add each user for (String user : users) { if (random.nextBoolean()) { // 50% chance to add the user PermissionType randomPermission = permissions.get(random.nextInt(permissions.size())); projectPermissions.userPermissions(user, randomPermission); System.out.println("User " + user + " assigned " + randomPermission + " permission to project " + projectKey); } } // Randomly decide to add each group for (String group : groups) { if (random.nextBoolean()) { // 50% chance to add the group PermissionType randomPermission = permissions.get(random.nextInt(permissions.size())); projectPermissions.groupPermissions(group, randomPermission); System.out.println("Group " + group + " assigned " + randomPermission + " permission to project " + projectKey); } } // Assign static admin permissions to static users for (String admin : projectStaticAdmins) { projectPermissions.userPermissions(admin, PermissionType.ADMIN); System.out.println("Static admin " + admin + " assigned ADMIN permission to project " + projectKey); } ProjectPermissions projectPermissionsObject = new ProjectPermissions(projectKey) .projectPermissions(projectPermissions); // Add specs repositories to the project for (String specsRepository : specsRepositories) { projectPermissionsObject.specsRepositories(specsRepository); System.out.println("Specs Repository " + specsRepository + " added to the project " + projectKey); } return projectPermissionsObject; } public static void main(String... argv) { BambooServer bambooServer = new BambooServer("https://bamboo1000.osalva.net"); ProjectPermissionsSpec projectPermissionsSpec = new ProjectPermissionsSpec(); // Iterate over each project key and publish the permissions for (String projectKey : projectPermissionsSpec.projectKeys) { ProjectPermissions projectPermissions = projectPermissionsSpec.generateProjectPermissions(projectKey); bambooServer.publish(projectPermissions); System.out.println("Published permissions for project: " + projectKey); } } }
- Push the change/Scan the repository for specs. It should work on the first time
- Commend the following Block from the Specs code and commit it:
// Add specs repositories to the project for (String specsRepository : specsRepositories) { projectPermissionsObject.specsRepositories(specsRepository); System.out.println("Specs Repository " + specsRepository + " added to the project " + projectKey); }
- Push the change/Scan the repository for specs. It fails with a message such as:
[RssExecutionDirectoryManagerImpl] Cleaning all RSS execution cache for repository 7077889 [AllTypesSpecsImporter] java.nio.file.NoSuchFileException:
Expected Results
Bamboo should process the Java Specs changes via RSS normally and modify the permissions as requested. Any cleanups triggered by RssPermissionManagerImpl should be carried over to the end of the process or be actioned on a per-object basis; meaning remove one object at a time on demand and not the complete <bamboo-home>/local-working-dir/serverSide/REPOSITORY_STORED_SPECS/repository-123456-master/internal-yamls/ folder.
Actual Results
Bamboo gets into a race condition which will call RssPermissionManagerImpl#scheduleFullSpecsUpdate in the middle of Specs processing. scheduleFullSpecsUpdate will call cleanExecutionCacheDirectory which will remove all the files in the temporary YAML folder and generate the following:
2024-11-15 16:52:18,603 INFO [23-BAM::SpecsDetection:pool-24-thread-3] [RssExecutionDirectoryManagerImpl] Cleaning all RSS execution cache for repository 7077889 2024-11-15 16:52:18,603 DEBUG [23-BAM::SpecsDetection:pool-24-thread-3] [RssExecutionDirectoryManagerImpl] Removing RSS cache repository /var/atlassian/application-data/bamboo/local-working-dir/serverSide/REPOSITORY_STORED_SPECS/repository-7077889-master 2024-11-15 16:52:18,606 WARN [23-BAM::SpecsDetection:pool-24-thread-3] [AllTypesSpecsImporter] java.nio.file.NoSuchFileException: /var/atlassian/application-data/bamboo/local-working-dir/serverSide/REPOSITORY_STORED_SPECS/repository-7077889-master/internal-yamls/project-permissions/00003-b0fb92b8-project-permissions-for-project-PRO3.yaml
Workaround
Isolate the Project Permissions change and push them either from:
- Move the Project Permissions to a dedicated Specs repository which does not share the same Specs repository used to set Plan/Deployment Specs
or - Publish the changes using Maven over mvn -Ppublish - That will still make Bamboo call the cleanup but it will not remove any YAML files as the files are generated locally on the machine that executed Maven
or - Adjust the Project permissions manually