Skip to content

Commit

Permalink
fix: add warning message for related auth subscriptions
Browse files Browse the repository at this point in the history
  • Loading branch information
dpilch committed Jun 20, 2024
1 parent 7d2fce2 commit a57e1ba
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ModelTransformer } from '@aws-amplify/graphql-model-transformer';
import { HasManyTransformer, HasOneTransformer, BelongsToTransformer } from '@aws-amplify/graphql-relational-transformer';
import { testTransform } from '@aws-amplify/graphql-transformer-test-utils';
import { TransformerLog, TransformerLogLevel, TransformParameters } from '@aws-amplify/graphql-transformer-interfaces';
import { AuthTransformer } from '../../graphql-auth-transformer';
Expand Down Expand Up @@ -394,3 +395,92 @@ type Invoice
);
});
});

describe.only('inherit related auth on subscriptions warning', () => {
test('does not show message when auth rules align', () => {
const schema = `
type Primary @model @auth(rules: [{ allow: public }]) {
relatedOne: RelatedOne! @hasOne
}
type RelatedOne @model @auth(rules: [{ allow: public }]) {
primary: Primary! @belongsTo
}
`;
const logs = testTransform({
schema,
authConfig: {
defaultAuthentication: { authenticationType: 'API_KEY' },
additionalAuthenticationProviders: [],
},
transformers: [new ModelTransformer(), new HasOneTransformer(), new BelongsToTransformer(), new AuthTransformer()],
}).logs;

expect(logs.length).toBe(0);
});

test('does not show message when related fields are optional', () => {
const schema = `
type Primary @model @auth(rules: [{ allow: groups, groupsField: "groups" }]) {
content: String
groups: [String]
relatedOne: RelatedOne @hasOne
}
type RelatedOne @model @auth(rules: [{ allow: groups, groupsField: "groups" }]) {
content: String
groups: [String]
primaryId: String
primary: Primary @belongsTo
}
`;
const logs = testTransform({
schema,
authConfig: {
defaultAuthentication: { authenticationType: 'AMAZON_COGNITO_USER_POOLS' },
additionalAuthenticationProviders: [],
},
transformers: [new ModelTransformer(), new HasOneTransformer(), new BelongsToTransformer(), new AuthTransformer()],
}).logs;

expect(logs.length).toBe(0);
});

test('shows message when related fields are required', () => {
const schema = `
type Primary @model @auth(rules: [{ allow: groups, groupsField: "groups" }]) {
content: String
groups: [String]
relatedOne: RelatedOne! @hasOne
}
type RelatedOne @model @auth(rules: [{ allow: groups, groupsField: "groups" }]) {
content: String
groups: [String]
primaryId: String
primary: Primary! @belongsTo
}
`;
const logs = testTransform({
schema,
authConfig: {
defaultAuthentication: { authenticationType: 'AMAZON_COGNITO_USER_POOLS' },
additionalAuthenticationProviders: [],
},
transformers: [new ModelTransformer(), new HasOneTransformer(), new BelongsToTransformer(), new AuthTransformer()],
}).logs;

expect(logs).toMatchInlineSnapshot(`
Array [
Object {
"level": "WARN",
"message": "Subscriptions will inherit related auth when relational fields are set as required. Consider modifying your schema to use optional relational fields for Primary.relatedOne.",
},
Object {
"level": "WARN",
"message": "Subscriptions will inherit related auth when relational fields are set as required. Consider modifying your schema to use optional relational fields for RelatedOne.primary.",
},
]
`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -727,9 +727,6 @@ export class AuthTransformer extends TransformerAuthBase implements TransformerA
// Relational field redaction is default to `needsFieldResolver`, which stays consistent with current behavior of always redacting relational field when field resolver is needed
let redactRelationalField: boolean = needsFieldResolver;
const fieldIsRequired = field.type.kind === Kind.NON_NULL_TYPE;
if (fieldIsRequired) {
redactRelationalField = false;
}
const relatedModelObject = this.getRelatedModelObject(ctx, getBaseType(field.type));
const relatedModelName = relatedModelObject.name.value;
if (this.authModelConfig.has(relatedModelName)) {
Expand All @@ -756,9 +753,7 @@ export class AuthTransformer extends TransformerAuthBase implements TransformerA

// When the default redaction is false, it means no field resolver is involved
// Need the additional check on model level auth rules of both sides to determine the relational field redaction
// do not redact relational field when required
// appsync will throw an error if trying to nullify a required field
if (!fieldIsRequired && !redactRelationalField) {
if (!redactRelationalField) {
let filteredRelatedModelReadRoleDefinitions = roleDefinitions;
// When userpool private roles are detected, filter out the non-private userpool roles
if (filteredRelatedModelReadRoleDefinitions.some((r) => r.provider === 'userPools' && r.strategy === 'private')) {
Expand Down Expand Up @@ -790,6 +785,14 @@ export class AuthTransformer extends TransformerAuthBase implements TransformerA
return fieldReadRoleDefinitions.some((fr) => isIdenticalAuthRole(fr, relatedRole) && !isDynamicAuthOrCustomAuth(fr));
});
redactRelationalField = !isIdenticalRoleDefinitions;
// do not redact relational field when required
// appsync will throw an error if trying to nullify a required field
if (redactRelationalField && fieldIsRequired) {
redactRelationalField = false;
this.warn(
`Subscriptions will inherit related auth when relational fields are set as required. Consider modifying your schema to use optional relational fields for ${typeName}.${field.name.value}.`,
);
}
break;
}
}
Expand Down

0 comments on commit a57e1ba

Please sign in to comment.