Skip to content

Commit

Permalink
SDK updates for e2e scenario tests
Browse files Browse the repository at this point in the history

Co-authored-by: Matt Schoch <matt@narval.xyz>
  • Loading branch information
Ptroger and mattschoch authored Aug 26, 2024
1 parent 775f072 commit 72499ac
Show file tree
Hide file tree
Showing 31 changed files with 1,900 additions and 185 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ jobs:
npx nx affected --target test:e2e \
--exclude tag:type:application \
--base=origin/main \
--testPathIgnorePatterns=packages/armory-sdk/src/lib/__test__/e2e/user-journeys.spec.ts
--testPathIgnorePatterns=packages/armory-sdk/src/lib/__test__/e2e/*
- name: Send Slack notification on failure
if: failure() && github.ref == 'refs/heads/main'
Expand Down
2 changes: 1 addition & 1 deletion apps/armory/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ ARMORY_DATABASE_SCHEMA := ${ARMORY_PROJECT_DIR}/src/shared/module/persistence/sc
# === Start ===

armory/start/dev:
npx nx serve ${ARMORY_PROJECT_NAME}
npx nx serve ${ARMORY_PROJECT_NAME} -- --port 9230

# === Setup ===

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,13 @@ export class HistoricalTransferFeedService implements DataFeed<HistoricalTransfe
}

static build(transfers: Transfer[]): HistoricalTransfer[] {
return transfers.map((transfer) => ({
...omit('clientId', transfer),
amount: transfer.amount.toString(),
timestamp: transfer.createdAt.getTime(),
rates: buildHistoricalTranferRates(transfer.rates)
}))
return transfers.map((transfer) => {
return {
...omit('clientId', transfer),
amount: transfer.amount.toString(),
timestamp: transfer.createdAt.getTime(),
rates: buildHistoricalTranferRates(transfer.rates)
}
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
AuthorizationRequestStatus,
Decision,
EvaluationResponse,
FIXTURE,
SignTransaction,
getChainAccountId
} from '@narval/policy-engine-shared'
Expand Down Expand Up @@ -124,7 +125,8 @@ describe(AuthorizationRequestService.name, () => {

expect(authzRequestRepositoryMock.update).toHaveBeenCalledWith({
id: authzRequest.id,
approvals: [jwt]
approvals: [jwt],
status: AuthorizationRequestStatus.APPROVING
})
expect(service.evaluate).toHaveBeenCalledWith(updatedAuthzRequest)
})
Expand All @@ -137,6 +139,7 @@ describe(AuthorizationRequestService.name, () => {
accessToken: {
value: jwt
},
principal: FIXTURE.CREDENTIAL.Bob,
transactionRequestIntent: {
type: Intents.TRANSFER_NATIVE,
amount: '1000000000000000000',
Expand Down Expand Up @@ -224,7 +227,7 @@ describe(AuthorizationRequestService.name, () => {
chainId: request.transactionRequest.chainId,
clientId: authzRequest.clientId,
requestId: authzRequest.id,
initiatedBy: authzRequest.authentication, // TODO: this will change when the underlying data is corrected.
initiatedBy: FIXTURE.CREDENTIAL.Bob.userId,
rates: {
'fiat:usd': 0.99
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,17 @@ export class AuthorizationRequestService {
try {
const authzRequest = await this.authzRequestRepository.update({
id: requestId,
approvals: [sig]
approvals: [sig],
status: AuthorizationRequestStatus.APPROVING
})

await this.evaluate(authzRequest)
} catch (error) {
this.logger.error('Error approving authorization request', {
requestId,
sig,
error
})
await this.authzRequestApprovalRepository.updateMany({
requestId,
sig,
Expand Down Expand Up @@ -137,25 +143,9 @@ export class AuthorizationRequestService {
})

const status = getStatus(evaluation.decision)

const authzRequest = await this.authzRequestRepository.update({
id: input.id,
clientId: input.clientId,
status,
evaluations: [
{
id: uuid(),
decision: evaluation.decision,
signature: evaluation.accessToken?.value || null,
approvalRequirements: evaluation.approvals,
transactionRequestIntent: evaluation.transactionRequestIntent,
createdAt: new Date()
}
]
})

// NOTE: we will track the transfer before we update the status to PERMITTED so that we don't have a brief window where a second transfer can come in before the history is tracked.
// TODO: (@wcalderipe, 01/02/24) Move to the TransferTrackingService.
if (authzRequest.request.action === Action.SIGN_TRANSACTION && status === AuthorizationRequestStatus.PERMITTED) {
if (input.request.action === Action.SIGN_TRANSACTION && status === AuthorizationRequestStatus.PERMITTED) {
// TODO: (@wcalderipe, 08/02/24) Remove the cast `as Intent`.
const intent = evaluation.transactionRequestIntent as Intent

Expand All @@ -165,17 +155,26 @@ export class AuthorizationRequestService {
to: [FIAT_ID_USD]
})

// This should never happen, a successful permit always has a principal, so this is just a fail-safe check.
if (!evaluation.principal?.userId) {
throw new ApplicationException({
message: 'Principal userId not found',
context: {
evaluation
},
suggestedHttpStatusCode: HttpStatus.BAD_REQUEST
})
}

const transfer = {
resourceId: authzRequest.request.resourceId,
clientId: authzRequest.clientId,
requestId: authzRequest.id,
resourceId: input.request.resourceId,
clientId: input.clientId,
requestId: input.id,
from: intent.from,
to: intent.to,
token: intent.token,
chainId: authzRequest.request.transactionRequest.chainId,
// TODO: (@mattschoch) Get real initiator? -- this used to reference publicKey but
// should actually pull data out of a decoded JWT
initiatedBy: authzRequest.authentication,
chainId: input.request.transactionRequest.chainId,
initiatedBy: evaluation.principal?.userId,
createdAt: new Date(),
amount: BigInt(intent.amount),
rates: transferPrices[intent.token] || {}
Expand All @@ -185,6 +184,22 @@ export class AuthorizationRequestService {
}
}

const authzRequest = await this.authzRequestRepository.update({
id: input.id,
clientId: input.clientId,
status,
evaluations: [
{
id: uuid(),
decision: evaluation.decision,
signature: evaluation.accessToken?.value || null,
approvalRequirements: evaluation.approvals,
transactionRequestIntent: evaluation.transactionRequestIntent,
createdAt: new Date()
}
]
})

this.logger.log('Authorization request status updated', {
clientId: authzRequest.clientId,
id: authzRequest.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ApiClientIdGuard } from '../../../../shared/decorator/api-client-id-gua
import { ClientId } from '../../../../shared/decorator/client-id.decorator'
import { ErrorResponseDto } from '../../../../shared/dto/error-response.dto'
import { AuthorizationRequestService } from '../../../core/service/authorization-request.service'
import { AuthorizationRequestDto } from '../../../http/rest/dto/authorization-request.dto'
import { ApprovalDto, AuthorizationRequestDto } from '../../../http/rest/dto/authorization-request.dto'
import { AuthorizationResponseDto } from '../../../http/rest/dto/authorization-response.dto'
import { toCreateAuthorizationRequest } from '../../../http/rest/util'

Expand Down Expand Up @@ -70,9 +70,8 @@ export class AuthorizationRequestController {
status: HttpStatus.CREATED,
type: AuthorizationResponseDto
})
async approve(@Param('id') id: string, @Body() body: string): Promise<AuthorizationResponseDto> {
const authzRequest = await this.authorizationRequestService.approve(id, body)

async approve(@Param('id') id: string, @Body() body: ApprovalDto): Promise<AuthorizationResponseDto> {
const authzRequest = await this.authorizationRequestService.approve(id, body.signature)
return AuthorizationResponseDto.create(authzRequest)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AuthorizationRequest, SerializedAuthorizationRequest } from '@narval/policy-engine-shared'
import { AuthorizationRequest, JwtString, SerializedAuthorizationRequest } from '@narval/policy-engine-shared'
import { createZodDto } from 'nestjs-zod'
import { z } from 'zod'

export class AuthorizationRequestDto extends createZodDto(
SerializedAuthorizationRequest.pick({
Expand All @@ -10,3 +11,9 @@ export class AuthorizationRequestDto extends createZodDto(
approvals: AuthorizationRequest.shape.approvals.optional()
})
) {}

export class ApprovalDto extends createZodDto(
z.object({
signature: JwtString
})
) {}
Loading

0 comments on commit 72499ac

Please sign in to comment.