-
Notifications
You must be signed in to change notification settings - Fork 21
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
Conversation
…rchy under project parent, uses checkPermission as best practice
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ 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
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 1 file with indirect coverage changes Continue to review full report in Codecov by Sentry.
|
RuntimeNotFoundException(cloudContext, runtimeName, "permission denied") | ||
) | ||
} yield resp | ||
.adaptError { case _: SamException => |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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. :)
There was a problem hiding this comment.
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...))
There was a problem hiding this comment.
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]) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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")) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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…))
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(fixed)
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
.