Skip to content

Commit

Permalink
Add tests and rules to mutations
Browse files Browse the repository at this point in the history
  • Loading branch information
cesarvarela committed Dec 11, 2024
1 parent 8b6cabc commit ba3b46e
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 68 deletions.
2 changes: 1 addition & 1 deletion site/gatsby-site/playwright/seeds/customData/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const users: DBUser[] = [
},
{
_id: new ObjectId("619b47eb5eed5334edfa3bd9"),
userId: "619b47ea5eed5334edfa3bbc",
userId: "648a4c0eaf3f54bf50f018a3",
roles: ["admin"],
first_name: "Sean",
last_name: "McGregor"
Expand Down
14 changes: 6 additions & 8 deletions site/gatsby-site/server/fields/checklists.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { GraphQLFieldConfigMap, GraphQLList } from "graphql";
import { allow } from "graphql-shield";
import { allow, or } from "graphql-shield";
import { generateMutationFields, generateQueryFields, getQueryArgs, getQueryResolver } from "../utils";
import { ChecklistType, RisksInputType, RiskType } from "../types/checklist";
import { isAdmin, isChecklistsOwner, isSubscriber } from "../rules";

const getRiskClassificationsMongoQuery = (tagStrings: any) => {

Expand Down Expand Up @@ -190,21 +191,18 @@ export const queryFields: GraphQLFieldConfigMap<any, any> = {
}

export const mutationFields: GraphQLFieldConfigMap<any, any> = {
...generateMutationFields({ collectionName: 'checklists', Type: ChecklistType, generateFields: ['updateOne', 'deleteOne', 'insertOne', 'upsertOne'] }),
...generateMutationFields({ collectionName: 'checklists', Type: ChecklistType, generateFields: ['deleteOne', 'insertOne', 'upsertOne'] }),
}


export const permissions = {
Query: {
checklist: allow,
checklists: allow,
risks: allow,
},
Mutation: {
updateOneChecklist: allow,
deleteOneChecklist: allow,
insertOneChecklist: allow,
upsertOneChecklist: allow,
insertOneChecklist: allow, // TODO: anonymous users can create checklists, this may break with the Next Auth implementation
deleteOneChecklist: or(isAdmin, isChecklistsOwner()),
upsertOneChecklist: or(isAdmin, isChecklistsOwner()),
},
}

47 changes: 0 additions & 47 deletions site/gatsby-site/server/generated/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,20 +369,6 @@ export type ChecklistRiskPrecedent = {
title?: Maybe<Scalars['String']['output']>;
};

export type ChecklistSetType = {
_id?: InputMaybe<Scalars['ObjectId']['input']>;
about?: InputMaybe<Scalars['String']['input']>;
date_created?: InputMaybe<Scalars['DateTime']['input']>;
date_updated?: InputMaybe<Scalars['DateTime']['input']>;
id?: InputMaybe<Scalars['String']['input']>;
name?: InputMaybe<Scalars['String']['input']>;
owner_id?: InputMaybe<Scalars['String']['input']>;
risks?: InputMaybe<Array<InputMaybe<RisksSetListObjectType>>>;
tags_goals?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>>;
tags_methods?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>>;
tags_other?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>>;
};

export enum ChecklistSortByInput {
AboutAsc = 'ABOUT_ASC',
AboutDesc = 'ABOUT_DESC',
Expand Down Expand Up @@ -412,10 +398,6 @@ export type ChecklistSortType = {
owner_id?: InputMaybe<SortType>;
};

export type ChecklistUpdateType = {
set?: InputMaybe<ChecklistSetType>;
};

export type Classification = {
__typename?: 'Classification';
_id?: Maybe<Scalars['ObjectId']['output']>;
Expand Down Expand Up @@ -1915,7 +1897,6 @@ export type Mutation = {
updateManyNotifications?: Maybe<UpdateManyPayload>;
updateManyQuickadds?: Maybe<UpdateManyPayload>;
updateOneCandidate?: Maybe<Candidate>;
updateOneChecklist?: Maybe<Checklist>;
updateOneDuplicate?: Maybe<Duplicate>;
updateOneEntity?: Maybe<Entity>;
updateOneIncident?: Maybe<Incident>;
Expand Down Expand Up @@ -2166,12 +2147,6 @@ export type MutationUpdateOneCandidateArgs = {
};


export type MutationUpdateOneChecklistArgs = {
filter: ChecklistFilterType;
update: ChecklistUpdateType;
};


export type MutationUpdateOneDuplicateArgs = {
filter: DuplicateFilterType;
update: DuplicateUpdateType;
Expand Down Expand Up @@ -2507,14 +2482,6 @@ export type PrecedentsObjectFilterType = {
title?: InputMaybe<StringFilter>;
};

export type PrecedentsSetListObjectType = {
description?: InputMaybe<Scalars['String']['input']>;
id?: InputMaybe<Scalars['String']['input']>;
incident_id?: InputMaybe<Scalars['Int']['input']>;
tags?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>>;
title?: InputMaybe<Scalars['String']['input']>;
};

export type PromoteSubmissionToReportInput = {
incident_ids: Array<InputMaybe<Scalars['Int']['input']>>;
is_incident_report?: InputMaybe<Scalars['Boolean']['input']>;
Expand Down Expand Up @@ -3220,20 +3187,6 @@ export type RisksPayloadPrecedentTsne = {
y?: Maybe<Scalars['Float']['output']>;
};

export type RisksSetListObjectType = {
generated?: InputMaybe<Scalars['Boolean']['input']>;
id?: InputMaybe<Scalars['String']['input']>;
likelihood?: InputMaybe<Scalars['String']['input']>;
precedents?: InputMaybe<Array<InputMaybe<PrecedentsSetListObjectType>>>;
risk_notes?: InputMaybe<Scalars['String']['input']>;
risk_status?: InputMaybe<Scalars['String']['input']>;
severity?: InputMaybe<Scalars['String']['input']>;
tag?: InputMaybe<Scalars['String']['input']>;
tags?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>>;
title?: InputMaybe<Scalars['String']['input']>;
touched?: InputMaybe<Scalars['Boolean']['input']>;
};

export enum SortType {
Asc = 'ASC',
Desc = 'DESC'
Expand Down
6 changes: 4 additions & 2 deletions site/gatsby-site/server/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MongoClient } from 'mongodb';
import { Classification, Duplicate, Entity, Incident, Report, Submission, Subscription, User, Notification, History_Report, History_Incident } from './generated/graphql';
import { Classification, Duplicate, Entity, Incident, Report, Submission, Subscription, User, Notification, History_Report, History_Incident, Checklist } from './generated/graphql';
import { IncomingMessage } from 'http';

export interface Context {
Expand All @@ -17,7 +17,7 @@ export type DBIncident = Omit<Incident, 'AllegedDeployerOfAISystem' | 'AllegedDe
& { editors: string[] }

export type DBIncidentHistory = Omit<History_Incident, '__typename' | 'AllegedDeployerOfAISystem' | 'AllegedDeveloperOfAISystem' | 'AllegedHarmedOrNearlyHarmedParties' | 'implicated_systems'>
& { "Alleged deployer of AI system": string[], "Alleged developer of AI system": string[], "Alleged harmed or nearly harmed parties": string[], implicated_systems: string[] };
& { "Alleged deployer of AI system": string[], "Alleged developer of AI system": string[], "Alleged harmed or nearly harmed parties": string[], implicated_systems: string[] };

export type DBEntity = Entity;

Expand Down Expand Up @@ -51,3 +51,5 @@ export type DBSubscription = Omit<Subscription, 'entityId' | 'incident_id' | 'us
export type NotificationTypes = 'new-report-incident' | 'incident-updated' | 'entity' | 'new-incidents' | 'submission-promoted'

export type DBNotification = Omit<Notification, 'userId'> & { userId?: string, type: NotificationTypes }

export type DBChecklist = Checklist;
26 changes: 25 additions & 1 deletion site/gatsby-site/server/rules.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { rule } from "graphql-shield";
import { Context, DBSubscription, DBUser } from "./interfaces";
import { Context, DBChecklist, DBSubscription, DBUser } from "./interfaces";
import { getMongoDbFilter } from "graphql-to-mongodb";
import { SubscriptionType } from "./types/subscription";
import { getSimplifiedType } from "./utils";
import { GraphQLFilter } from "graphql-to-mongodb/lib/src/mongoDbFilter";
import { UserType } from "./types/user";
import config, { Config } from "./config";
import { ChecklistType } from "./types/checklist";

export const isRole = (role: string) => rule()(
async (parent, args, context: Context, info) => {
Expand Down Expand Up @@ -115,3 +116,26 @@ export const notQueriesAdminData = () => rule()(
)

export const isAdmin = isRole('admin');

export const isSubscriber = isRole('subscriber');

export const isChecklistsOwner = () => rule()(
async (parent, args, context: Context, info) => {

const collection = context.client.db('aiidprod').collection('checklists');
const simpleType = getSimplifiedType(ChecklistType);
const filter = getMongoDbFilter(simpleType, args.filter as GraphQLFilter);
const checklists = await collection.find<DBChecklist>(filter).toArray();

const { user } = context;

const meetsOwnership = checklists.every(c => c.owner_id === user?.id);

if (!meetsOwnership) {

return new Error('not authorized');
}

return true;
},
)
48 changes: 40 additions & 8 deletions site/gatsby-site/server/tests/fixtures/checklists.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ObjectId } from 'bson';
import { Fixture } from "../utils";
import { Checklist, ChecklistInsertType, ChecklistUpdateType } from "../../generated/graphql";
import { Checklist, ChecklistInsertType } from "../../generated/graphql";

const checklist1 = {
_id: new ObjectId("6537e59e9208f3f75b2db1f7"),
owner_id: "63601cdc29e6840df23ad3e5",
owner_id: "60a7c5b7b4f5b8a6d8f9c7e6",
tags_methods: ["GMF:Known AI Technology:Language Modeling"],
tags_goals: ["GMF:Known AI Goal:Chatbot"],
about: "",
Expand Down Expand Up @@ -50,7 +50,7 @@ const checklist2 = {
}
],
tags_other: ["CSETv1:Entertainment Industry:yes"],
id: "849bd303-261f-4abe-8746-77dad5841dbe",
id: "849bd303-261f-4abe-8746-77dad5841daa",
name: "Test Checklist 2"
}

Expand All @@ -59,7 +59,7 @@ const subscriber = {
first_name: 'Subscriber',
last_name: 'One',
roles: ['subscriber'],
userId: 'subscriber1',
userId: '60a7c5b7b4f5b8a6d8f9c7e6',
}

const admin = {
Expand All @@ -78,7 +78,7 @@ const anonymous = {
userId: 'anon',
}

const fixture: Fixture<Checklist, ChecklistUpdateType, ChecklistInsertType> = {
const fixture: Fixture<Checklist, any, ChecklistInsertType> = {
name: 'checklists',
query: `
_id
Expand Down Expand Up @@ -153,11 +153,43 @@ const fixture: Fixture<Checklist, ChecklistUpdateType, ChecklistInsertType> = {
},
testUpdateOne: null,
testUpdateMany: null,
testInsertOne: null,
testInsertOne: {
allowed: [subscriber, admin, anonymous],
denied: [],
insert: {
about: "Test Insert",
},
result: {
_id: expect.any(String),
about: "Test Insert",
}
},
testInsertMany: null,
testDeleteOne: null,
testDeleteOne: {
allowed: [admin, subscriber],
denied: [anonymous],
filter: { _id: { EQ: new ObjectId("6537e59e9208f3f75b2db1f7") } },
result: {
_id: "6537e59e9208f3f75b2db1f7",
}
},
testDeleteMany: null,
testUpsertOne: null,
testUpsertOne: {
shouldUpdate: {
allowed: [admin, subscriber],
denied: [anonymous],
filter: { id: { EQ: "849bd303-261f-4abe-8746-77dad5841dbe" } },
update: { name: 'Updated name' },
result: { name: 'Updated name', _id: '6537e59e9208f3f75b2db1f7' }
},
shouldInsert: {
allowed: [subscriber, admin, anonymous],
denied: [],
filter: { id: { EQ: "test" } },
update: { name: 'New checklist', id: "test" },
result: { name: 'New checklist', id: "test", _id: expect.any(String) }
},
},
}

export default fixture;
4 changes: 3 additions & 1 deletion site/gatsby-site/server/tests/mutation-fields.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import submissionsFixture from './fixtures/submissions';
import classificationsFixture from './fixtures/classifications';
import subscriptionsFixture from './fixtures/subscriptions';
import duplicatesFixture from './fixtures/duplicates';
import checklistsFixture from './fixtures/checklists';

const fixtures = [
quickaddsFixture,
Expand All @@ -23,8 +24,9 @@ const fixtures = [
usersFixture,
submissionsFixture,
classificationsFixture,
subscriptionsFixture,
subscriptionsFixture,
duplicatesFixture,
checklistsFixture,
]

fixtures.forEach((collection) => {
Expand Down

0 comments on commit ba3b46e

Please sign in to comment.