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

Validator for duplicate names in iamResource trait #2293

Merged
merged 7 commits into from
May 22, 2024

Conversation

tkyadav
Copy link
Contributor

@tkyadav tkyadav commented May 20, 2024

Background

IamResourceTraitValidator does not validates conflicting resource names in IAM space. For example, assume there exists two resource shapes Resource1 and Resource2. If I add trait @iamResource(name: "Resource1") on Resource2, there are conflicting resource names in the IAM space. This behavior is not detected/prevented by any validator in smithy.

Testing

Wrote a unit test for the validator.


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@tkyadav tkyadav requested a review from a team as a code owner May 20, 2024 21:20
@tkyadav tkyadav requested a review from syall May 20, 2024 21:20
for (ResourceShape resource : topDownIndex.getContainedResources(service)) {
String resourceName = resource.getId().getName();
IamResourceTrait iamResourceTrait;
if (resource.hasTrait(IamResourceTrait.class) && resource.getTrait(IamResourceTrait.class).isPresent()
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can use expectTrait. As hasTrait is already called, if the trait isn't actually resolved then that's an error - https://smithy.io/javadoc/1.5.1/software/amazon/smithy/model/shapes/Shape.html#expectTrait(java.lang.Class)

Copy link
Contributor

@0xjjoyy 0xjjoyy left a comment

Choose a reason for hiding this comment

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

Copy link
Contributor

@syall syall left a comment

Choose a reason for hiding this comment

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

Instead of creating an event per conflict found, I think it would be better to collect all conflicting resources and then emit 1 event.

For example, if there were 3 resources that conflict:

// Omitted other irrelevant shapes
@aws.iam#iamResource(name: "Beer")
resource BadIamResourceName1 {}
@aws.iam#iamResource(name: "Beer")
resource BadIamResourceName2 {}
@aws.iam#iamResource(name: "Beer")
resource BadIamResourceName3 {}

the validator currently would emit 2 events:

[ERROR] smithy.example#BadIamResourceName2: Conflicting IAM resource names in an entire service closure is not allowed. This IAM resource name `Beer` conflicts with other resource `(resource: `smithy.example#BadIamResourceName1`)` in the service `smithy.example#MyService`. | IamResourceTraitConflictingName
[ERROR] smithy.example#BadIamResourceName3: Conflicting IAM resource names in an entire service closure is not allowed. This IAM resource name `Beer` conflicts with other resource `(resource: `smithy.example#BadIamResourceName1`)` in the service `smithy.example#MyService`. | IamResourceTraitConflictingName

Also, this will create events based on the order the model is traversed, which may not be stable across model changes.

Instead, I think it would be better to collect all of the conflicting names into 1 event:

[ERROR] smithy.example#MyService: Multiple IAM resources defined with the same IAM resource name is not allowed in a service closure, but found multiple resources named `Beer` in the service `smithy.example#MyService`: `smithy.example#BadIamResourceName1`, `smithy.example#BadIamResourceName2`, `smithy.example#BadIamResourceName3` | IamResourceTraitConflictingName

Also, should resources without the iamResource trait be included in this validation?

Comment on lines 49 to 54
String resourceName = resource.getId().getName();
IamResourceTrait iamResourceTrait;
if (resource.hasTrait(IamResourceTrait.class)
&& resource.expectTrait(IamResourceTrait.class).getName().isPresent()) {
resourceName = resource.getTrait(IamResourceTrait.class).get().getName().get();
}
Copy link
Contributor

@syall syall May 21, 2024

Choose a reason for hiding this comment

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

I think the method you want to use is IamResourceTrait::resolveResourceName().

To get the resource name in the IAM space, something like this could work:

String resourceName = IamResourceTrait.resolveResourceName(resource);

Copy link
Contributor

Choose a reason for hiding this comment

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

Note that this means the .getName check in the if must also be removed, as resolveResourceName checks other sources.

@tkyadav tkyadav requested a review from syall May 22, 2024 17:11
@syall syall merged commit b999809 into smithy-lang:main May 22, 2024
13 checks passed
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.

4 participants