Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions openapi/openapi-component_catalog-v1.0.0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,12 @@ paths:
schema:
type: string
example: 'aSdFam...yCg=='
- name: X-Shared-Secret
in: header
required: false
schema:
type: string
example: 'SKiPJ...K46h'
responses:
"200":
description: The CatalogItem.
Expand Down Expand Up @@ -579,6 +585,12 @@ paths:
required: true
schema:
type: string
- name: X-Shared-Secret
in: header
required: false
schema:
type: string
example: 'SKiPJ...K46h'
responses:
"200":
description: A list of valid CatalogItems.
Expand Down Expand Up @@ -639,6 +651,12 @@ paths:
required: true
schema:
type: string
- name: X-Shared-Secret
in: header
required: false
schema:
type: string
example: 'SKiPJ...K46h'
responses:
"200":
description: The CatalogItem.
Expand Down Expand Up @@ -1215,6 +1233,10 @@ components:
@com.fasterxml.jackson.annotation.JsonInclude(
com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL
)
visible:
type: boolean
example: true
description: Whether the catalog item is visible for the user requesting it

userActions:
type: array
Expand All @@ -1230,6 +1252,7 @@ components:
- authors
- date
- updatedAt
- visible
example:
id: aSdFam...yCg==
slug: myproject_some-repo
Expand All @@ -1248,6 +1271,9 @@ components:
- '@SomeAuthor'
- '@SomeOtherAuthor'
date: "2021-07-01T00:00:00Z"
updatedAt: 1625097600000
componentCount: 5
visible: true
CatalogItemUserAction:
properties:
id:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
@Configuration
public class ApplicationPropertiesConfiguration {

@Bean("securityProps")
@ConfigurationProperties(prefix = "component-provisioner.security")
public SecurityProps securityProps() {
return SecurityProps.builder().build();
}

@Bean("awxServiceConfig")
@ConfigurationProperties(prefix = "component-provisioner.awx.service")
public AWXServiceProps awxServiceProps() {
Expand Down Expand Up @@ -57,6 +63,12 @@ public AzureAdTokenServiceProps azureAdTokenServiceProps() {
return AzureAdTokenServiceProps.builder().build();
}

@Builder // useful for unit testing
@Data
public static class SecurityProps {
private String sharedSecret;
}

@Builder // useful for unit testing
@Data
public static class ProjectsInfoServicesCacheProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ public ProvisionActionWrapper addMandatoryCatalogItemParamsIfMissing(ProvisionAc

private CatalogItem fetchCatalogItem(ProvisionActionWrapper wrapper) {
var accessToken = authenticationProvider.getAccessToken();
return componentCatalogService.getCatalogItem(accessToken, wrapper.getCatalogItemId(), wrapper.getProjectKey());
return componentCatalogService.getCatalogItem(accessToken, wrapper.getCatalogItemId(), wrapper.getProjectKey(), true);
}

private void applyDefaultValue(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,19 @@ public class ComponentCatalogService {

private final ApplicationPropertiesConfiguration.ComponentProvisionerParametersProps parametersProps;

private final ApplicationPropertiesConfiguration.SecurityProps securityProps;

public ComponentCatalogService(
CatalogItemUserActionMessageDefinitionsApi itemUserActionMessagesDefinitionsApi,
ApiClientsBuilder apiClientsBuilder,
ApplicationPropertiesConfiguration.ComponentCatalogServiceProps componentCatalogServiceProps,
@Qualifier("componentProvisionerParametersConfig") ApplicationPropertiesConfiguration.ComponentProvisionerParametersProps parametersProps) {
@Qualifier("componentProvisionerParametersConfig") ApplicationPropertiesConfiguration.ComponentProvisionerParametersProps parametersProps,
ApplicationPropertiesConfiguration.SecurityProps securityProps) {
this.itemUserActionMessagesDefinitionsApi = itemUserActionMessagesDefinitionsApi;
this.apiClientsBuilder = apiClientsBuilder;
this.componentCatalogServiceProps = componentCatalogServiceProps;
this.parametersProps = parametersProps;
this.securityProps = securityProps;
}

public Pair<HttpStatusCode, Optional<CatalogItemUserActionMessageDefinition>> getCatalogItemUserActionMessageDefinition(
Expand Down Expand Up @@ -150,11 +154,12 @@ public List<ProjectComponentInfo> getProjectComponents(String accessToken, Strin
return componentsApi.getProjectComponents(projectKey);
}

public CatalogItem getCatalogItem(String accessToken, String catalogItemId, String projectKey) {
public CatalogItem getCatalogItem(String accessToken, String catalogItemId, String projectKey, boolean ignoreItemVisibilityRestrictions) {
var apiClient = apiClientsBuilder.componentCatalogApiClient(accessToken, componentCatalogServiceProps.getBaseRestUrl().toString());
var catalogItemsApi = apiClientsBuilder.catalogItemsApi(apiClient);
var sharedSecret = ignoreItemVisibilityRestrictions ? securityProps.getSharedSecret() : null;

var catalogItem = catalogItemsApi.getCatalogItemByIdForProjectKey(catalogItemId, projectKey);
var catalogItem = catalogItemsApi.getCatalogItemByIdForProjectKey(catalogItemId, projectKey, sharedSecret);

log.debug("Retrieved catalog item with id {} for project key {}: {}", catalogItemId, projectKey, catalogItem);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public List<CreateIncidentParameter> getDeletionParameters(String projectKey, St

var apiClient = apiClientsBuilder.componentCatalogApiClient(authenticationProvider.getAccessToken(), componentCatalogServiceProps.getBaseRestUrl().toString());
var catalogItemsApi = apiClientsBuilder.catalogItemsApi(apiClient);
var catalogItem = catalogItemsApi.getCatalogItemById(catalogItemId);
var catalogItem = catalogItemsApi.getCatalogItemById(catalogItemId, null);

return extractDeletionParameters(catalogItem, projectComponent, ActionType.PROVISION.getValue());
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ component-provisioner:
azure:
token:
url: ${AZURE_TOKEN_URL}
security:
shared-secret: ${SECURITY_SHARED_SECRET}
caching:
projects-info-services-cache:
enabled: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,14 @@
import org.opendevstack.component_provisioner.server.controllers.exceptions.ProjectConfigurationException;
import org.opendevstack.component_provisioner.server.controllers.exceptions.SlugNotFoundException;
import org.opendevstack.component_provisioner.server.controllers.validators.MandatoryFieldType;
import org.opendevstack.component_provisioner.server.controllers.validators.MandatoryFieldsValidator;
import org.opendevstack.component_provisioner.server.controllers.validators.ProvisionerActionsApiValidator;
import org.opendevstack.component_provisioner.server.mappers.EntitiesMapper;
import org.opendevstack.component_provisioner.server.services.awx.AwxWorkflowJobLaunchMother;
import org.opendevstack.component_provisioner.server.services.awx.AwxWorkflowJobMother;
import org.opendevstack.component_provisioner.server.model.ProvisionAction;
import org.opendevstack.component_provisioner.server.model.ProvisionActionMother;
import org.opendevstack.component_provisioner.server.model.ProvisionActionParameter;
import org.opendevstack.component_provisioner.server.model.ProvisionActionParameterMother;
import org.opendevstack.component_provisioner.server.model.ProvisionActionResponse;
import org.opendevstack.component_provisioner.server.model.ProvisionActionResponseMother;
import org.opendevstack.component_provisioner.server.services.AuthenticationProvider;
import org.opendevstack.component_provisioner.server.services.AwxService;
import org.opendevstack.component_provisioner.server.services.ComponentCatalogService;
import org.opendevstack.component_provisioner.server.services.PlaceholderPostProcessor;
import org.opendevstack.component_provisioner.server.services.ProjectsInfoService;
import org.opendevstack.component_provisioner.server.services.ReplaceParametersService;
import org.opendevstack.component_provisioner.server.model.*;
import org.opendevstack.component_provisioner.server.services.*;
import org.opendevstack.component_provisioner.server.services.awx.AwxWorkflowJob;
import org.opendevstack.component_provisioner.server.services.awx.AwxWorkflowJobLaunch;
import org.opendevstack.component_provisioner.server.services.awx.AwxWorkflowJobLaunchMother;
import org.opendevstack.component_provisioner.server.services.awx.AwxWorkflowJobMother;
import org.springframework.http.HttpStatus;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.client.RestClientException;
Expand All @@ -48,15 +37,8 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class ProvisionerActionsApiFacadeTest {
Expand All @@ -82,9 +64,6 @@ class ProvisionerActionsApiFacadeTest {
@Mock
private ReplaceParametersService replaceParametersService;

@Mock
private MandatoryFieldsValidator mandatoryFieldsValidator;

@Mock
private ProjectsInfoService projectsInfoService;

Expand All @@ -100,7 +79,7 @@ void bypassAddMissingMandatoryParamsByDefault() {
.when(facade)
.addMandatoryCatalogItemParamsIfMissing(any(), any());
lenient()
.when(componentCatalogService.getCatalogItem(any(), any(), any()))
.when(componentCatalogService.getCatalogItem(any(), any(), any(), anyBoolean()))
.thenReturn(new CatalogItem());
}

Expand Down Expand Up @@ -939,7 +918,7 @@ void triggerProvisionAction_validatesHiddenMandatoryWorkflowName_beforeWorkflowW
var provisionActionResponse = ProvisionActionResponseMother.of();
provisionActionResponse.setId(123);

when(componentCatalogService.getCatalogItem("token", "CAT", "PRJ")).thenReturn(catalogItem);
when(componentCatalogService.getCatalogItem("token", "CAT", "PRJ", true)).thenReturn(catalogItem);
when(placeholderPostProcessor.process(any())).thenAnswer(inv -> inv.getArgument(0));

ArgumentCaptor<ProvisionActionWrapper> wrapperCaptor = ArgumentCaptor.forClass(ProvisionActionWrapper.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ class ComponentCatalogServiceTest {
@Mock
private ApplicationPropertiesConfiguration.ComponentProvisionerParametersProps parametersProps;

@Mock
private ApplicationPropertiesConfiguration.SecurityProps securityProps;

@InjectMocks
private ComponentCatalogService componentCatalogService;

Expand Down Expand Up @@ -334,6 +337,7 @@ void givenValidInput_whenGetCatalogItemIsCalled_thenCatalogItemIsReturned() thro
String accessToken = "access-token";
String catalogItemId = "CAT-123";
String projectKey = "PRJ-1";
boolean ignoreItemVisibilityRestrictions = false;

URL baseUrl = URI.create("http://component-catalog").toURL();

Expand All @@ -345,12 +349,12 @@ void givenValidInput_whenGetCatalogItemIsCalled_thenCatalogItemIsReturned() thro
when(apiClientsBuilder.catalogItemsApi(componentCatalogApiClient))
.thenReturn(catalogItemsApi);
when(catalogItemsApi.getCatalogItemByIdForProjectKey(
catalogItemId, projectKey))
catalogItemId, projectKey, null))
.thenReturn(expectedCatalogItem);

// when
CatalogItem result = componentCatalogService.getCatalogItem(
accessToken, catalogItemId, projectKey);
accessToken, catalogItemId, projectKey, ignoreItemVisibilityRestrictions);

// then
assertThat(result).isSameAs(expectedCatalogItem);
Expand All @@ -360,7 +364,7 @@ void givenValidInput_whenGetCatalogItemIsCalled_thenCatalogItemIsReturned() thro
verify(apiClientsBuilder)
.catalogItemsApi(componentCatalogApiClient);
verify(catalogItemsApi)
.getCatalogItemByIdForProjectKey(catalogItemId, projectKey);
.getCatalogItemByIdForProjectKey(catalogItemId, projectKey, null);

verifyNoMoreInteractions(catalogItemsApi);
verifyNoInteractions(
Expand All @@ -370,6 +374,32 @@ void givenValidInput_whenGetCatalogItemIsCalled_thenCatalogItemIsReturned() thro
);
}

@Test
void givenIgnoredVisibilityRestrictions_whenGetCatalogItemIsCalled_thenSharedSecretIsForwarded() throws MalformedURLException {
// given
var accessToken = "access-token";
var catalogItemId = "CAT-123";
var projectKey = "PRJ-1";
var sharedSecret = "test-shared-secret";
var baseUrl = URI.create("http://component-catalog").toURL();
var expectedCatalogItem = new CatalogItem();

when(componentCatalogServiceProps.getBaseRestUrl()).thenReturn(baseUrl);
when(apiClientsBuilder.componentCatalogApiClient(accessToken, baseUrl.toString()))
.thenReturn(componentCatalogApiClient);
when(apiClientsBuilder.catalogItemsApi(componentCatalogApiClient)).thenReturn(catalogItemsApi);
when(securityProps.getSharedSecret()).thenReturn(sharedSecret);
when(catalogItemsApi.getCatalogItemByIdForProjectKey(catalogItemId, projectKey, sharedSecret))
.thenReturn(expectedCatalogItem);

// when
var result = componentCatalogService.getCatalogItem(accessToken, catalogItemId, projectKey, true);

// then
assertThat(result).isSameAs(expectedCatalogItem);
verify(catalogItemsApi).getCatalogItemByIdForProjectKey(catalogItemId, projectKey, sharedSecret);
}

@Test
void givenValidInput_whenGetProjectComponents_thenProjectComponentsAreReturned() throws Exception {
// given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@
import org.opendevstack.component_provisioner.client.component_catalog.v1.ApiClient;
import org.opendevstack.component_provisioner.client.component_catalog.v1.api.CatalogItemsApi;
import org.opendevstack.component_provisioner.client.component_catalog.v1.api.ProvisionerActionsApi;
import org.opendevstack.component_provisioner.client.component_catalog.v1.model.CatalogItem;
import org.opendevstack.component_provisioner.client.component_catalog.v1.model.CatalogItemUserAction;
import org.opendevstack.component_provisioner.client.component_catalog.v1.model.CatalogItemUserActionParameter;
import org.opendevstack.component_provisioner.client.component_catalog.v1.model.ProjectComponentParameter;
import org.opendevstack.component_provisioner.client.component_catalog.v1.model.ProvisioningDeleteRequest;
import org.opendevstack.component_provisioner.client.component_catalog.v1.model.ProvisioningStatus;
import org.opendevstack.component_provisioner.client.component_catalog.v1.model.ProvisioningStatusUpdateRequest;
import org.opendevstack.component_provisioner.client.component_catalog.v1.model.*;
import org.opendevstack.component_provisioner.config.ApplicationPropertiesConfiguration;
import org.opendevstack.component_provisioner.server.mappers.CreateIncidentParameterMapper;
import org.opendevstack.component_provisioner.server.mappers.EntitiesMapper;
Expand All @@ -28,6 +22,7 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

Expand Down Expand Up @@ -147,7 +142,7 @@ void givenProjectComponent_whenGetDeletionParameters_thenReturnsMappedParameters
.id("PROVISION")
.parameters(List.of(actionParam))
.build()));
when(catalogItemsApi.getCatalogItemById(any())).thenReturn(catalogItem);
when(catalogItemsApi.getCatalogItemById(any(), isNull())).thenReturn(catalogItem);

var projectParam = ProjectComponentParameter.builder()
.name("param1")
Expand Down Expand Up @@ -187,7 +182,7 @@ void givenUserActionsIsNull_whenGetDeletionParameters_thenReturnsEmptyList() thr

CatalogItem catalogItem = new CatalogItem();
catalogItem.setUserActions(null);
when(catalogItemsApi.getCatalogItemById(any())).thenReturn(catalogItem);
when(catalogItemsApi.getCatalogItemById(any(), isNull())).thenReturn(catalogItem);

// when
var result = provisionService.getDeletionParameters(projectKey, componentId);
Expand Down Expand Up @@ -218,7 +213,7 @@ void givenActionParametersIsNull_whenGetDeletionParameters_thenReturnsEmptyList(
catalogItem.setUserActions(List.of(CatalogItemUserAction.builder()
.parameters(null)
.build()));
when(catalogItemsApi.getCatalogItemById(any())).thenReturn(catalogItem);
when(catalogItemsApi.getCatalogItemById(any(), isNull())).thenReturn(catalogItem);

// when
var result = provisionService.getDeletionParameters(projectKey, componentId);
Expand Down Expand Up @@ -252,7 +247,7 @@ void givenSendOnDeletionIsFalse_whenGetDeletionParameters_thenReturnsEmptyList()
.sendOnDeletion(false)
.build()))
.build()));
when(catalogItemsApi.getCatalogItemById(any())).thenReturn(catalogItem);
when(catalogItemsApi.getCatalogItemById(any(), isNull())).thenReturn(catalogItem);

// when
var result = provisionService.getDeletionParameters(projectKey, componentId);
Expand Down Expand Up @@ -287,7 +282,7 @@ void givenProjectParametersIsNull_whenGetDeletionParameters_thenReturnsEmptyList
.sendOnDeletion(true)
.build()))
.build()));
when(catalogItemsApi.getCatalogItemById(any())).thenReturn(catalogItem);
when(catalogItemsApi.getCatalogItemById(any(), isNull())).thenReturn(catalogItem);

// when
var result = provisionService.getDeletionParameters(projectKey, componentId);
Expand Down Expand Up @@ -321,7 +316,7 @@ void givenParamNameNotFoundInProject_whenGetDeletionParameters_thenReturnsEmptyL
.sendOnDeletion(true)
.build()))
.build()));
when(catalogItemsApi.getCatalogItemById(any())).thenReturn(catalogItem);
when(catalogItemsApi.getCatalogItemById(any(), isNull())).thenReturn(catalogItem);

var projectParam = ProjectComponentParameter.builder()
.name("param1")
Expand Down
1 change: 1 addition & 0 deletions src/test/resources/application-testing.env
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ SPRING_CLOUD_AZURE_ACTIVE_DIRECTORY_CREDENTIAL_CLIENT_ID="api://21920dff-90ff-4b

SPRING_SECURITY_PROVISIONER_USERNAME=username
SPRING_SECURITY_PROVISIONER_PASSWORD=password
SECURITY_SHARED_SECRET=test-shared-secret

COMPONENT_CATALOG_PROVISIONER_USERNAME=<place-your-username-here>
COMPONENT_CATALOG_PROVISIONER_PASSWORD=<place-your-password-here>
Expand Down
Loading