Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Get and GetCredentials for CFServiceInstances #3610

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

klapkov
Copy link
Contributor

@klapkov klapkov commented Nov 11, 2024

Is there a related GitHub Issue?

#3609
#3608

What is this change about?

Here we expose GET /v3/service_instances/:guid and we also add GET /v3/service_instances/:guid/credentials

Does this PR introduce a breaking change?

No

Acceptance Steps

Tag your pair, your PM, and/or team

api/handlers/service_instance.go Outdated Show resolved Hide resolved
api/handlers/service_instance.go Show resolved Hide resolved
api/handlers/service_instance.go Outdated Show resolved Hide resolved

serviceInstance, err := h.serviceInstanceRepo.GetServiceInstance(r.Context(), authInfo, serviceInstanceGUID)
if err != nil {
return nil, apierrors.LogAndReturn(logger, err, "failed to get service instance")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should "mask" the forbidden error as "not found" in order not to leak information. See here for example

})

It("returns 404 Not Found", func() {
expectNotAuthorizedError()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the It says "returns 404" (correct), but it verifies for not authorised error (not correct :))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The api should mask forbidden error as not found. Therefore the test should expect a not found error rather then unauthorised. I think you did it the other way round :)

}
}`),
}))
When("ToCredentialsSecretData", func() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This When should be a Describe as it describes a function under test


JustBeforeEach(func() {
var err error
secretData, err = tools.ToCredentialsSecretData(credsObject)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invoking the method under test should be performed within the describe for that function. It should not be invoked in the global describe

credsObject any
secretData map[string][]byte
credsObject any
secretData map[string][]byte
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

secretData can be local to the ToCredentialsSecretData describe

secretData map[string][]byte
credsObject any
secretData map[string][]byte
decodedCredentials map[string]any
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decodedCredentials should be pushed down to ToDecodedSecretDataCredentials describe

tools/credentials_test.go Show resolved Hide resolved
@danail-branekov
Copy link
Member

Also, e2e tests would be nice for the two new endpoints

@klapkov
Copy link
Contributor Author

klapkov commented Dec 12, 2024

@danail-branekov Did some changes, could you take a look.

@klapkov klapkov force-pushed the get_service_is_credentials branch from 612645d to 76ed317 Compare December 12, 2024 09:04
Copy link
Member

@danail-branekov danail-branekov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have resolved the comments that have been already addressed, and left the ones that have not been unresolved.
I have also added some more comments, please have a look

return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "failed to get service instance", "GUID", serviceInstanceGUID)
}

if serviceInstance.Type != korifiv1alpha1.UserProvidedType {
Copy link
Member

@danail-branekov danail-branekov Dec 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to push this check to the repository (reasoning below). The repository looks up the service instance anyway, so it could return a not found error in case the service instance type is not upsi.

From API point of view, instance credentials are just another resource. We strive to keep api handlers simple and only take care to process the request parameters, delegate to a repository and present the result. Business logic on aspects of getting and processing resources should be "outsourced" to repositories.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forget about it, after a short discussion, having that decision in the handler is probably ok. Apologies for the noise


serviceInstance, err := h.serviceInstanceRepo.GetServiceInstance(r.Context(), authInfo, serviceInstanceGUID)
if err != nil {
return nil, apierrors.LogAndReturn(logger, err, "failed to get service instance")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still not resolved, the api should mask forbidden errors as not found

})

It("returns 404 Not Found", func() {
expectNotAuthorizedError()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The api should mask forbidden error as not found. Therefore the test should expect a not found error rather then unauthorised. I think you did it the other way round :)

})

It("returns 404 Not Found", func() {
_, actualAuthInfo, actualInstanceGUID := serviceInstanceRepo.GetServiceInstanceCredentialsArgsForCall(0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my point of view, checking GetServiceInstanceCredentials invocation and its parameter duplicates the checks in the default case. I think expecting a not found error is enough for this test.

})
})

When("getting the service instance fails with not found", func() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the handler should only interpret the "forbidden" error and present it as not found. Any other sort of errors (regiardless not found, general error, whatever) should be just returned.

Having said that, I would alter this When to verify that when the repository returns a generic error, it results into an unexpected error (HTTP 500). In other words, as the handler does not handle the not found error in any particular way, I would go for the least specific test case.

})
})

When("the unmarshaling of the secret fails", func() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the comment on the "not found" error above. The handler does not handle unprocessable entity error in any particular way, it simply returns it. Another context with this particular error does not bring any more value. Therefore I would propose deleting at in order to keep the test simple

})
})
})
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add a When to verify that the repository returns unprocessiable entity error when the secret data is invalid json?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danail-branekov Maybe this is a stupid question, but how would I achieve that ? I would have to create a secret with an invalid json format, how would I marshal it ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

secret = &corev1.Secret{
				ObjectMeta: metav1.ObjectMeta{
					Name:      secretName,
					Namespace: space.Name,
				},
				Data: map[string][]byte{korifiv1alpha1.CredentialSecretKey, []byte{"not-json"}},
			}
Expect(k8sClient.Create(ctx, secret)).To(Succeed())

How about that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants