Skip to content

Commit

Permalink
fix: additional fixes and tests related to cross-model field comparis…
Browse files Browse the repository at this point in the history
…on (#1496)
  • Loading branch information
ymc9 authored Jun 9, 2024
1 parent 54e1e02 commit 28c2bc8
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 6 deletions.
6 changes: 4 additions & 2 deletions packages/schema/src/plugins/enhancer/policy/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,9 @@ function hasCrossModelComparison(expr: Expression) {
}

function getSourceModelOfFieldAccess(expr: Expression) {
if (isDataModel(expr.$resolvedType?.decl)) {
// an expression that resolves to a data model and is part of a member access, return the model
// e.g.: profile.age => Profile
if (isDataModel(expr.$resolvedType?.decl) && isMemberAccessExpr(expr.$container)) {
return expr.$resolvedType?.decl;
}

Expand All @@ -497,7 +499,7 @@ function getSourceModelOfFieldAccess(expr: Expression) {
return getContainerOfType(expr, isDataModel);
}

// direct field reference
// direct field reference, return the model
if (isDataModelFieldReference(expr)) {
return (expr.target.ref as DataModelField).$container;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -769,8 +769,8 @@ describe('Cross-model field comparison', () => {
await expect(db.user.update({ where: { id: 1 }, data: { age: 25 } })).toResolveTruthy();
});

it('with auth', async () => {
const { prisma, enhance } = await loadSchema(
it('with auth case 1', async () => {
const { enhance } = await loadSchema(
`
model User {
id Int @id @default(autoincrement())
Expand Down Expand Up @@ -803,8 +803,7 @@ describe('Cross-model field comparison', () => {
level Int
@@allow('all', true)
}
`,
{ preserveTsFiles: true }
`
);

await expect(enhance().post.create({ data: { title: 'P1' } })).toBeRejectedByPolicy();
Expand All @@ -820,4 +819,182 @@ describe('Cross-model field comparison', () => {
})
).toResolveTruthy();
});

it('with auth case 2', async () => {
const { prisma, enhance } = await loadSchema(
`
model User {
id Int @id @default(autoincrement())
teamMembership TeamMembership[]
@@allow('all', true)
}
model Team {
id Int @id @default(autoincrement())
permissions Permission[]
assets Asset[]
@@allow('all', true)
}
model Asset {
id Int @id @default(autoincrement())
name String
team Team @relation(fields: [teamId], references: [id])
teamId Int
@@allow('all', auth().teamMembership?[role.permissions?[name == 'ManageTeam' && teamId == this.teamId]])
@@allow('read', true)
}
model TeamMembership {
id Int @id @default(autoincrement())
role TeamRole?
user User @relation(fields: [userId], references: [id])
userId Int
@@allow('all', true)
}
model TeamRole {
id Int @id @default(autoincrement())
permissions Permission[]
membership TeamMembership @relation(fields: [membershipId], references: [id])
membershipId Int @unique
@@allow('all', true)
}
model Permission {
id Int @id @default(autoincrement())
name String
team Team @relation(fields: [teamId], references: [id])
teamId Int
role TeamRole @relation(fields: [roleId], references: [id])
roleId Int
@@allow('all', true)
}
`
);

const team1 = await prisma.team.create({ data: {} });
const team2 = await prisma.team.create({ data: {} });

const user = await prisma.user.create({
data: {
teamMembership: {
create: {
role: {
create: {
permissions: { create: [{ name: 'ManageTeam', team: { connect: { id: team1.id } } }] },
},
},
},
},
},
});

const asset = await prisma.asset.create({
data: { name: 'Asset1', team: { connect: { id: team1.id } } },
});

const dbTeam1 = enhance({
id: user.id,
teamMembership: [{ role: { permissions: [{ name: 'ManageTeam', teamId: team1.id }] } }],
});
await expect(dbTeam1.asset.update({ where: { id: asset.id }, data: { name: 'Asset2' } })).toResolveTruthy();

const dbTeam2 = enhance({
id: user.id,
teamMembership: [{ role: { permissions: [{ name: 'ManageTeam', teamId: team2.id }] } }],
});
await expect(
dbTeam2.asset.update({ where: { id: asset.id }, data: { name: 'Asset2' } })
).toBeRejectedByPolicy();
});

it('with auth case 3', async () => {
const { prisma, enhance } = await loadSchema(
`
model User {
id Int @id @default(autoincrement())
teamMembership TeamMembership[]
@@allow('all', true)
}
model Team {
id Int @id @default(autoincrement())
permissions Permission[]
assets Asset[]
@@allow('all', true)
}
model Asset {
id Int @id @default(autoincrement())
name String
team Team @relation(fields: [teamId], references: [id])
teamId Int
@@allow('all', auth().teamMembership?[role.permissions?[name == 'ManageTeam' && team == this.team]])
@@allow('read', true)
}
model TeamMembership {
id Int @id @default(autoincrement())
role TeamRole?
user User @relation(fields: [userId], references: [id])
userId Int
@@allow('all', true)
}
model TeamRole {
id Int @id @default(autoincrement())
permissions Permission[]
membership TeamMembership @relation(fields: [membershipId], references: [id])
membershipId Int @unique
@@allow('all', true)
}
model Permission {
id Int @id @default(autoincrement())
name String
team Team @relation(fields: [teamId], references: [id])
teamId Int
role TeamRole @relation(fields: [roleId], references: [id])
roleId Int
@@allow('all', true)
}
`
);

const team1 = await prisma.team.create({ data: {} });
const team2 = await prisma.team.create({ data: {} });

const user = await prisma.user.create({
data: {
teamMembership: {
create: {
role: {
create: {
permissions: { create: [{ name: 'ManageTeam', team: { connect: { id: team1.id } } }] },
},
},
},
},
},
});

const asset = await prisma.asset.create({
data: { name: 'Asset1', team: { connect: { id: team1.id } } },
});

const dbTeam1 = enhance({
id: user.id,
teamMembership: [{ role: { permissions: [{ name: 'ManageTeam', team: { id: team1.id } }] } }],
});
await expect(dbTeam1.asset.update({ where: { id: asset.id }, data: { name: 'Asset2' } })).toResolveTruthy();

const dbTeam2 = enhance({
id: user.id,
teamMembership: [{ role: { permissions: [{ name: 'ManageTeam', teamId: team2.id }] } }],
});
await expect(
dbTeam2.asset.update({ where: { id: asset.id }, data: { name: 'Asset2' } })
).toBeRejectedByPolicy();
});
});

0 comments on commit 28c2bc8

Please sign in to comment.