forked from MergeFi/backend
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathescrow.controller.spec.ts
More file actions
113 lines (100 loc) · 3.51 KB
/
Copy pathescrow.controller.spec.ts
File metadata and controls
113 lines (100 loc) · 3.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import { Test, TestingModule } from '@nestjs/testing';
import { Reflector } from '@nestjs/core';
import { getRepositoryToken } from '@nestjs/typeorm';
import { EscrowController } from './escrow.controller';
import { EscrowService } from './escrow.service';
import { AssetType, EscrowStatus } from '../common/enums';
import { Escrow } from '../common/entities';
import { IdempotencyKey } from '../common/entities/idempotency-key.entity';
import { IdempotencyInterceptor } from '../common/idempotency/idempotency.interceptor';
function makeEscrowWithLeakyMetadata(): Escrow {
return {
id: 'esc_1',
bounty: null,
bountyId: 'bounty_1',
milestone: null,
milestoneId: null,
maintenancePool: null,
maintenancePoolId: null,
sponsorId: 'sponsor_1',
contractId: null,
amount: '100.0000000',
asset: AssetType.USDC,
status: EscrowStatus.FAILED,
fundedByAddress: 'GFUNDER',
fundTxHash: null,
releaseTxHash: null,
refundTxHash: null,
metadata: {
error:
'Soroban simulation failed: internal RPC detail that must never reach a client',
},
payments: [],
lockedAt: null,
releasedAt: null,
refundedAt: null,
createdAt: new Date(),
updatedAt: new Date(),
};
}
describe('EscrowController (#19 metadata leak)', () => {
let controller: EscrowController;
let escrowService: {
fund: jest.Mock;
findOne: jest.Mock;
release: jest.Mock;
refund: jest.Mock;
splitRelease: jest.Mock;
};
beforeEach(async () => {
escrowService = {
fund: jest.fn().mockResolvedValue(makeEscrowWithLeakyMetadata()),
findOne: jest.fn().mockResolvedValue(makeEscrowWithLeakyMetadata()),
release: jest.fn().mockResolvedValue(makeEscrowWithLeakyMetadata()),
refund: jest.fn().mockResolvedValue(makeEscrowWithLeakyMetadata()),
splitRelease: jest.fn().mockResolvedValue([]),
};
const module: TestingModule = await Test.createTestingModule({
controllers: [EscrowController],
providers: [
{ provide: EscrowService, useValue: escrowService },
// These endpoints carry @Idempotent, which resolves
// IdempotencyInterceptor via DI even though this suite calls
// controller methods directly and never runs the interceptor
// itself (#16).
IdempotencyInterceptor,
Reflector,
{
provide: getRepositoryToken(IdempotencyKey),
useValue: {},
},
],
}).compile();
controller = module.get(EscrowController);
});
it('fund() never returns metadata to the client', async () => {
const result = await controller.fund({
amount: '100',
asset: AssetType.USDC,
funderAddress: 'GFUNDER',
bountyId: 'bounty_1',
});
expect(result).not.toHaveProperty('metadata');
expect(JSON.stringify(result)).not.toContain('internal RPC detail');
});
it('findOne() (GET /escrow/:id) never returns metadata to the client', async () => {
const result = await controller.findOne('esc_1');
expect(result).not.toHaveProperty('metadata');
expect(JSON.stringify(result)).not.toContain('internal RPC detail');
});
it('release() never returns metadata to the client', async () => {
const result = await controller.release('esc_1', {
recipientAddress: 'GRECIPIENT',
});
expect(result).not.toHaveProperty('metadata');
});
it('refund() never returns metadata to the client', async () => {
const result = await controller.refund('esc_1');
expect(result).not.toHaveProperty('metadata');
});
});