From 2826f24cea8f95a92408f73c364d1279f053b7d6 Mon Sep 17 00:00:00 2001 From: Christos Arvanitis Date: Wed, 27 Nov 2024 19:53:03 +0200 Subject: [PATCH 1/3] fix(openapi): Rewrite Swagger to OpenAPI annotations (#1514) * fix(openapi): Rewrite Swagger to OpenAPI annotations * chore(deps): bump latest kork version --------- Co-authored-by: Edgar Garcia --- build.gradle | 1 + front50-web/front50-web.gradle | 2 +- .../front50/controllers/AdminController.java | 8 +++--- .../controllers/DeliveryController.java | 14 +++++----- .../controllers/PermissionsController.java | 6 ++--- .../v2/ApplicationsController.java | 24 +++++++++-------- .../controllers/v2/ProjectsController.java | 26 +++++++++---------- gradle.properties | 2 +- 8 files changed, 43 insertions(+), 40 deletions(-) diff --git a/build.gradle b/build.gradle index 55373dbce..eb7a13ab1 100644 --- a/build.gradle +++ b/build.gradle @@ -18,6 +18,7 @@ plugins { id 'io.spinnaker.project' version "$spinnakerGradleVersion" apply false id "org.jetbrains.kotlin.jvm" version "$kotlinVersion" apply false id "org.jetbrains.kotlin.plugin.allopen" version "$kotlinVersion" apply false + } allprojects { diff --git a/front50-web/front50-web.gradle b/front50-web/front50-web.gradle index a7f22c1f8..95ac9b175 100644 --- a/front50-web/front50-web.gradle +++ b/front50-web/front50-web.gradle @@ -35,7 +35,7 @@ dependencies { implementation "io.spinnaker.kork:kork-web" implementation "io.spinnaker.kork:kork-exceptions" implementation "com.squareup.retrofit:converter-jackson" - implementation "io.swagger:swagger-annotations" + implementation "io.swagger.core.v3:swagger-annotations" implementation "commons-codec:commons-codec" implementation "javax.validation:validation-api" diff --git a/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/AdminController.java b/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/AdminController.java index 7d29ed7bf..de3b70462 100644 --- a/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/AdminController.java +++ b/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/AdminController.java @@ -18,8 +18,8 @@ import com.netflix.spinnaker.front50.model.AdminOperations; import com.netflix.spinnaker.front50.model.ObjectType; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import java.util.Collection; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; @@ -29,7 +29,7 @@ @RestController @RequestMapping("/admin") -@Api(value = "admin", description = "Various administrative operations") +@Tag(name = "admin", description = "Various administrative operations") public class AdminController { private final Collection adminOperations; @@ -39,7 +39,7 @@ public AdminController(Collection adminOperations) { this.adminOperations = adminOperations; } - @ApiOperation(value = "", notes = "Recover a previously deleted object") + @Operation(summary = "", description = "Recover a previously deleted object") @RequestMapping(value = "/recover", method = RequestMethod.POST) void recover(@RequestBody AdminOperations.Recover operation) { adminOperations.forEach(o -> o.recover(operation)); diff --git a/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/DeliveryController.java b/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/DeliveryController.java index ed04c40e1..efc1c44ae 100644 --- a/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/DeliveryController.java +++ b/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/DeliveryController.java @@ -4,7 +4,7 @@ import com.netflix.spinnaker.front50.model.delivery.Delivery; import com.netflix.spinnaker.front50.model.delivery.DeliveryRepository; import com.netflix.spinnaker.kork.web.exceptions.NotFoundException; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; import java.util.Collection; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; @@ -25,35 +25,35 @@ public DeliveryController(DeliveryRepository deliveryRepository) { } @PostFilter("hasPermission(filterObject.application, 'APPLICATION', 'READ')") - @ApiOperation(value = "", notes = "Get all delivery configs") + @Operation(summary = "", description = "Get all delivery configs") @RequestMapping(method = RequestMethod.GET, value = "/deliveries") Collection getAllConfigs() { return deliveryRepository.getAllConfigs(); } @PreAuthorize("hasPermission(#application, 'APPLICATION', 'READ')") - @ApiOperation(value = "", notes = "Get the delivery configs for an application") + @Operation(summary = "", description = "Get the delivery configs for an application") @RequestMapping(method = RequestMethod.GET, value = "/applications/{application}/deliveries") Collection getConfigByAppName(@PathVariable String application) { return deliveryRepository.getConfigsByApplication(application); } @PostAuthorize("hasPermission(returnObject.application, 'APPLICATION', 'READ')") - @ApiOperation(value = "", notes = "Get a delivery config by id") + @Operation(summary = "", description = "Get a delivery config by id") @RequestMapping(method = RequestMethod.GET, value = "deliveries/{id}") Delivery getConfigById(@PathVariable String id) { return deliveryRepository.findById(id); } @PreAuthorize("hasPermission(#config.application, 'APPLICATION', 'WRITE')") - @ApiOperation(value = "", notes = "Create a delivery config") + @Operation(summary = "", description = "Create a delivery config") @RequestMapping(method = RequestMethod.POST, value = "/deliveries") Delivery createConfig(@RequestBody Delivery config) { return deliveryRepository.upsertConfig(config); } @PreAuthorize("hasPermission(#config.application, 'APPLICATION', 'WRITE')") - @ApiOperation(value = "", notes = "Update a delivery config") + @Operation(summary = "", description = "Update a delivery config") @RequestMapping(method = RequestMethod.PUT, value = "/deliveries/{id}") Delivery upsertConfig(@PathVariable String id, @RequestBody Delivery config) { if (!id.equals(config.getId())) { @@ -71,7 +71,7 @@ Delivery upsertConfig(@PathVariable String id, @RequestBody Delivery config) { } @PreAuthorize("hasPermission(#application, 'APPLICATION', 'WRITE')") - @ApiOperation(value = "", notes = "Delete a delivery config") + @Operation(summary = "", description = "Delete a delivery config") @RequestMapping( method = RequestMethod.DELETE, value = "/applications/{application}/deliveries/{id}") diff --git a/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/PermissionsController.java b/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/PermissionsController.java index a3ae67126..4bf7d004a 100644 --- a/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/PermissionsController.java +++ b/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/PermissionsController.java @@ -2,7 +2,7 @@ import com.netflix.spinnaker.front50.ApplicationPermissionsService; import com.netflix.spinnaker.front50.model.application.Application; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; import java.util.Set; import org.springframework.web.bind.annotation.*; @@ -16,7 +16,7 @@ public PermissionsController(ApplicationPermissionsService permissionsService) { this.permissionsService = permissionsService; } - @ApiOperation(value = "", notes = "Get all application permissions. Internal use only.") + @Operation(summary = "", description = "Get all application permissions. Internal use only.") @RequestMapping(method = RequestMethod.GET, value = "/applications") public Set getAllApplicationPermissions() { return permissionsService.getAllApplicationPermissions(); @@ -27,7 +27,7 @@ public Application.Permission getApplicationPermission(@PathVariable String appN return permissionsService.getApplicationPermission(appName); } - @ApiOperation(value = "", notes = "Create an application permission.") + @Operation(summary = "", description = "Create an application permission.") @RequestMapping(method = RequestMethod.POST, value = "/applications") public Application.Permission createApplicationPermission( @RequestBody Application.Permission newPermission) { diff --git a/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/v2/ApplicationsController.java b/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/v2/ApplicationsController.java index d535c18ff..7c8879b17 100644 --- a/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/v2/ApplicationsController.java +++ b/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/v2/ApplicationsController.java @@ -13,8 +13,8 @@ import com.netflix.spinnaker.front50.model.application.ApplicationPermissionDAO; import com.netflix.spinnaker.front50.model.application.ApplicationService; import com.netflix.spinnaker.kork.web.exceptions.NotFoundException; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import java.util.*; import java.util.stream.Collectors; import javax.servlet.http.HttpServletResponse; @@ -30,7 +30,7 @@ @RestController @RequestMapping("/v2/applications") -@Api(value = "application", description = "Application API") +@Tag(name = "application", description = "Application API") public class ApplicationsController { private static final Logger log = LoggerFactory.getLogger(ApplicationsController.class); @@ -62,9 +62,9 @@ public ApplicationsController( @PreAuthorize("#restricted ? @fiatPermissionEvaluator.storeWholePermission() : true") @PostFilter("#restricted ? hasPermission(filterObject.name, 'APPLICATION', 'READ') : true") - @ApiOperation( - value = "", - notes = + @Operation( + summary = "", + description = "Fetch all applications.\n\nSupports filtering by one or more attributes:\n- ?email=my@email.com\n- ?email=my@email.com&name=flex") @RequestMapping(method = RequestMethod.GET) public List applications( @@ -113,7 +113,7 @@ public List applications( } @PreAuthorize("@fiatPermissionEvaluator.canCreate('APPLICATION', #app)") - @ApiOperation(value = "", notes = "Create an application") + @Operation(summary = "", description = "Create an application") @RequestMapping(method = RequestMethod.POST) public Application create(@RequestBody final Application app) { if (applicationService.findByName(app.getName()) != null) { @@ -135,7 +135,7 @@ public Application create(@RequestBody final Application app) { } @PreAuthorize("hasPermission(#applicationName, 'APPLICATION', 'WRITE')") - @ApiOperation(value = "", notes = "Delete an application") + @Operation(summary = "", description = "Delete an application") @RequestMapping(method = RequestMethod.DELETE, value = "/{applicationName:.+}") public void delete(@PathVariable String applicationName, HttpServletResponse response) { applicationService.delete(applicationName); @@ -143,7 +143,7 @@ public void delete(@PathVariable String applicationName, HttpServletResponse res } @PreAuthorize("hasPermission(#app.name, 'APPLICATION', 'WRITE')") - @ApiOperation(value = "", notes = "Update an existing application by merging the attributes") + @Operation(summary = "", description = "Update an existing application by merging the attributes") @RequestMapping(method = RequestMethod.PATCH, value = "/{applicationName:.+}") public Application update( @PathVariable final String applicationName, @RequestBody final Application app) { @@ -158,7 +158,9 @@ public Application update( } @PreAuthorize("hasPermission(#app.name, 'APPLICATION', 'WRITE')") - @ApiOperation(value = "", notes = "Update an existing application by replacing all attributes") + @Operation( + summary = "", + description = "Update an existing application by replacing all attributes") @RequestMapping(method = RequestMethod.PUT, value = "/{applicationName:.+}") public Application replace( @PathVariable final String applicationName, @RequestBody final Application app) { @@ -173,7 +175,7 @@ public Application replace( } @PostAuthorize("hasPermission(#applicationName, 'APPLICATION', 'READ')") - @ApiOperation(value = "", notes = "Fetch a single application by name") + @Operation(summary = "", description = "Fetch a single application by name") @RequestMapping(method = RequestMethod.GET, value = "/{applicationName:.+}") public Application get(@PathVariable final String applicationName) { Application app = applicationDAO.findByName(applicationName.toUpperCase()); diff --git a/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/v2/ProjectsController.java b/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/v2/ProjectsController.java index 2f484a662..dfa2c6987 100644 --- a/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/v2/ProjectsController.java +++ b/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/v2/ProjectsController.java @@ -25,8 +25,8 @@ import com.netflix.spinnaker.front50.model.project.Project; import com.netflix.spinnaker.front50.model.project.ProjectDAO; import com.netflix.spinnaker.kork.web.exceptions.NotFoundException; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -38,7 +38,7 @@ @RestController @RequestMapping(value = "/v2/projects", produces = MediaType.APPLICATION_JSON_VALUE) -@Api(value = "projects", description = "Project API") +@Tag(name = "projects", description = "Project API") public class ProjectsController { private static final Splitter COMMA_SPLITTER = Splitter.on(','); @@ -50,9 +50,9 @@ public ProjectsController(ProjectDAO projectDAO) { } @RequestMapping(value = "/search", method = RequestMethod.GET) - @ApiOperation( - value = "", - notes = + @Operation( + summary = "", + description = "Search for projects given one or more attributes.\n\n- /search?q=ProjectName\n- /search?q=ApplicationName\n") public Set search(@RequestParam("q") final String query) { return projectDAO.all().stream() @@ -64,9 +64,9 @@ public Set search(@RequestParam("q") final String query) { .collect(Collectors.toSet()); } - @ApiOperation( - value = "", - notes = + @Operation( + summary = "", + description = "Fetch all projects.\n\n Support filtering by one or more attributes:\n - ?name=projectName\n - ?email=my@email.com") @RequestMapping(method = RequestMethod.GET) public List projects( @@ -78,7 +78,7 @@ public List projects( return (pageSize == null) ? projects : projects.subList(0, Math.min(pageSize, projects.size())); } - @ApiOperation(value = "", notes = "Fetch a single project") + @Operation(summary = "", description = "Fetch a single project") @RequestMapping(method = RequestMethod.GET, value = "/{projectId}") public Project project(@PathVariable String projectId) { try { @@ -88,7 +88,7 @@ public Project project(@PathVariable String projectId) { } } - @ApiOperation(value = "", notes = "Update an existing project") + @Operation(summary = "", description = "Update an existing project") @RequestMapping(method = RequestMethod.PUT, value = "/{projectId}") public Project put(@PathVariable final String projectId, @RequestBody final Project project) { Project existingProject = projectDAO.findById(projectId); @@ -110,7 +110,7 @@ public Project put(@PathVariable final String projectId, @RequestBody final Proj return project; } - @ApiOperation(value = "", notes = "Create a project") + @Operation(summary = "", description = "Create a project") @RequestMapping(method = RequestMethod.POST) public Project create(@RequestBody final Project project) { project.setCreateTs(System.currentTimeMillis()); @@ -202,7 +202,7 @@ private static boolean clusterHasMatchingApplication( .orElse(false); } - @ApiOperation(value = "", notes = "Delete a project") + @Operation(summary = "", description = "Delete a project") @RequestMapping(method = RequestMethod.DELETE, value = "/{projectId}") public void delete(@PathVariable String projectId, HttpServletResponse response) { projectDAO.delete(projectId); diff --git a/gradle.properties b/gradle.properties index 8befd70e6..822dbc940 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ fiatVersion=1.51.0 includeProviders=azure,gcs,oracle,redis,s3,swift,sql -korkVersion=7.245.0 +korkVersion=7.247.0 org.gradle.parallel=true spinnakerGradleVersion=8.32.1 targetJava17=true From 2ab0d909859a4ef764eb39d2e1969cb86d8c126e Mon Sep 17 00:00:00 2001 From: spinnakerbot Date: Wed, 27 Nov 2024 13:51:59 -0500 Subject: [PATCH 2/3] chore(dependencies): Autobump fiatVersion (#1517) Co-authored-by: root --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 822dbc940..8d8e92489 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -fiatVersion=1.51.0 +fiatVersion=1.52.0 includeProviders=azure,gcs,oracle,redis,s3,swift,sql korkVersion=7.247.0 org.gradle.parallel=true From 268236a159bd289b6734a0bb9022ed4963150a47 Mon Sep 17 00:00:00 2001 From: spinnakerbot Date: Tue, 10 Dec 2024 14:29:24 -0500 Subject: [PATCH 3/3] chore(dependencies): Autobump fiatVersion (#1519) * chore(dependencies): Autobump fiatVersion * refactor(retrofit2): refactor the code to align with the retrofit2 upgrade of fiat-api * refactor(retrofit2): use retrofit-mock library instead of mocking Call. --------- Co-authored-by: root Co-authored-by: kirangodishala --- front50-core/front50-core.gradle | 1 + .../front50/ApplicationPermissionsService.java | 3 ++- .../spinnaker/front50/ServiceAccountsService.java | 11 ++++++++--- .../front50/ApplicationPermissionsServiceSpec.groovy | 3 ++- .../front50/ServiceAccountsServiceSpec.groovy | 11 ++++++++--- front50-web/front50-web.gradle | 1 + .../controllers/v2/ApplicationsController.java | 3 ++- gradle.properties | 2 +- 8 files changed, 25 insertions(+), 10 deletions(-) diff --git a/front50-core/front50-core.gradle b/front50-core/front50-core.gradle index 00919eb28..a196e2ee4 100644 --- a/front50-core/front50-core.gradle +++ b/front50-core/front50-core.gradle @@ -47,5 +47,6 @@ dependencies { // in front50-test to front50-common, but front50-test seems like a better place. testImplementation project(":front50-test") testImplementation "io.spinnaker.kork:kork-sql-test" + testImplementation "com.squareup.retrofit2:retrofit-mock" } diff --git a/front50-core/src/main/java/com/netflix/spinnaker/front50/ApplicationPermissionsService.java b/front50-core/src/main/java/com/netflix/spinnaker/front50/ApplicationPermissionsService.java index cc396ab8e..4f717fc25 100644 --- a/front50-core/src/main/java/com/netflix/spinnaker/front50/ApplicationPermissionsService.java +++ b/front50-core/src/main/java/com/netflix/spinnaker/front50/ApplicationPermissionsService.java @@ -25,6 +25,7 @@ import com.netflix.spinnaker.front50.model.application.ApplicationDAO; import com.netflix.spinnaker.front50.model.application.ApplicationPermissionDAO; import com.netflix.spinnaker.kork.exceptions.SystemException; +import com.netflix.spinnaker.kork.retrofit.Retrofit2SyncCall; import com.netflix.spinnaker.kork.retrofit.exceptions.SpinnakerServerException; import com.netflix.spinnaker.kork.web.exceptions.NotFoundException; import java.util.AbstractMap.SimpleEntry; @@ -182,7 +183,7 @@ private void syncUsers(Permission newPermission, Permission oldPermission) { if (fiatConfigurationProperties.getRoleSync().isEnabled()) { try { - fiatService.get().sync(new ArrayList<>(roles)); + Retrofit2SyncCall.execute(fiatService.get().sync(new ArrayList<>(roles))); } catch (SpinnakerServerException e) { log.warn("Error syncing users", e); } diff --git a/front50-core/src/main/java/com/netflix/spinnaker/front50/ServiceAccountsService.java b/front50-core/src/main/java/com/netflix/spinnaker/front50/ServiceAccountsService.java index 4fdb57cfe..97dfc38b6 100644 --- a/front50-core/src/main/java/com/netflix/spinnaker/front50/ServiceAccountsService.java +++ b/front50-core/src/main/java/com/netflix/spinnaker/front50/ServiceAccountsService.java @@ -23,6 +23,7 @@ import com.netflix.spinnaker.front50.config.annotations.ConditionalOnAnyProviderExceptRedisIsEnabled; import com.netflix.spinnaker.front50.model.serviceaccount.ServiceAccount; import com.netflix.spinnaker.front50.model.serviceaccount.ServiceAccountDAO; +import com.netflix.spinnaker.kork.retrofit.Retrofit2SyncCall; import com.netflix.spinnaker.kork.retrofit.exceptions.SpinnakerServerException; import com.netflix.spinnaker.kork.web.exceptions.NotFoundException; import java.util.Collection; @@ -86,7 +87,8 @@ public void deleteServiceAccounts(Collection serviceAccountsToDe sa -> { try { serviceAccountDAO.delete(sa.getId()); - fiatService.ifPresent(service -> service.logoutUser(sa.getId())); + fiatService.ifPresent( + service -> Retrofit2SyncCall.execute(service.logoutUser(sa.getId()))); } catch (Exception e) { log.warn("Could not delete service account user {}", sa.getId(), e); } @@ -129,7 +131,7 @@ private void syncUsers(Collection serviceAccounts) { .flatMap(Collection::stream) .distinct() .collect(Collectors.toList()); - fiatService.get().sync(rolesToSync); + Retrofit2SyncCall.execute(fiatService.get().sync(rolesToSync)); log.debug("Synced users with roles: {}", rolesToSync); // Invalidate the current user's permissions in the local cache Authentication auth = SecurityContextHolder.getContext().getAuthentication(); @@ -149,7 +151,10 @@ private void syncServiceAccount(ServiceAccount serviceAccount) { return; } try { - fiatService.get().syncServiceAccount(serviceAccount.getId(), serviceAccount.getMemberOf()); + Retrofit2SyncCall.execute( + fiatService + .get() + .syncServiceAccount(serviceAccount.getId(), serviceAccount.getMemberOf())); log.debug( "Synced service account {} with roles: {}", serviceAccount.getId(), diff --git a/front50-core/src/test/groovy/com/netflix/spinnaker/front50/ApplicationPermissionsServiceSpec.groovy b/front50-core/src/test/groovy/com/netflix/spinnaker/front50/ApplicationPermissionsServiceSpec.groovy index e35bfea1f..9961bb48b 100644 --- a/front50-core/src/test/groovy/com/netflix/spinnaker/front50/ApplicationPermissionsServiceSpec.groovy +++ b/front50-core/src/test/groovy/com/netflix/spinnaker/front50/ApplicationPermissionsServiceSpec.groovy @@ -23,6 +23,7 @@ import com.netflix.spinnaker.front50.config.FiatConfigurationProperties import com.netflix.spinnaker.front50.model.application.Application import com.netflix.spinnaker.front50.model.application.ApplicationDAO import com.netflix.spinnaker.front50.model.application.ApplicationPermissionDAO +import retrofit2.mock.Calls import spock.lang.Specification import spock.lang.Unroll @@ -44,7 +45,7 @@ class ApplicationPermissionsServiceSpec extends Specification { subject.createApplicationPermission(permission) then: - 1 * fiatService.sync(expectedSyncedRoles) + 1 * fiatService.sync(expectedSyncedRoles) >> Calls.response(null) where: permission | expectedSyncedRoles diff --git a/front50-core/src/test/groovy/com/netflix/spinnaker/front50/ServiceAccountsServiceSpec.groovy b/front50-core/src/test/groovy/com/netflix/spinnaker/front50/ServiceAccountsServiceSpec.groovy index 043b9ebe0..2c4b83596 100644 --- a/front50-core/src/test/groovy/com/netflix/spinnaker/front50/ServiceAccountsServiceSpec.groovy +++ b/front50-core/src/test/groovy/com/netflix/spinnaker/front50/ServiceAccountsServiceSpec.groovy @@ -26,6 +26,7 @@ import com.netflix.spinnaker.front50.model.serviceaccount.ServiceAccountDAO import org.springframework.security.core.Authentication import org.springframework.security.core.context.SecurityContext import org.springframework.security.core.context.SecurityContextHolder +import retrofit2.mock.Calls import spock.lang.Specification import spock.lang.Subject @@ -67,13 +68,14 @@ class ServiceAccountsServiceSpec extends Specification { } SecurityContextHolder.setContext(securityContext) fiatConfigurationProperties.isDisableRoleSyncWhenSavingServiceAccounts() >> false + when: serviceAccountDAO.create(serviceAccount.id, serviceAccount) >> serviceAccount service.createServiceAccount(serviceAccount) then: 1 * fiatPermissionsEvaluator.invalidatePermission(_) - 1 * fiatService.sync(["test-role"]) + 1 * fiatService.sync(["test-role"]) >> Calls.response(null) } def "deleting multiple service account should call sync once"() { @@ -92,13 +94,14 @@ class ServiceAccountsServiceSpec extends Specification { ] )] fiatConfigurationProperties.isDisableRoleSyncWhenSavingServiceAccounts() >> false + when: service.deleteServiceAccounts(serviceAccounts) then: 1 * serviceAccountDAO.delete("test-svc-acct-1") 1 * serviceAccountDAO.delete("test-svc-acct-2") - 1 * fiatService.sync(['test-role-1', 'test-role-2']) + 1 * fiatService.sync(['test-role-1', 'test-role-2']) >> Calls.response(null) } def "unknown managed service accounts should not throw exception"() { @@ -118,6 +121,8 @@ class ServiceAccountsServiceSpec extends Specification { 1 * serviceAccountDAO.findById(test1ServiceAccount.id) >> test1ServiceAccount 1 * serviceAccountDAO.findById(test2ServiceAccount.id) >> { throw new NotFoundException(test2ServiceAccount.id) } 1 * serviceAccountDAO.delete(test1ServiceAccount.id) + 1 * fiatService.logoutUser(_) >> Calls.response(null) + 1 * fiatService.sync(_) >> Calls.response(1L) 0 * serviceAccountDAO.delete(test2ServiceAccount.id) } @@ -144,7 +149,7 @@ class ServiceAccountsServiceSpec extends Specification { then: 1 * fiatPermissionsEvaluator.invalidatePermission(_) - 1 * fiatService.syncServiceAccount("test-svc-acct", ["test-role"]) + 1 * fiatService.syncServiceAccount("test-svc-acct", ["test-role"]) >> Calls.response(1L) 0 * fiatService.sync(["test-role"]) } } diff --git a/front50-web/front50-web.gradle b/front50-web/front50-web.gradle index 95ac9b175..88917cd11 100644 --- a/front50-web/front50-web.gradle +++ b/front50-web/front50-web.gradle @@ -32,6 +32,7 @@ dependencies { implementation "io.spinnaker.fiat:fiat-core:$fiatVersion" implementation "io.spinnaker.kork:kork-artifacts" implementation "io.spinnaker.kork:kork-config" + implementation "io.spinnaker.kork:kork-retrofit" implementation "io.spinnaker.kork:kork-web" implementation "io.spinnaker.kork:kork-exceptions" implementation "com.squareup.retrofit:converter-jackson" diff --git a/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/v2/ApplicationsController.java b/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/v2/ApplicationsController.java index 7c8879b17..19fd5305f 100644 --- a/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/v2/ApplicationsController.java +++ b/front50-web/src/main/java/com/netflix/spinnaker/front50/controllers/v2/ApplicationsController.java @@ -12,6 +12,7 @@ import com.netflix.spinnaker.front50.model.application.ApplicationDAO; import com.netflix.spinnaker.front50.model.application.ApplicationPermissionDAO; import com.netflix.spinnaker.front50.model.application.ApplicationService; +import com.netflix.spinnaker.kork.retrofit.Retrofit2SyncCall; import com.netflix.spinnaker.kork.web.exceptions.NotFoundException; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -125,7 +126,7 @@ public Application create(@RequestBody final Application app) { && fiatConfigurationProperties.getRoleSync().isEnabled() && fiatService.isPresent()) { try { - fiatService.get().sync(); + Retrofit2SyncCall.execute(fiatService.get().sync()); } catch (Exception e) { log.warn("failed to trigger fiat permission sync", e); } diff --git a/gradle.properties b/gradle.properties index 8d8e92489..8339eb949 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -fiatVersion=1.52.0 +fiatVersion=1.53.0 includeProviders=azure,gcs,oracle,redis,s3,swift,sql korkVersion=7.247.0 org.gradle.parallel=true