-
Notifications
You must be signed in to change notification settings - Fork 37
Conversation
Codecov Report
@@ Coverage Diff @@
## master #110 +/- ##
=========================================
Coverage ? 67.98%
Complexity ? 377
=========================================
Files ? 36
Lines ? 1968
Branches ? 258
=========================================
Hits ? 1338
Misses ? 526
Partials ? 104
Continue to review full report at Codecov.
|
Hi @chingor13 @JesseLovelace @jkwlui @broady, I resolved presubmit checks, please review when you have a moment. Thank you! |
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.
a few question, but looks good in general!
private Condition condition; | ||
|
||
public static class Builder { | ||
private List<String> members = new ArrayList(); |
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.
Did we end up deciding to use a List
instead of a Set
for the list of members?
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 updated it to List<> instead of Set<> to get the conversation moving. I can revert back to Set<>.
@@ -85,22 +96,25 @@ public String apply(Identity identity) { | |||
|
|||
@Override | |||
protected Policy fromPb(com.google.iam.v1.Policy policyPb) { | |||
Map<Role, Set<Identity>> bindings = new HashMap<>(); | |||
List<Binding> bindingsList = new ArrayList<Binding>(); |
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 want to allow users to modify the binding in-place?
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'd need to allow mutations outside of builders. That's okay but it does allow for mutation directly of the policy when it wasn't allowed beforehand.
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 could use ImmutableList.Builder
if we want to keep it immutable
setCondition(binding.condition); | ||
} | ||
|
||
public final Binding.Builder setRole(String role) { |
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.
is there a reason to use String
instead of Role
?
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'm trying to remove helpers from the new usage patterns. I could add them back in though.
private List<String> members; | ||
private Condition condition; | ||
|
||
public static class Builder { |
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.
Should we be using auto-value for these classes and builders if they are meant to be value classes?
It might be tricky if we're trying to enforce that the list of members is immutable on the actual value, but it's probably worthwhile to have these classes fully immutable.
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.
good call I didn't think about using auto-value and I think you're right in that it can be helpful to be fully immutable reducing the number of builders.
Please correct me but I don't think I should update the Policy class but only Binding and Condition to use Auto-Value.
I notice there are no documentation on the fields/getter/setter for auto-value classes. @chingor13 how do we usually document these? |
I can add documentation to autovalue implementation after I get a review of the surface. |
import javax.annotation.Nullable; | ||
|
||
@AutoValue | ||
abstract class Condition { |
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 probably be public?
import javax.annotation.Nullable; | ||
|
||
@AutoValue | ||
abstract class Binding { |
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 probably be public?
abstract class Binding { | ||
abstract String getRole(); | ||
|
||
abstract ImmutableList<String> getMembers(); |
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.
Assuming this class is public, we want to keep guava types off the surface of the classes. This should be a List<String>
and we'd document that the implementation is immutable so they shouldn't try to modify it.
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 missed this comment a while back. The reason I'm using ImmutableList<> is based on recommendation from AutoValue docs https://github.com/google/auto/blob/master/value/userguide/builders-howto.md#-use-a-collection-valued-property. I want getMembers() to support a builder helper as well in case it's easier for users.
WDYT?
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.
Removed ImmutableList and now using List in the surface while still supporting helper methods addMembers and removeMembers.
@@ -85,22 +96,25 @@ public String apply(Identity identity) { | |||
|
|||
@Override | |||
protected Policy fromPb(com.google.iam.v1.Policy policyPb) { | |||
Map<Role, Set<Identity>> bindings = new HashMap<>(); | |||
List<Binding> bindingsList = new ArrayList<Binding>(); |
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 could use ImmutableList.Builder
if we want to keep it immutable
|
||
package com.google.cloud; | ||
|
||
import static org.junit.Assert.*; |
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.
nit: avoid * imports
* Return false if Policy is version 3 OR bindings has a conditional binding. | ||
* Return true if Policy is version 1 AND bindings does not have a conditional binding. | ||
*/ | ||
private static boolean checkVersion(int version, List<Binding> bindingsList) { |
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 might call this isVersion
. The check*
methods in guava throw exceptions when conditions are not met, whereas this method is returning a boolean
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.
LGTM
Codecov Report
@@ Coverage Diff @@
## master #110 +/- ##
=========================================
Coverage ? 67.98%
Complexity ? 377
=========================================
Files ? 36
Lines ? 1968
Branches ? 258
=========================================
Hits ? 1338
Misses ? 526
Partials ? 104
Continue to review full report at Codecov.
|
Codecov Report
@@ Coverage Diff @@
## master #110 +/- ##
=========================================
Coverage 67.94% 67.94%
Complexity 377 377
=========================================
Files 36 36
Lines 1959 1959
Branches 254 254
=========================================
Hits 1331 1331
Misses 524 524
Partials 104 104
Continue to review full report at Codecov.
|
Updated based on discussion with @chingor13, @kolea2, @elharo, @jkwlui, and David (not sure of their Github handle). Please take a look when you have a moment. Thank you for your help. |
cc: @netdpb (David) |
return false; | ||
} | ||
for (int i = 0; i < bindingsList.size(); i++) { | ||
bindingsList.get(i).equals(other.getBindingsList().get(i)); |
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.
sorry, missed this. Should this be returning something?
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.
oh, I missed this as well. Will fix.
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 haven't finished reviewing the test code yet, but I have to run.
Feel free not to address all (or any!) of these issues in this PR if they require further discussion.
Some are pure style nits, which you should feel free to ignore anyway (like deleting the final period at the end of a Javadoc @throws
clause).
|
||
public abstract ImmutableList<String> getMembers(); | ||
|
||
@Nullable |
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.
Why @Nullable
instead of a non-nullable Optional<Condition>
?
Either is okay, but it's interesting that you're using both patterns in the same class.
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 picked Nullable because it made more sense to me in this case. I'm not well versed in Optional's. Both patterns? Not sure I understand.
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.
Sorry, I thought for some reason that you were also using Optional
. Don't know why I thought that.
public abstract static class Builder { | ||
public abstract Builder setRole(String role); | ||
|
||
public abstract Builder setMembers(List<String> members); |
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 could even take Iterable<String>
if you want to be most general.
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.
Thanks, addressing.
|
||
public abstract String getRole(); | ||
|
||
public abstract ImmutableList<String> getMembers(); |
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 you expect this to be called other than from addMembers(String...)
and removeMembers(String...)
? If not, make this have default access.
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.
No, good point.
|
||
public abstract Builder setCondition(Condition condition); | ||
|
||
public abstract String getRole(); |
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.
Is this used from anywhere? Do you need it? Generally, builders don't need getters.
Same for getCondition()
.
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.
removed to reduce surface size. At the moment they were convenience but I'd like to get more developer input before adding unnecessary methods to the public surface.
@BetaApi("This is a Beta API is not stable yet and may change in the future.") | ||
@AutoValue | ||
public abstract class Condition { | ||
@Nullable |
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.
Why are these nullable?
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.
Good point, no reason other than my first attempt with AutoValue. removing.
checkArgument( | ||
!isConditional(this.version, this.bindingsList), | ||
"getBindings() is only supported with version 1 policies and non-conditional policies"); | ||
ImmutableMap.Builder<Role, Set<Identity>> bindingsV1Builder = ImmutableMap.builder(); |
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.
You can use an ImmutableSetMultimap
instead, regardless of whether you change the method return type. You can always get the map out with Multimaps.asMap()
.
} | ||
|
||
/** Returns the list of bindings that comprises the policy for version 3. */ | ||
public List<Binding> getBindingsList() { |
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.
public List<Binding> getBindingsList() { | |
public ImmutableList<Binding> getBindingsList() { |
return Objects.equals(bindings, other.getBindings()) | ||
&& Objects.equals(etag, other.getEtag()) | ||
&& Objects.equals(version, other.getVersion()); | ||
if (bindingsList.size() != other.getBindingsList().size()) { |
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 whole block can be just
if (!bindingsList.equals(other.getBindingsList())) {
return false;
}
for (int i = 0; i < bindingsList.size(); i++) { | ||
bindingsList.get(i).equals(other.getBindingsList().get(i)); | ||
} | ||
return Objects.equals(etag, other.getEtag()) && Objects.equals(version, other.getVersion()); |
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.
Can etag
ever be null? If not, just call etag.equals(other.getEtag())
.
version
is an int
, so you can just do version == other.getVersion()
. Otherwise you're boxing the int
.
Binding.newBuilder().setRole(EDITOR).setMembers(MEMBERS_LIST_2).build()); | ||
private static final List<Binding> BINDINGS_WITH_CONDITIONS = | ||
ImmutableList.copyOf(BINDINGS_NO_CONDITIONS) | ||
.of( |
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.
You're calling a static method on an instance, and throwing the instance away. That's not what you want to do. (If the project used Error-Prone, this would have generated a warning.)
It looks like you want a variant of BINDINGS_NO_CONDITIONS
where the viewer role has a condition. What about this?
ImmutableList.of(
BINDINGS_NO_CONDITIONS.get(0).toBuilder().setCondition(...).build(),
BINDINGS_NO_CONDITIONS.get(1))
Although it might be nice to have a constant for each element of BINDINGS_NO_CONDITIONS
(VIEWER
and EDITOR
)?
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.
We should still clean up a bunch of the review comments, but they are minor and can be done separately. We can merge, but let's not lose the work items to clean up.
I'll make a separate list and file an issue to track it. Thanks @chingor13! |
|
||
public abstract ImmutableList<String> getMembers(); | ||
|
||
@Nullable |
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.
Sorry, I thought for some reason that you were also using Optional
. Don't know why I thought that.
public static Builder newBuilder() { | ||
return new AutoValue_Binding.Builder(); | ||
List<String> emptyMembers = ImmutableList.of(); |
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.
You could just inline emptyMembers
into setMembers(ImmutableList.of())
.
/** | ||
* Set IAM Members for Policy Binding | ||
* | ||
* @throws NullPointerException if a member is null. |
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.
You don't really need to repeat this everywhere. It's better to use @Nullable
for the hopefully few cases where null is accepted.
* | ||
* @throws IllegalArgumentException if policy version is equal to 3 or has conditional bindings | ||
* because conditional policies are not supported | ||
*/ | ||
public final Builder removeRole(Role role) { | ||
checkArgument( |
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 still think all of these should use checkState
instead of checkArgument
so they throw IllegalStateException
.
Throw IllegalArgumentException
when the caller should have known that the arguments to this method are invalid.
Throw IllegalStateException
when the caller should have known that this method cannot be called given the state of the object.
🤖 I have created a release \*beep\* \*boop\* --- ## [1.93.0](https://www.github.com/googleapis/java-core/compare/v1.92.6...v1.93.0) (2020-02-27) ### Features * support conditional policies ([#110](https://www.github.com/googleapis/java-core/issues/110)) ([61e2d19](https://www.github.com/googleapis/java-core/commit/61e2d19bb4400978681aa018a8dc200214203830)) ### Bug Fixes * fix conversion for pre-epoch timestamps ([#160](https://www.github.com/googleapis/java-core/issues/160)) ([1f8b6b4](https://www.github.com/googleapis/java-core/commit/1f8b6b4835aaa702ec94bbbde89ed90f519c935a)) ### Dependencies * update dependency com.google.api:gax-bom to v1.54.0 ([#168](https://www.github.com/googleapis/java-core/issues/168)) ([5b52f9e](https://www.github.com/googleapis/java-core/commit/5b52f9e8d8cdc82b56114d3d1e857d137ae7ca98)) * update dependency io.grpc:grpc-bom to v1.27.2 ([#166](https://www.github.com/googleapis/java-core/issues/166)) ([28c9859](https://www.github.com/googleapis/java-core/commit/28c98595c9ee96760a063085bd85024177bd6dd2)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please).
fixes: #118
Add support for conditional policies based on design document.
PTAL: @broady @jkwlui @JesseLovelace @chingor13