Skip to content

Commit

Permalink
supporting both legacy and new groups
Browse files Browse the repository at this point in the history
  • Loading branch information
Ptroger committed Nov 6, 2024
1 parent a4bef0e commit b6906ea
Show file tree
Hide file tree
Showing 15 changed files with 817 additions and 79 deletions.
14 changes: 12 additions & 2 deletions apps/policy-engine/src/engine/core/service/data-store.service.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { LoggerService } from '@narval/nestjs-shared'
import {
DataStore,
DataStoreConfiguration,
Expand All @@ -20,7 +21,10 @@ import { DataStoreRepositoryFactory } from '../factory/data-store-repository.fac

@Injectable()
export class DataStoreService {
constructor(private dataStoreRepositoryFactory: DataStoreRepositoryFactory) {}
constructor(
private dataStoreRepositoryFactory: DataStoreRepositoryFactory,
private logger: LoggerService
) {}

async fetch(store: DataStore): Promise<{
entity: EntityStore
Expand Down Expand Up @@ -53,6 +57,13 @@ export class DataStoreService {
})
}

if (validation.issues) {
this.logger.warn('Entity data validation warnings', {
urlConfig: store.data,
errors: validation.issues
})
}

const signatureVerification = await this.verifySignature({
data: entityData.entity.data,
signature: entitySignature.entity.signature,
Expand All @@ -68,7 +79,6 @@ export class DataStoreService {

throw signatureVerification.error
}

throw new DataStoreException({
message: 'Invalid entity domain invariant',
suggestedHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import {
SerializedTransactionRequest,
SerializedUserOperationV6,
accountEntitySchema,
accountGroupEntitySchema,
addressBookAccountEntitySchema,
groupEntitySchema,
tokenEntitySchema,
userEntitySchema
userEntitySchema,
userGroupEntitySchema
} from '@narval/policy-engine-shared'
import { Intent } from '@narval/transaction-request-intent'
import { loadPolicy } from '@open-policy-agent/opa-wasm'
Expand Down Expand Up @@ -38,12 +40,24 @@ export type Input = {
// many Rego rules performing a look up on the dataset.
const Id = z.string().toLowerCase()

export const UserGroup = userGroupEntitySchema.extend({
id: Id,
users: z.array(Id)
})
export type UserGroup = z.infer<typeof UserGroup>

export const Account = accountEntitySchema.extend({
id: Id,
assignees: z.array(Id)
})
export type Account = z.infer<typeof Account>

export const AccountGroup = accountGroupEntitySchema.extend({
id: Id,
accounts: z.array(Id)
})
export type AccountGroup = z.infer<typeof AccountGroup>

export const Group = groupEntitySchema.extend({
id: Id,
users: z.array(Id),
Expand All @@ -56,6 +70,8 @@ export const Data = z.object({
addressBook: z.record(Id, addressBookAccountEntitySchema.extend({ id: Id })),
tokens: z.record(Id, tokenEntitySchema.extend({ id: Id })),
users: z.record(Id, userEntitySchema.extend({ id: Id })),
accountGroups: z.record(Id, AccountGroup),
userGroups: z.record(Id, UserGroup),
groups: z.record(Id, Group),
accounts: z.record(Id, Account)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,5 +360,39 @@ describe('toData', () => {
)
})
})

it('indexes legacy groups with members by lower case id', () => {
const { entities } = toData({
...FIXTURE.ENTITIES,
userGroupMembers: [
...FIXTURE.ENTITIES.userGroupMembers!,
{ userId: 'test-legacy-alice', groupId: 'test-legacy-user-group' }
],
accountGroupMembers: [
...FIXTURE.ENTITIES.accountGroupMembers!,
{ accountId: 'test-legacy-account', groupId: 'test-legacy-account-group' }
]
})

expect(entities.userGroups['test-legacy-user-group']).toEqual({
id: 'test-legacy-user-group',
users: ['test-legacy-alice']
})
expect(entities.accountGroups['test-legacy-account-group']).toEqual({
id: 'test-legacy-account-group',
accounts: ['test-legacy-account']
})
const group = FIXTURE.GROUP.Engineering

expect(entities.groups[group.id.toLowerCase()]).toEqual({
id: group.id.toLowerCase(),
users: FIXTURE.USER_GROUP_MEMBER.filter(({ groupId }) => groupId === group.id).map(({ userId }) =>
userId.toLowerCase()
),
accounts: FIXTURE.ACCOUNT_GROUP_MEMBER.filter(({ groupId }) => groupId === group.id).map(({ accountId }) =>
accountId.toLowerCase()
)
})
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { InputType, safeDecode } from '@narval/transaction-request-intent'
import { HttpStatus } from '@nestjs/common'
import { indexBy } from 'lodash/fp'
import { OpenPolicyAgentException } from '../exception/open-policy-agent.exception'
import { Account, Data, Group, Input } from '../type/open-policy-agent.type'
import { Account, AccountGroup, Data, Group, Input, UserGroup } from '../type/open-policy-agent.type'

type Mapping<R extends Request> = (
request: R,
Expand Down Expand Up @@ -192,33 +192,19 @@ export const toInput = (params: {
}

export const toData = (entities: Entities): Data => {
const groups = new Map<string, Group>()

// Process user group members
entities.userGroupMembers.forEach(({ userId, groupId }) => {
const userGroups = entities.userGroupMembers.reduce((groups, { userId, groupId }) => {
const id = groupId.toLowerCase()
const group = groups.get(id) || {
id: groupId,
users: [],
accounts: []
}

group.users.push(userId)
groups.set(id, group)
})
const group = groups.get(id)

// Process account group members
entities.accountGroupMembers.forEach(({ accountId, groupId }) => {
const id = groupId.toLowerCase()
const group = groups.get(id) || {
id: groupId,
users: [],
accounts: []
if (group) {
return groups.set(id, {
id: groupId,
users: group.users.concat(userId)
})
} else {
return groups.set(groupId, { id: groupId, users: [userId] })
}

group.accounts.push(accountId)
groups.set(id, group)
})
}, new Map<string, UserGroup>())

const accountAssignees = entities.userAccounts.reduce((assignees, { userId, accountId }) => {
const account = assignees.get(accountId)
Expand All @@ -235,13 +221,36 @@ export const toData = (entities: Entities): Data => {
assignees: accountAssignees.get(account.id) || []
}))

const accountGroups = entities.accountGroupMembers.reduce((groups, { accountId, groupId }) => {
const group = groups.get(groupId)

if (group) {
return groups.set(groupId, {
id: groupId,
accounts: group.accounts.concat(accountId)
})
} else {
return groups.set(groupId, { id: groupId, accounts: [accountId] })
}
}, new Map<string, AccountGroup>())

const groups = (entities.groups || []).reduce((groups, { id }) => {
const users = userGroups.get(id)?.users || []
const accounts = accountGroups.get(id)?.accounts || []
groups.set(id, { id, users, accounts })

return groups
}, new Map<string, Group>())

const data: Data = {
entities: {
addressBook: indexBy('id', entities.addressBook),
tokens: indexBy('id', entities.tokens),
users: indexBy('id', entities.users),
groups: Object.fromEntries(groups),
accounts: indexBy('id', accounts)
groups: indexBy('id', Object.fromEntries(groups)),
userGroups: Object.fromEntries(userGroups),
accounts: indexBy('id', accounts),
accountGroups: Object.fromEntries(accountGroups)
}
}

Expand Down
Loading

0 comments on commit b6906ea

Please sign in to comment.