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

[IA-5066] DO NOT MERGE getRuntime v1 checks notebook-cluster-status action assuming hiera… #4785

Closed
wants to merge 4 commits into from

Conversation

mlilynolting
Copy link
Contributor

@mlilynolting mlilynolting commented Sep 18, 2024

Assumes Sam model hierarchy of runtime under project parent, uses checkPermission as best practice.

Jira ticket: https://broadworkbench.atlassian.net/browse/IA-5066

https://broadworkbench.atlassian.net/browse/IA-5063

Summary of changes

getRuntime now checks permission once, for the relevant runtime action, using the preferred SamService checkPermission.

…rchy under project parent, uses checkPermission as best practice
@mlilynolting mlilynolting changed the title [IA-5066] getRuntime v1 checks notebook-cluster-status action assuming hiera… [IA-5066] DO NOT MERGE getRuntime v1 checks notebook-cluster-status action assuming hiera… Sep 18, 2024
@mlilynolting mlilynolting marked this pull request as draft September 18, 2024 18:07
Copy link

codecov bot commented Sep 18, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 74.78%. Comparing base (4ad7058) to head (e66ffe4).
Report is 9 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #4785      +/-   ##
===========================================
- Coverage    74.79%   74.78%   -0.02%     
===========================================
  Files          165      165              
  Lines        14946    14940       -6     
  Branches      1178     1144      -34     
===========================================
- Hits         11179    11173       -6     
  Misses        3767     3767              
Flag Coverage Δ
74.78% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...h/leonardo/http/service/RuntimeServiceInterp.scala 88.73% <100.00%> (+0.19%) ⬆️

... and 1 file with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4ad7058...e66ffe4. Read the comment docs.

RuntimeNotFoundException(cloudContext, runtimeName, "permission denied")
)
} yield resp
.adaptError { case _: SamException =>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need to adapt the error? SamServiceInterp already throws a friendly LeoException with status 403 -- can we just throw that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My understanding is that the best practice is to mask 403/forbidden style errors with 404 messages, since users without access rights shouldn't be able to verify that a runtime with the given ID even exists. This is how getRuntime worked before, and I think it's standard across Leo (and a pretty common pattern elsewhere)

Copy link
Collaborator

Choose a reason for hiding this comment

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

I feel like it's reasonable to respond 404 if the runtime doesn't exist and 403 if the runtime exists but the caller doesn't have permission.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll ask AppSec what their preferred behavior is.

For context I think you wrote this comment ~4ya

Copy link
Collaborator

@rtitle rtitle Sep 19, 2024

Choose a reason for hiding this comment

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

I think our comments crossed.. yeah, just thinking more about the best practice.

For instance, I was trying google apis and they seem to respond 403 in both cases:

$ gcloud projects describe asdfasdffoobar --verbosity debug

 User [[email protected]] does not have permission to access projects instance [asdfasdffoobar] (or it may not exist):
…
  "error": {
    "code": 403,
    "message": "The caller does not have permission",
    "status": "PERMISSION_DENIED"
  }

Maybe we should respond 403 with a message "Caller does not have permission or it doesn't exist" 🤔


// throws 404 if not existent
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would be nice to keep this comment -- RuntimeServiceDbQueries.getRuntime will throw 404 if the runtime doesn't exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I got tripped up on "throw" and was frustrated trying to test it until I realized that it wasn't throwing the error, it was returning it in the usual Scala way. Wasn't sure of the right verb and wasn't sure that it needed saying

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, that's an annoyance I have with this Scala style: the exceptions aren't annotated. Any IO can throw any Throwable at any time. At least in Java you can specify throws IOException, for example (although you still have unchecked exceptions so it's not perfect).

Anyway that's just my thinking about why I like to leave comments about what certain things can throw. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But it isn't throwing, is it? Like these come back as return values in Eithers, like Left(SamException...))

Copy link
Collaborator

@rtitle rtitle Sep 19, 2024

Choose a reason for hiding this comment

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

It throws the exception when you run the IO, and it short-circuits the for-comprehension. So close enough to throwing, IMO.

Technically they are not Eithers -- there is no Either in the type. An IO[A] can either yield a successful A or raise an error, which short-circuits subsequent flatMap chains. But they are not represented as Either, the success-or-failure behavior is baked into the IO data type.

@@ -819,34 +821,65 @@ class RuntimeServiceInterpTest
}

it should "get a runtime" in isolatedDbTest {
val mockSamService: SamService[IO] = mock[SamService[IO]](defaultMockitoAnswer[IO])
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should be the default response of MockSamService, so not sure you need to override the mock here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

MockSamService isn't a Mockito mock, though, and I wanted to have access to the method stubbing/mocking for my tests.

val service = makeRuntimeService(samService = mockSamService)

val exc = service
.getRuntime(unauthorizedUserInfo, cloudContextGcp, RuntimeName("cluster"))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure this call is hitting samService.checkAuthorized. Seems like we want to be getting an existing runtime, to verify the access control check fails as expected? Right now it looks like the runtime doesn't exist, so it would return 404.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

(fixed)

isEq(RuntimeAction.GetRuntimeStatus)
)(any(Ask[IO, AppContext].getClass))
).thenReturn(
IO.pure(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Don't think IO[Either[..]] is the correct return type. Maybe .thenReturn(IO.raiseException(SamException.create…))?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

(fixed)

@LizBaldo LizBaldo closed this Oct 28, 2024
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.

3 participants