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

fix: redact relational field in mutation & subscription based on model auth rules #2536

Draft
wants to merge 44 commits into
base: main
Choose a base branch
from

Conversation

AaronZyLee
Copy link
Contributor

@AaronZyLee AaronZyLee commented May 8, 2024

Description of changes

The relational field is redacted in mutation result and subsequent subscription from another client based on the comparison result of

  • Read role definitions for relational field
  • Read role definitions for the related model

The comparison will occur if the relational field is not protected by any field level auth rules (as the field is redacted when field level auth is added currently). The field redaction will only happen when the model subscription level is on in either case

CDK / CloudFormation Parameters Changed

Issue #, if available

N/A

Description of how you validated changes

  • Unit tests
  • E2E tests

Checklist

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

@AaronZyLee AaronZyLee requested a review from a team as a code owner May 8, 2024 19:03
@AaronZyLee AaronZyLee changed the title fix: redact relational field in mutation & subscription based on mode… fix: redact relational field in mutation & subscription based on model auth rules May 8, 2024
@AaronZyLee AaronZyLee marked this pull request as draft May 8, 2024 19:07
@@ -185,7 +185,7 @@ export class DDBRelationalResolverGenerator extends RelationalResolverGenerator
MappingTemplate.s3MappingTemplateFromString(
print(
compoundExpression([
iff(ref('ctx.stash.deniedField'), raw('#return($util.toJson(null))')),
iff(ref('ctx.stash.deniedField'), compoundExpression([set(ref('result'), obj({ items: list([]) })), raw('#return($result)')])),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For a hasMany relation, when the field is redacted, the { item: [] } should be returned instead of a null value. Otherwise the following error will be thrown by AppSync
Screenshot 2024-05-08 at 10 59 03 AM

Copy link
Contributor

Choose a reason for hiding this comment

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

Is it because the related field is not null. I believe we don't this today if the auth rules on the relational field is restrictive than model rules.

/**
* Primary auth rules - Related auth rules - Redact relational field
*/
const testCases: [string[], string[], boolean][] = [
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These test cases are the main part of this unit test, which defines the different auth rules on both relation models and whether to redact the relational field. These cases are tested below in the dimension of data source types and relation types(field or reference)

* @param role2 auth role 2
* @returns boolean for two roles are identical
*/
const isIdenticalAuthRole = (role1: RoleDefinition, role2: RoleDefinition): boolean =>
Copy link
Member

Choose a reason for hiding this comment

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

nit: can you add this as a utliity near the RoleDefinition type itself, and add some unit tests to catch edge cases. Especially to make sure we handle undefined elements in one or both operands.

(relatedRole) =>
isIdenticalAuthRole(relatedRole, fieldRole) ||
(relatedRole.provider === fieldRole.provider &&
(relatedRole.provider === 'userPools' || relatedRole.provider === 'oidc') &&
Copy link
Member

Choose a reason for hiding this comment

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

  1. Wouldn't identityPools be a valid provider for this case?
  2. As above, put this utility in RoleDefinition & make sure we have plenty of tests for it

* @param role auth role definition
* @returns boolean for the auth role is a dynamic or custom auth role
*/
const isDynamicAuthOrCustomAuth = (role: RoleDefinition): boolean =>
Copy link
Member

Choose a reason for hiding this comment

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

as above, put this utility in RoleDefinition & make sure we have plenty of tests for it

if (isFieldRoleHavingAccessToBothSide(fieldRole, filteredRelatedModelReadRoleDefinitions)) {
// Check if two role definitions are identical without dynamic auth role or custom auth role
// If not, redact the relational field
redactRelationalField = !(
Copy link
Member

Choose a reason for hiding this comment

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

This filter is pretty hard to parse (a negation of a multi-layer boolean test that includes 2 loops). Can you separate it out for readibility?

}
`;

const referenceSchemaTempalte = `
Copy link
Member

Choose a reason for hiding this comment

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

nit

Suggested change
const referenceSchemaTempalte = `
const referenceSchemaTemplate = `

}
test.each(testTable)('%s - Primary %s - Related %s should redact relational field - %s', expectation);
});
describe('RDS datasources - reference relation', () => {
Copy link
Member

Choose a reason for hiding this comment

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

It "shouldn't" make a difference, but we should test heterogeneous relationships as well (DDB Primary, SQL Related; and SQL Primary, DDB Related)

@dpilch dpilch self-assigned this May 15, 2024
@dpilch dpilch force-pushed the fix-sub-owner branch 2 times, most recently from 28c90f2 to 1a6beac Compare May 17, 2024 21:17
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.

None yet

4 participants