diff --git a/packages/backend/src/accounting/psql/balance.test.ts b/packages/backend/src/accounting/psql/balance.test.ts
index 027c6f1eff..46a5c9df89 100644
--- a/packages/backend/src/accounting/psql/balance.test.ts
+++ b/packages/backend/src/accounting/psql/balance.test.ts
@@ -39,7 +39,7 @@ describe('Balances', (): void => {
afterEach(async (): Promise => {
jest.useRealTimers()
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/accounting/psql/ledger-account/index.test.ts b/packages/backend/src/accounting/psql/ledger-account/index.test.ts
index fdb9a898c2..483203ed44 100644
--- a/packages/backend/src/accounting/psql/ledger-account/index.test.ts
+++ b/packages/backend/src/accounting/psql/ledger-account/index.test.ts
@@ -13,15 +13,18 @@ import { ForeignKeyViolationError } from 'objection'
import { createLedgerAccount } from '../../../tests/ledgerAccount'
import { ServiceDependencies } from '../service'
import { createAccount, getLiquidityAccount } from '.'
+import { AppServices } from '../../../app'
+import { IocContract } from '@adonisjs/fold'
describe('Ledger Account', (): void => {
+ let deps: IocContract
let serviceDeps: ServiceDependencies
let appContainer: TestContainer
let knex: Knex
let asset: Asset
beforeAll(async (): Promise => {
- const deps = initIocContainer({ ...Config, useTigerBeetle: false })
+ deps = initIocContainer({ ...Config, useTigerBeetle: false })
appContainer = await createTestApp(deps)
serviceDeps = {
logger: await deps.use('logger'),
@@ -40,7 +43,7 @@ describe('Ledger Account', (): void => {
afterEach(async (): Promise => {
jest.useRealTimers()
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/accounting/psql/ledger-transfer/index.test.ts b/packages/backend/src/accounting/psql/ledger-transfer/index.test.ts
index 3efb12f752..0a6e9ea452 100644
--- a/packages/backend/src/accounting/psql/ledger-transfer/index.test.ts
+++ b/packages/backend/src/accounting/psql/ledger-transfer/index.test.ts
@@ -22,15 +22,18 @@ import {
} from '.'
import { ServiceDependencies } from '../service'
import { TransferError } from '../../errors'
+import { AppServices } from '../../../app'
+import { IocContract } from '@adonisjs/fold'
describe('Ledger Transfer', (): void => {
+ let deps: IocContract
let serviceDeps: ServiceDependencies
let appContainer: TestContainer
let knex: Knex
let asset: Asset
beforeAll(async (): Promise => {
- const deps = initIocContainer({ ...Config, useTigerBeetle: false })
+ deps = initIocContainer({ ...Config, useTigerBeetle: false })
appContainer = await createTestApp(deps)
serviceDeps = {
logger: await deps.use('logger'),
@@ -65,7 +68,7 @@ describe('Ledger Transfer', (): void => {
afterEach(async (): Promise => {
jest.useRealTimers()
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/accounting/psql/ledger-transfer/model.test.ts b/packages/backend/src/accounting/psql/ledger-transfer/model.test.ts
index aea03c66f5..9b1853b26e 100644
--- a/packages/backend/src/accounting/psql/ledger-transfer/model.test.ts
+++ b/packages/backend/src/accounting/psql/ledger-transfer/model.test.ts
@@ -47,7 +47,7 @@ describe('Ledger Transfer Model', (): void => {
afterEach(async (): Promise => {
jest.useRealTimers()
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/accounting/psql/service.test.ts b/packages/backend/src/accounting/psql/service.test.ts
index e799068137..c0f544abe9 100644
--- a/packages/backend/src/accounting/psql/service.test.ts
+++ b/packages/backend/src/accounting/psql/service.test.ts
@@ -62,7 +62,7 @@ describe('Psql Accounting Service', (): void => {
afterEach(async (): Promise => {
jest.useRealTimers()
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/accounting/tigerbeetle/service.test.ts b/packages/backend/src/accounting/tigerbeetle/service.test.ts
index 686f77ea21..de79ce21d3 100644
--- a/packages/backend/src/accounting/tigerbeetle/service.test.ts
+++ b/packages/backend/src/accounting/tigerbeetle/service.test.ts
@@ -57,7 +57,7 @@ describe('TigerBeetle Accounting Service', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/asset/model.test.ts b/packages/backend/src/asset/model.test.ts
index d9464d7844..44d1ac98b7 100644
--- a/packages/backend/src/asset/model.test.ts
+++ b/packages/backend/src/asset/model.test.ts
@@ -25,7 +25,7 @@ describe('Models', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/asset/service.test.ts b/packages/backend/src/asset/service.test.ts
index 5fd3042012..3d8e328f41 100644
--- a/packages/backend/src/asset/service.test.ts
+++ b/packages/backend/src/asset/service.test.ts
@@ -38,7 +38,7 @@ describe('Asset Service', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
@@ -414,7 +414,7 @@ describe('Asset Service using Cache', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/fee/model.test.ts b/packages/backend/src/fee/model.test.ts
index 35c39d4d1b..b4b044354a 100644
--- a/packages/backend/src/fee/model.test.ts
+++ b/packages/backend/src/fee/model.test.ts
@@ -23,7 +23,7 @@ describe('Fee Model', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/fee/service.test.ts b/packages/backend/src/fee/service.test.ts
index e57068f7e3..5e80acde78 100644
--- a/packages/backend/src/fee/service.test.ts
+++ b/packages/backend/src/fee/service.test.ts
@@ -4,7 +4,6 @@ import { TestContainer, createTestApp } from '../tests/app'
import { initIocContainer } from '..'
import { Config } from '../config/app'
import { FeeService } from './service'
-import { Knex } from 'knex'
import { truncateTables } from '../tests/tableManager'
import { createAsset } from '../tests/asset'
import { Asset } from '../asset/model'
@@ -18,14 +17,12 @@ import { Pagination, SortOrder } from '../shared/baseModel'
describe('Fee Service', (): void => {
let deps: IocContract
let appContainer: TestContainer
- let knex: Knex
let feeService: FeeService
let asset: Asset
beforeAll(async (): Promise => {
deps = await initIocContainer(Config)
appContainer = await createTestApp(deps)
- knex = appContainer.knex
feeService = await deps.use('feeService')
})
@@ -34,7 +31,7 @@ describe('Fee Service', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/graphql/middleware/index.test.ts b/packages/backend/src/graphql/middleware/index.test.ts
index 6456b418df..5728a0170c 100644
--- a/packages/backend/src/graphql/middleware/index.test.ts
+++ b/packages/backend/src/graphql/middleware/index.test.ts
@@ -33,7 +33,7 @@ describe('GraphQL Middleware', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/graphql/resolvers/accounting_transfer.psql.test.ts b/packages/backend/src/graphql/resolvers/accounting_transfer.psql.test.ts
index 1ec2f06a61..fea75ff56c 100644
--- a/packages/backend/src/graphql/resolvers/accounting_transfer.psql.test.ts
+++ b/packages/backend/src/graphql/resolvers/accounting_transfer.psql.test.ts
@@ -37,7 +37,7 @@ describe('Accounting Transfer', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/graphql/resolvers/accounting_transfer.tigerbeetle.test.ts b/packages/backend/src/graphql/resolvers/accounting_transfer.tigerbeetle.test.ts
index b6fe08cee7..e35a9d41ac 100644
--- a/packages/backend/src/graphql/resolvers/accounting_transfer.tigerbeetle.test.ts
+++ b/packages/backend/src/graphql/resolvers/accounting_transfer.tigerbeetle.test.ts
@@ -39,7 +39,7 @@ describe('TigerBeetle: Accounting Transfer', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/graphql/resolvers/asset.test.ts b/packages/backend/src/graphql/resolvers/asset.test.ts
index 8ee9e279bd..12b6fdb2af 100644
--- a/packages/backend/src/graphql/resolvers/asset.test.ts
+++ b/packages/backend/src/graphql/resolvers/asset.test.ts
@@ -54,7 +54,7 @@ describe('Asset Resolvers', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/graphql/resolvers/auto-peering.test.ts b/packages/backend/src/graphql/resolvers/auto-peering.test.ts
index 49715fdfe0..0d7862c7db 100644
--- a/packages/backend/src/graphql/resolvers/auto-peering.test.ts
+++ b/packages/backend/src/graphql/resolvers/auto-peering.test.ts
@@ -93,7 +93,7 @@ describe('Auto Peering Resolvers', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/graphql/resolvers/combined_payments.test.ts b/packages/backend/src/graphql/resolvers/combined_payments.test.ts
index 2f3ac34706..8cea2d69c0 100644
--- a/packages/backend/src/graphql/resolvers/combined_payments.test.ts
+++ b/packages/backend/src/graphql/resolvers/combined_payments.test.ts
@@ -34,7 +34,7 @@ describe('Payment', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/graphql/resolvers/fee.test.ts b/packages/backend/src/graphql/resolvers/fee.test.ts
index ee7306f2ef..8eade969c3 100644
--- a/packages/backend/src/graphql/resolvers/fee.test.ts
+++ b/packages/backend/src/graphql/resolvers/fee.test.ts
@@ -31,7 +31,7 @@ describe('Fee Resolvers', () => {
})
afterEach(async () => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async () => {
diff --git a/packages/backend/src/graphql/resolvers/incoming_payment.test.ts b/packages/backend/src/graphql/resolvers/incoming_payment.test.ts
index 77dfc66d96..30cbfa893b 100644
--- a/packages/backend/src/graphql/resolvers/incoming_payment.test.ts
+++ b/packages/backend/src/graphql/resolvers/incoming_payment.test.ts
@@ -50,7 +50,7 @@ describe('Incoming Payment Resolver', (): void => {
})
afterAll(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
await appContainer.apolloClient.stop()
await appContainer.shutdown()
})
diff --git a/packages/backend/src/graphql/resolvers/liquidity.test.ts b/packages/backend/src/graphql/resolvers/liquidity.test.ts
index 457099cb36..5c417e32c1 100644
--- a/packages/backend/src/graphql/resolvers/liquidity.test.ts
+++ b/packages/backend/src/graphql/resolvers/liquidity.test.ts
@@ -60,7 +60,7 @@ describe('Liquidity Resolvers', (): void => {
})
afterAll(async (): Promise => {
- await truncateTables(knex)
+ await truncateTables(deps)
await appContainer.apolloClient.stop()
await appContainer.shutdown()
})
diff --git a/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts b/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts
index a4698992dc..9bf4c88788 100644
--- a/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts
+++ b/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts
@@ -58,7 +58,7 @@ describe('OutgoingPayment Resolvers', (): void => {
afterEach(async (): Promise => {
jest.restoreAllMocks()
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/graphql/resolvers/peer.test.ts b/packages/backend/src/graphql/resolvers/peer.test.ts
index 4aec23a2e8..215169895e 100644
--- a/packages/backend/src/graphql/resolvers/peer.test.ts
+++ b/packages/backend/src/graphql/resolvers/peer.test.ts
@@ -68,7 +68,7 @@ describe('Peer Resolvers', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/graphql/resolvers/quote.test.ts b/packages/backend/src/graphql/resolvers/quote.test.ts
index 246f7ac486..96157ee50d 100644
--- a/packages/backend/src/graphql/resolvers/quote.test.ts
+++ b/packages/backend/src/graphql/resolvers/quote.test.ts
@@ -46,7 +46,7 @@ describe('Quote Resolvers', (): void => {
afterEach(async (): Promise => {
jest.restoreAllMocks()
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/graphql/resolvers/tenant.test.ts b/packages/backend/src/graphql/resolvers/tenant.test.ts
index 177ed85015..99cda31197 100644
--- a/packages/backend/src/graphql/resolvers/tenant.test.ts
+++ b/packages/backend/src/graphql/resolvers/tenant.test.ts
@@ -64,14 +64,15 @@ describe('Tenant Resolvers', (): void => {
let deps: IocContract
let appContainer: TestContainer
let config: IAppConfig
+ const dbSchema = 'tenant_resolver_test_schema'
beforeAll(async (): Promise => {
deps = await initIocContainer({
...Config,
- dbSchema: 'tenant_service_test_schema'
+ dbSchema
})
- appContainer = await createTestApp(deps)
config = await deps.use('config')
+ appContainer = await createTestApp(deps)
const authServiceClient = await deps.use('authServiceClient')
jest
.spyOn(authServiceClient.tenant, 'create')
@@ -85,7 +86,7 @@ describe('Tenant Resolvers', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex, true)
+ await truncateTables(deps, { truncateTenants: true })
})
afterAll(async (): Promise => {
await appContainer.apolloClient.stop()
@@ -346,25 +347,91 @@ describe('Tenant Resolvers', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
- test.each`
- isOperator | description
- ${true} | ${'operator'}
- ${false} | ${'tenant'}
- `(
- 'can update a tenant as $description',
- async ({ isOperator }): Promise => {
- const client = isOperator
- ? appContainer.apolloClient
- : tenantedApolloClient
- const updateInput = {
- ...generateTenantInput(),
- id: tenant.id
- }
+ test('can update a tenant as operator', async (): Promise => {
+ // operator cant update apiSecret
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const { apiSecret, ...input } = generateTenantInput()
+ const updateInput = {
+ ...input,
+ id: tenant.id
+ }
+
+ const mutation = await appContainer.apolloClient
+ .mutate({
+ mutation: gql`
+ mutation UpdateTenant($input: UpdateTenantInput!) {
+ updateTenant(input: $input) {
+ tenant {
+ id
+ email
+ apiSecret
+ idpConsentUrl
+ idpSecret
+ publicName
+ }
+ }
+ }
+ `,
+ variables: {
+ input: updateInput
+ }
+ })
+ .then((query): TenantMutationResponse => query.data?.updateTenant)
+
+ expect(mutation.tenant).toEqual({
+ ...updateInput,
+ __typename: 'Tenant',
+ apiSecret: expect.any(String)
+ })
+ })
+
+ test('can update a tenant as tenant', async (): Promise => {
+ const updateInput = {
+ ...generateTenantInput(),
+ id: tenant.id
+ }
+
+ const mutation = await tenantedApolloClient
+ .mutate({
+ mutation: gql`
+ mutation UpdateTenant($input: UpdateTenantInput!) {
+ updateTenant(input: $input) {
+ tenant {
+ id
+ email
+ apiSecret
+ idpConsentUrl
+ idpSecret
+ publicName
+ }
+ }
+ }
+ `,
+ variables: {
+ input: updateInput
+ }
+ })
+ .then((query): TenantMutationResponse => query.data?.updateTenant)
- const mutation = await client
+ expect(mutation.tenant).toEqual({
+ ...updateInput,
+ __typename: 'Tenant'
+ })
+ })
+
+ test('Cannot update API secret as operator', async (): Promise => {
+ const updateInput = {
+ ...generateTenantInput(),
+ id: tenant.id,
+ apiSecret: 'newApiSecretValue'
+ }
+
+ try {
+ expect.assertions(2)
+ await appContainer.apolloClient
.mutate({
mutation: gql`
mutation UpdateTenant($input: UpdateTenantInput!) {
@@ -385,13 +452,19 @@ describe('Tenant Resolvers', (): void => {
}
})
.then((query): TenantMutationResponse => query.data?.updateTenant)
-
- expect(mutation.tenant).toEqual({
- ...updateInput,
- __typename: 'Tenant'
- })
+ } catch (error) {
+ expect(error).toBeInstanceOf(ApolloError)
+ expect((error as ApolloError).graphQLErrors).toContainEqual(
+ expect.objectContaining({
+ message: 'Operator cannot update apiSecret over admin api',
+ extensions: expect.objectContaining({
+ code: GraphQLErrorCode.BadUserInput
+ })
+ })
+ )
}
- )
+ })
+
test('Cannot update other tenant as non-operator', async (): Promise => {
const firstTenant = await createTenant(deps)
const secondTenant = await createTenant(deps)
diff --git a/packages/backend/src/graphql/resolvers/tenant.ts b/packages/backend/src/graphql/resolvers/tenant.ts
index 6fdddf16da..eae36ebc3a 100644
--- a/packages/backend/src/graphql/resolvers/tenant.ts
+++ b/packages/backend/src/graphql/resolvers/tenant.ts
@@ -122,6 +122,17 @@ export const updateTenant: MutationResolvers['updateTenan
})
}
+ if (isOperator && 'apiSecret' in args.input) {
+ throw new GraphQLError(
+ 'Operator cannot update apiSecret over admin api',
+ {
+ extensions: {
+ code: GraphQLErrorCode.BadUserInput
+ }
+ }
+ )
+ }
+
const tenantService = await ctx.container.use('tenantService')
try {
const updatedTenant = await tenantService.update(args.input)
diff --git a/packages/backend/src/graphql/resolvers/tenant_settings.test.ts b/packages/backend/src/graphql/resolvers/tenant_settings.test.ts
index c4afbd6732..473f1e0795 100644
--- a/packages/backend/src/graphql/resolvers/tenant_settings.test.ts
+++ b/packages/backend/src/graphql/resolvers/tenant_settings.test.ts
@@ -59,11 +59,12 @@ function createTenantedApolloClient(
describe('Tenant Settings Resolvers', (): void => {
let deps: IocContract
let appContainer: TestContainer
+ const dbSchema = 'tenant_settings_resolver_test_schema'
beforeAll(async (): Promise => {
deps = initIocContainer({
...Config,
- dbSchema: 'tenant_settings_service_test_schema'
+ dbSchema
})
appContainer = await createTestApp(deps)
@@ -80,7 +81,7 @@ describe('Tenant Settings Resolvers', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex, true)
+ await truncateTables(deps, { truncateTenants: true })
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/graphql/resolvers/walletAddressKey.test.ts b/packages/backend/src/graphql/resolvers/walletAddressKey.test.ts
index fc4400f9af..9cd736f973 100644
--- a/packages/backend/src/graphql/resolvers/walletAddressKey.test.ts
+++ b/packages/backend/src/graphql/resolvers/walletAddressKey.test.ts
@@ -41,7 +41,7 @@ describe('Wallet Address Key Resolvers', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/graphql/resolvers/wallet_address.test.ts b/packages/backend/src/graphql/resolvers/wallet_address.test.ts
index 88ae1d78d8..045956da46 100644
--- a/packages/backend/src/graphql/resolvers/wallet_address.test.ts
+++ b/packages/backend/src/graphql/resolvers/wallet_address.test.ts
@@ -3,7 +3,11 @@ import { gql, ApolloError } from '@apollo/client'
import { Knex } from 'knex'
import { v4 as uuid } from 'uuid'
-import { createTestApp, TestContainer } from '../../tests/app'
+import {
+ createApolloClient,
+ createTestApp,
+ TestContainer
+} from '../../tests/app'
import { IocContract } from '@adonisjs/fold'
import { AppServices } from '../../app'
import { Asset } from '../../asset/model'
@@ -38,6 +42,7 @@ import { GraphQLErrorCode } from '../errors'
import { AssetService } from '../../asset/service'
import { faker } from '@faker-js/faker'
import { Tenant } from '../../tenants/model'
+import { createTenant } from '../../tests/tenant'
describe('Wallet Address Resolvers', (): void => {
let deps: IocContract
@@ -49,8 +54,7 @@ describe('Wallet Address Resolvers', (): void => {
beforeAll(async (): Promise => {
deps = initIocContainer({
...Config,
- localCacheDuration: 0,
- adminApiSecret: '123' //to force not being an operator.
+ localCacheDuration: 0
})
appContainer = await createTestApp(deps)
knex = appContainer.knex
@@ -59,7 +63,7 @@ describe('Wallet Address Resolvers', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
@@ -315,14 +319,22 @@ describe('Wallet Address Resolvers', (): void => {
})
test('bad input data when not allowed to perform cross tenant create', async (): Promise => {
+ // Make request as non-operator.
+ const nonOperatorTenant = await createTenant(deps)
+ const tenantedApolloClient = await createApolloClient(
+ appContainer.container,
+ appContainer.app,
+ nonOperatorTenant.id
+ )
+
const badInputData = {
- tenantId: 'ae4950b6-3e1b-4e50-ad24-25c065bdd3a9',
+ tenantId: uuid(), // some tenant other than requestor
assetId: input.assetId,
url: input.url
}
try {
expect.assertions(2)
- await appContainer.apolloClient
+ await tenantedApolloClient
.mutate({
mutation: gql`
mutation CreateWalletAddress(
@@ -362,6 +374,69 @@ describe('Wallet Address Resolvers', (): void => {
)
}
})
+
+ test('Operator can perform cross tenant create', async (): Promise => {
+ // Setup non-tenant operator and form request for it from operator
+ const nonOperatorTenant = await createTenant(deps)
+ const asset = await createAsset(
+ deps,
+ {
+ code: 'xyz',
+ scale: 2
+ },
+ nonOperatorTenant.id
+ )
+ const input = {
+ tenantId: nonOperatorTenant.id,
+ assetId: asset.id,
+ url: 'https://bob.me/.well-known/pay'
+ }
+ const response = await appContainer.apolloClient // operator client
+ .mutate({
+ mutation: gql`
+ mutation CreateWalletAddress($input: CreateWalletAddressInput!) {
+ createWalletAddress(input: $input) {
+ walletAddress {
+ id
+ asset {
+ code
+ scale
+ }
+ url
+ }
+ }
+ }
+ `,
+ variables: {
+ input
+ }
+ })
+ .then((query): CreateWalletAddressMutationResponse => {
+ if (query.data) {
+ return query.data.createWalletAddress
+ } else {
+ throw new Error('Data was empty')
+ }
+ })
+
+ assert.ok(response.walletAddress)
+ expect(response.walletAddress).toEqual({
+ __typename: 'WalletAddress',
+ id: response.walletAddress.id,
+ url: input.url,
+ asset: {
+ __typename: 'Asset',
+ code: asset.code,
+ scale: asset.scale
+ }
+ })
+ await expect(
+ walletAddressService.get(response.walletAddress.id)
+ ).resolves.toMatchObject({
+ id: response.walletAddress.id,
+ asset
+ })
+ })
})
describe('Update Wallet Address', (): void => {
diff --git a/packages/backend/src/graphql/resolvers/webhooks.test.ts b/packages/backend/src/graphql/resolvers/webhooks.test.ts
index b5ecda5ccb..9d6afddfca 100644
--- a/packages/backend/src/graphql/resolvers/webhooks.test.ts
+++ b/packages/backend/src/graphql/resolvers/webhooks.test.ts
@@ -20,7 +20,7 @@ describe('Webhook Events Query', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts
index 0dcde43128..922f375c52 100644
--- a/packages/backend/src/index.ts
+++ b/packages/backend/src/index.ts
@@ -236,7 +236,8 @@ export function initIocContainer(
knex: await deps.use('knex'),
tenantCache: await deps.use('tenantCache'),
authServiceClient: deps.use('authServiceClient'),
- tenantSettingService: await deps.use('tenantSettingService')
+ tenantSettingService: await deps.use('tenantSettingService'),
+ config: await deps.use('config')
})
})
@@ -768,6 +769,11 @@ export const start = async (
Model.knex(knex)
+ // Update Operator Tenant from config
+ const tenantService = await container.use('tenantService')
+ const error = await tenantService.updateOperatorApiSecretFromConfig()
+ if (error) throw error
+
await app.boot()
await app.startAdminServer(config.adminPort)
logger.info(`Admin listening on ${app.getAdminPort()}`)
diff --git a/packages/backend/src/open_payments/authServer/service.test.ts b/packages/backend/src/open_payments/authServer/service.test.ts
index 1fd758a204..9b4a4af00a 100644
--- a/packages/backend/src/open_payments/authServer/service.test.ts
+++ b/packages/backend/src/open_payments/authServer/service.test.ts
@@ -24,7 +24,7 @@ describe('Auth Server Service', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/grant/service.test.ts b/packages/backend/src/open_payments/grant/service.test.ts
index eb10c65d71..fe7a0ba84e 100644
--- a/packages/backend/src/open_payments/grant/service.test.ts
+++ b/packages/backend/src/open_payments/grant/service.test.ts
@@ -46,7 +46,7 @@ describe('Grant Service', (): void => {
afterEach(async (): Promise => {
jest.useRealTimers()
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/payment/combined/service.test.ts b/packages/backend/src/open_payments/payment/combined/service.test.ts
index 60251049ec..1f2bf75580 100644
--- a/packages/backend/src/open_payments/payment/combined/service.test.ts
+++ b/packages/backend/src/open_payments/payment/combined/service.test.ts
@@ -4,7 +4,6 @@ import { TestContainer, createTestApp } from '../../../tests/app'
import { initIocContainer } from '../../..'
import { Config } from '../../../config/app'
import { CombinedPaymentService } from './service'
-import { Knex } from 'knex'
import { truncateTables } from '../../../tests/tableManager'
import { getPageTests } from '../../../shared/baseModel.test'
import { createOutgoingPayment } from '../../../tests/outgoingPayment'
@@ -25,7 +24,6 @@ import {
describe('Combined Payment Service', (): void => {
let deps: IocContract
let appContainer: TestContainer
- let knex: Knex
let combinedPaymentService: CombinedPaymentService
let tenantId: string
let sendAsset: Asset
@@ -36,7 +34,6 @@ describe('Combined Payment Service', (): void => {
beforeAll(async (): Promise => {
deps = await initIocContainer(Config)
appContainer = await createTestApp(deps)
- knex = appContainer.knex
combinedPaymentService = await deps.use('combinedPaymentService')
tenantId = Config.operatorTenantId
})
@@ -57,7 +54,7 @@ describe('Combined Payment Service', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/payment/incoming/model.test.ts b/packages/backend/src/open_payments/payment/incoming/model.test.ts
index a71cf23d4b..3f1f91c76e 100644
--- a/packages/backend/src/open_payments/payment/incoming/model.test.ts
+++ b/packages/backend/src/open_payments/payment/incoming/model.test.ts
@@ -29,7 +29,7 @@ describe('Models', (): void => {
afterEach(async (): Promise => {
jest.useRealTimers()
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/payment/incoming/routes.test.ts b/packages/backend/src/open_payments/payment/incoming/routes.test.ts
index 06b0c69193..506aadf3ea 100644
--- a/packages/backend/src/open_payments/payment/incoming/routes.test.ts
+++ b/packages/backend/src/open_payments/payment/incoming/routes.test.ts
@@ -72,7 +72,7 @@ describe('Incoming Payment Routes', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/payment/incoming/service.test.ts b/packages/backend/src/open_payments/payment/incoming/service.test.ts
index afacfd0452..39b436341b 100644
--- a/packages/backend/src/open_payments/payment/incoming/service.test.ts
+++ b/packages/backend/src/open_payments/payment/incoming/service.test.ts
@@ -65,7 +65,7 @@ describe('Incoming Payment Service', (): void => {
afterEach(async (): Promise => {
jest.useRealTimers()
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/payment/incoming_remote/service.test.ts b/packages/backend/src/open_payments/payment/incoming_remote/service.test.ts
index a971c3523a..89d06494eb 100644
--- a/packages/backend/src/open_payments/payment/incoming_remote/service.test.ts
+++ b/packages/backend/src/open_payments/payment/incoming_remote/service.test.ts
@@ -1,4 +1,3 @@
-import { Knex } from 'knex'
import { v4 as uuid } from 'uuid'
import { RemoteIncomingPaymentService } from './service'
import { createTestApp, TestContainer } from '../../../tests/app'
@@ -26,7 +25,6 @@ describe('Remote Incoming Payment Service', (): void => {
let deps: IocContract
let appContainer: TestContainer
let remoteIncomingPaymentService: RemoteIncomingPaymentService
- let knex: Knex
let openPaymentsClient: OpenPaymentsClient
let grantService: GrantService
@@ -35,7 +33,6 @@ describe('Remote Incoming Payment Service', (): void => {
appContainer = await createTestApp(deps)
openPaymentsClient = await deps.use('openPaymentsClient')
grantService = await deps.use('grantService')
- knex = appContainer.knex
remoteIncomingPaymentService = await deps.use(
'remoteIncomingPaymentService'
)
@@ -43,7 +40,7 @@ describe('Remote Incoming Payment Service', (): void => {
afterEach(async (): Promise => {
jest.useRealTimers()
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/payment/outgoing/model.test.ts b/packages/backend/src/open_payments/payment/outgoing/model.test.ts
index f724192d6c..5c3538c13d 100644
--- a/packages/backend/src/open_payments/payment/outgoing/model.test.ts
+++ b/packages/backend/src/open_payments/payment/outgoing/model.test.ts
@@ -23,7 +23,7 @@ describe('Outgoing Payment Event Model', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/payment/outgoing/routes.test.ts b/packages/backend/src/open_payments/payment/outgoing/routes.test.ts
index 98a744f1e3..4f04a3642c 100644
--- a/packages/backend/src/open_payments/payment/outgoing/routes.test.ts
+++ b/packages/backend/src/open_payments/payment/outgoing/routes.test.ts
@@ -88,7 +88,7 @@ describe('Outgoing Payment Routes', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/payment/outgoing/service.test.ts b/packages/backend/src/open_payments/payment/outgoing/service.test.ts
index 05007973d3..4329933f3e 100644
--- a/packages/backend/src/open_payments/payment/outgoing/service.test.ts
+++ b/packages/backend/src/open_payments/payment/outgoing/service.test.ts
@@ -324,7 +324,7 @@ describe('OutgoingPaymentService', (): void => {
afterEach(async (): Promise => {
jest.restoreAllMocks()
receiverWalletAddress.scope?.persist(false)
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/quote/routes.test.ts b/packages/backend/src/open_payments/quote/routes.test.ts
index 3c161305fb..2c480bd45d 100644
--- a/packages/backend/src/open_payments/quote/routes.test.ts
+++ b/packages/backend/src/open_payments/quote/routes.test.ts
@@ -89,7 +89,7 @@ describe('Quote Routes', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/quote/service.test.ts b/packages/backend/src/open_payments/quote/service.test.ts
index ef91ab9568..9ecc0601ba 100644
--- a/packages/backend/src/open_payments/quote/service.test.ts
+++ b/packages/backend/src/open_payments/quote/service.test.ts
@@ -131,7 +131,7 @@ describe('QuoteService', (): void => {
afterEach(async (): Promise => {
jest.restoreAllMocks()
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/receiver/model.test.ts b/packages/backend/src/open_payments/receiver/model.test.ts
index 5ed02b0144..295de1dec9 100644
--- a/packages/backend/src/open_payments/receiver/model.test.ts
+++ b/packages/backend/src/open_payments/receiver/model.test.ts
@@ -29,7 +29,7 @@ describe('Receiver Model', (): void => {
afterEach(async (): Promise => {
jest.useRealTimers()
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/receiver/service.test.ts b/packages/backend/src/open_payments/receiver/service.test.ts
index 2077703d1c..4881e0617f 100644
--- a/packages/backend/src/open_payments/receiver/service.test.ts
+++ b/packages/backend/src/open_payments/receiver/service.test.ts
@@ -72,7 +72,7 @@ describe('Receiver Service', (): void => {
afterEach(async (): Promise => {
jest.restoreAllMocks()
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/wallet_address/key/routes.test.ts b/packages/backend/src/open_payments/wallet_address/key/routes.test.ts
index 0ea2017292..1608b3580f 100644
--- a/packages/backend/src/open_payments/wallet_address/key/routes.test.ts
+++ b/packages/backend/src/open_payments/wallet_address/key/routes.test.ts
@@ -37,7 +37,7 @@ describe('Wallet Address Keys Routes', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/wallet_address/key/service.test.ts b/packages/backend/src/open_payments/wallet_address/key/service.test.ts
index 57363cb649..c9a0970aa6 100644
--- a/packages/backend/src/open_payments/wallet_address/key/service.test.ts
+++ b/packages/backend/src/open_payments/wallet_address/key/service.test.ts
@@ -37,7 +37,7 @@ describe('Wallet Address Key Service', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/wallet_address/middleware.test.ts b/packages/backend/src/open_payments/wallet_address/middleware.test.ts
index 3ae2438ec1..af62847107 100644
--- a/packages/backend/src/open_payments/wallet_address/middleware.test.ts
+++ b/packages/backend/src/open_payments/wallet_address/middleware.test.ts
@@ -53,7 +53,7 @@ describe('Wallet Address Middleware', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/wallet_address/model.test.ts b/packages/backend/src/open_payments/wallet_address/model.test.ts
index 3dd586873d..c46499557b 100644
--- a/packages/backend/src/open_payments/wallet_address/model.test.ts
+++ b/packages/backend/src/open_payments/wallet_address/model.test.ts
@@ -377,7 +377,7 @@ describe('Models', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/wallet_address/routes.test.ts b/packages/backend/src/open_payments/wallet_address/routes.test.ts
index e30d4056fb..87da55b2ec 100644
--- a/packages/backend/src/open_payments/wallet_address/routes.test.ts
+++ b/packages/backend/src/open_payments/wallet_address/routes.test.ts
@@ -34,7 +34,7 @@ describe('Wallet Address Routes', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/open_payments/wallet_address/service.test.ts b/packages/backend/src/open_payments/wallet_address/service.test.ts
index 5d6f139996..1fb01fc48d 100644
--- a/packages/backend/src/open_payments/wallet_address/service.test.ts
+++ b/packages/backend/src/open_payments/wallet_address/service.test.ts
@@ -50,7 +50,7 @@ describe('Open Payments Wallet Address Service', (): void => {
afterEach(async (): Promise => {
jest.useRealTimers()
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
@@ -847,7 +847,7 @@ describe('Open Payments Wallet Address Service using Cache', (): void => {
afterEach(async (): Promise => {
jest.useRealTimers()
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/payment-method/handler/service.test.ts b/packages/backend/src/payment-method/handler/service.test.ts
index 5bcfaf36ea..519904d0d4 100644
--- a/packages/backend/src/payment-method/handler/service.test.ts
+++ b/packages/backend/src/payment-method/handler/service.test.ts
@@ -36,7 +36,7 @@ describe('PaymentMethodHandlerService', (): void => {
afterEach(async (): Promise => {
jest.restoreAllMocks()
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/payment-method/ilp/auto-peering/routes.test.ts b/packages/backend/src/payment-method/ilp/auto-peering/routes.test.ts
index 2a5f16b2a7..8c6a876ca5 100644
--- a/packages/backend/src/payment-method/ilp/auto-peering/routes.test.ts
+++ b/packages/backend/src/payment-method/ilp/auto-peering/routes.test.ts
@@ -23,7 +23,7 @@ describe('Auto Peering Routes', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/payment-method/ilp/auto-peering/service.test.ts b/packages/backend/src/payment-method/ilp/auto-peering/service.test.ts
index af2c2e2282..6e5d14be75 100644
--- a/packages/backend/src/payment-method/ilp/auto-peering/service.test.ts
+++ b/packages/backend/src/payment-method/ilp/auto-peering/service.test.ts
@@ -38,7 +38,7 @@ describe('Auto Peering Service', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/payment-method/ilp/peer-http-token/service.test.ts b/packages/backend/src/payment-method/ilp/peer-http-token/service.test.ts
index d9624fbb0b..1fc6c5675c 100644
--- a/packages/backend/src/payment-method/ilp/peer-http-token/service.test.ts
+++ b/packages/backend/src/payment-method/ilp/peer-http-token/service.test.ts
@@ -28,7 +28,7 @@ describe('HTTP Token Service', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/payment-method/ilp/peer/model.test.ts b/packages/backend/src/payment-method/ilp/peer/model.test.ts
index a664509eb1..355a579fe5 100644
--- a/packages/backend/src/payment-method/ilp/peer/model.test.ts
+++ b/packages/backend/src/payment-method/ilp/peer/model.test.ts
@@ -33,7 +33,7 @@ describe('Models', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/payment-method/ilp/peer/service.test.ts b/packages/backend/src/payment-method/ilp/peer/service.test.ts
index 9d0a7ae430..084cd7de63 100644
--- a/packages/backend/src/payment-method/ilp/peer/service.test.ts
+++ b/packages/backend/src/payment-method/ilp/peer/service.test.ts
@@ -55,7 +55,7 @@ describe('Peer Service', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/payment-method/ilp/service.test.ts b/packages/backend/src/payment-method/ilp/service.test.ts
index 48e59a88c4..29f380ba61 100644
--- a/packages/backend/src/payment-method/ilp/service.test.ts
+++ b/packages/backend/src/payment-method/ilp/service.test.ts
@@ -80,7 +80,7 @@ describe('IlpPaymentService', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
jest.restoreAllMocks()
nock.cleanAll()
diff --git a/packages/backend/src/payment-method/ilp/spsp/middleware.test.ts b/packages/backend/src/payment-method/ilp/spsp/middleware.test.ts
index 896c30dac6..8d24d79e25 100644
--- a/packages/backend/src/payment-method/ilp/spsp/middleware.test.ts
+++ b/packages/backend/src/payment-method/ilp/spsp/middleware.test.ts
@@ -49,7 +49,7 @@ describe('SPSP Middleware', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/payment-method/ilp/spsp/routes.test.ts b/packages/backend/src/payment-method/ilp/spsp/routes.test.ts
index b02c18274c..fdef34c42e 100644
--- a/packages/backend/src/payment-method/ilp/spsp/routes.test.ts
+++ b/packages/backend/src/payment-method/ilp/spsp/routes.test.ts
@@ -41,7 +41,7 @@ describe('SPSP Routes', (): void => {
})
afterAll(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
await appContainer.shutdown()
})
diff --git a/packages/backend/src/payment-method/ilp/stream-credentials/service.test.ts b/packages/backend/src/payment-method/ilp/stream-credentials/service.test.ts
index 3092f76491..1587af57c1 100644
--- a/packages/backend/src/payment-method/ilp/stream-credentials/service.test.ts
+++ b/packages/backend/src/payment-method/ilp/stream-credentials/service.test.ts
@@ -37,7 +37,7 @@ describe('Stream Credentials Service', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/payment-method/local/service.test.ts b/packages/backend/src/payment-method/local/service.test.ts
index ee2afc5d2b..4729d2d973 100644
--- a/packages/backend/src/payment-method/local/service.test.ts
+++ b/packages/backend/src/payment-method/local/service.test.ts
@@ -87,7 +87,7 @@ describe('LocalPaymentService', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
jest.restoreAllMocks()
nock.cleanAll()
diff --git a/packages/backend/src/shared/pagination.test.ts b/packages/backend/src/shared/pagination.test.ts
index 85d3df3e01..1136e50a7a 100644
--- a/packages/backend/src/shared/pagination.test.ts
+++ b/packages/backend/src/shared/pagination.test.ts
@@ -35,7 +35,7 @@ describe('Pagination', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/shared/utils.test.ts b/packages/backend/src/shared/utils.test.ts
index 63b00099ca..6adebe8a04 100644
--- a/packages/backend/src/shared/utils.test.ts
+++ b/packages/backend/src/shared/utils.test.ts
@@ -317,7 +317,7 @@ describe('utils', (): void => {
afterEach(async (): Promise => {
await redis.flushall()
- await truncateTables(appContainer.knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/tenants/errors.ts b/packages/backend/src/tenants/errors.ts
new file mode 100644
index 0000000000..d3ed0ac0b6
--- /dev/null
+++ b/packages/backend/src/tenants/errors.ts
@@ -0,0 +1,13 @@
+export enum TenantError {
+ TenantNotFound = 'TenantNotFound'
+}
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
+export const isTenantError = (o: any): o is TenantError =>
+ Object.values(TenantError).includes(o)
+
+export const errorToMessage: {
+ [key in TenantError]: string
+} = {
+ [TenantError.TenantNotFound]: 'Tenant not found'
+}
diff --git a/packages/backend/src/tenants/service.test.ts b/packages/backend/src/tenants/service.test.ts
index b5c3f01af7..6dcb645737 100644
--- a/packages/backend/src/tenants/service.test.ts
+++ b/packages/backend/src/tenants/service.test.ts
@@ -1,7 +1,6 @@
import assert from 'assert'
import { faker } from '@faker-js/faker'
import { IocContract } from '@adonisjs/fold'
-import nock from 'nock'
import { Knex } from 'knex'
import { AppServices } from '../app'
import { initIocContainer } from '..'
@@ -18,6 +17,7 @@ import { AuthServiceClient } from '../auth-service-client/client'
import { withConfigOverride } from '../tests/helpers'
import { TenantSetting } from './settings/model'
import { TenantSettingService } from './settings/service'
+import { isTenantError, TenantError } from './errors'
describe('Tenant Service', (): void => {
let deps: IocContract
@@ -34,20 +34,19 @@ describe('Tenant Service', (): void => {
...Config,
dbSchema
})
- appContainer = await createTestApp(deps)
- tenantService = await deps.use('tenantService')
knex = await deps.use('knex')
config = await deps.use('config')
+ appContainer = await createTestApp(deps)
+ tenantService = await deps.use('tenantService')
authServiceClient = await deps.use('authServiceClient')
tenantSettingsService = await deps.use('tenantSettingService')
})
afterEach(async (): Promise => {
- await truncateTables(knex, true, dbSchema)
+ await truncateTables(deps, { truncateTenants: true })
})
afterAll(async (): Promise => {
- nock.cleanAll()
await appContainer.shutdown()
})
@@ -447,3 +446,95 @@ describe('Tenant Service', (): void => {
})
})
})
+
+describe('Tenant Service (no tenant truncate)', (): void => {
+ let deps: IocContract
+ let config: IAppConfig
+ let appContainer: TestContainer
+ let tenantService: TenantService
+ let knex: Knex
+ let tenantCache: CacheDataStore
+ let updateSpyWasCalled: boolean
+ const dbSchema = 'tenant_service_test_schema2'
+
+ beforeAll(async (): Promise => {
+ deps = initIocContainer({
+ ...Config,
+ dbSchema
+ })
+ knex = await deps.use('knex')
+ config = await deps.use('config')
+ tenantService = await deps.use('tenantService')
+ tenantCache = await deps.use('tenantCache')
+
+ const updateOperatorSecretSpy = jest.spyOn(
+ tenantService,
+ 'updateOperatorApiSecretFromConfig'
+ )
+ appContainer = await createTestApp(deps)
+ updateSpyWasCalled = updateOperatorSecretSpy.mock.calls.length > 0
+ })
+
+ afterEach(async (): Promise => {
+ await truncateTables(deps)
+ })
+
+ afterAll(async (): Promise => {
+ await appContainer.shutdown()
+ })
+ describe('updateOperatorApiSecretFromConfig', () => {
+ test('called on application start', async (): Promise => {
+ expect(updateSpyWasCalled).toBe(true)
+ })
+
+ test('updates secret if changed', async (): Promise => {
+ // Setup operator with different secret than the config.
+ // As-if the api secret was set from a different config value originally.
+ const initialApiSecret = '123'
+ assert(initialApiSecret !== config.adminApiSecret)
+ const tenant = await Tenant.query(knex).patchAndFetchById(
+ config.operatorTenantId,
+ { apiSecret: initialApiSecret }
+ )
+ assert(tenant)
+ expect(tenant.apiSecret).toBe(initialApiSecret)
+
+ const error = await tenantService.updateOperatorApiSecretFromConfig()
+ expect(error).toBe(undefined)
+
+ const updated = await Tenant.query(knex).findById(tenant.id)
+ assert(updated)
+ expect(updated.apiSecret).toBe(config.adminApiSecret)
+
+ const cacheUpdated = await tenantCache.get(tenant.id)
+ assert(cacheUpdated)
+ expect(cacheUpdated.apiSecret).toBe(config.adminApiSecret)
+ })
+ test('does not update if secret hasnt changed', async (): Promise => {
+ const tenant = await Tenant.query(knex).findById(config.operatorTenantId)
+ assert(tenant)
+ assert(tenant.apiSecret === config.adminApiSecret)
+
+ const error = await tenantService.updateOperatorApiSecretFromConfig()
+
+ expect(error).toBe(undefined)
+
+ const updated = await Tenant.query(knex).findById(tenant.id)
+ assert(updated)
+ expect(updated.updatedAt).toStrictEqual(tenant.updatedAt)
+ })
+ test(
+ 'throws error if operator tenant not found',
+ withConfigOverride(
+ () => config,
+ { operatorTenantId: crypto.randomUUID() },
+ async (): Promise => {
+ const error = await tenantService.updateOperatorApiSecretFromConfig()
+
+ expect(isTenantError(error)).toBe(true)
+ expect(error).toEqual(TenantError.TenantNotFound)
+ }
+ )
+ )
+ })
+})
diff --git a/packages/backend/src/tenants/service.ts b/packages/backend/src/tenants/service.ts
index 64f97fa27a..4cd56dce85 100644
--- a/packages/backend/src/tenants/service.ts
+++ b/packages/backend/src/tenants/service.ts
@@ -6,6 +6,8 @@ import { CacheDataStore } from '../middleware/cache/data-stores'
import type { AuthServiceClient } from '../auth-service-client/client'
import { TenantSettingService } from './settings/service'
import { TenantSetting } from './settings/model'
+import type { IAppConfig } from '../config/app'
+import { TenantError } from './errors'
export interface TenantService {
get: (id: string, includeDeleted?: boolean) => Promise
@@ -13,13 +15,14 @@ export interface TenantService {
update: (options: UpdateTenantOptions) => Promise
delete: (id: string) => Promise
getPage: (pagination?: Pagination, sortOrder?: SortOrder) => Promise
+ updateOperatorApiSecretFromConfig: () => Promise
}
-
export interface ServiceDependencies extends BaseService {
knex: TransactionOrKnex
tenantCache: CacheDataStore
authServiceClient: AuthServiceClient
tenantSettingService: TenantSettingService
+ config: IAppConfig
}
export async function createTenantService(
@@ -37,7 +40,9 @@ export async function createTenantService(
update: (options) => updateTenant(deps, options),
delete: (id) => deleteTenant(deps, id),
getPage: (pagination, sortOrder) =>
- getTenantPage(deps, pagination, sortOrder)
+ getTenantPage(deps, pagination, sortOrder),
+ updateOperatorApiSecretFromConfig: () =>
+ updateOperatorApiSecretFromConfig(deps)
}
}
@@ -186,3 +191,21 @@ async function deleteTenant(
throw err
}
}
+
+async function updateOperatorApiSecretFromConfig(
+ deps: ServiceDependencies
+): Promise {
+ const { adminApiSecret, operatorTenantId } = deps.config
+
+ const tenant = await Tenant.query(deps.knex)
+ .findById(operatorTenantId)
+ .whereNull('deletedAt')
+
+ if (!tenant) {
+ return TenantError.TenantNotFound
+ }
+ if (tenant.apiSecret !== adminApiSecret) {
+ await tenant.$query(deps.knex).patch({ apiSecret: adminApiSecret })
+ await deps.tenantCache.set(operatorTenantId, tenant)
+ }
+}
diff --git a/packages/backend/src/tenants/settings/service.test.ts b/packages/backend/src/tenants/settings/service.test.ts
index a95791544e..92592e3f54 100644
--- a/packages/backend/src/tenants/settings/service.test.ts
+++ b/packages/backend/src/tenants/settings/service.test.ts
@@ -5,7 +5,6 @@ import { Config } from '../../config/app'
import { createTestApp, TestContainer } from '../../tests/app'
import nock from 'nock'
import { truncateTables } from '../../tests/tableManager'
-import { Knex } from 'knex'
import { Tenant } from '../model'
import { TenantService } from '../service'
import { faker } from '@faker-js/faker'
@@ -26,7 +25,6 @@ import {
import { AuthServiceClient } from '../../auth-service-client/client'
describe('TenantSetting Service', (): void => {
- let knex: Knex
let deps: IocContract
let appContainer: TestContainer
let tenant: Tenant
@@ -40,7 +38,6 @@ describe('TenantSetting Service', (): void => {
deps = initIocContainer({ ...Config, dbSchema })
appContainer = await createTestApp(deps)
- knex = await deps.use('knex')
tenantService = await deps.use('tenantService')
tenantSettingService = await deps.use('tenantSettingService')
authServiceClient = await deps.use('authServiceClient')
@@ -64,7 +61,7 @@ describe('TenantSetting Service', (): void => {
})
afterEach(async (): Promise => {
- await truncateTables(knex, true, dbSchema)
+ await truncateTables(deps, { truncateTenants: true })
})
afterAll(async (): Promise => {
diff --git a/packages/backend/src/tests/tableManager.ts b/packages/backend/src/tests/tableManager.ts
index 9467127684..cf293ef36e 100644
--- a/packages/backend/src/tests/tableManager.ts
+++ b/packages/backend/src/tests/tableManager.ts
@@ -1,4 +1,6 @@
+import { IocContract } from '@adonisjs/fold'
import { Knex } from 'knex'
+import { AppServices } from '../app'
export async function truncateTable(
knex: Knex,
@@ -9,10 +11,15 @@ export async function truncateTable(
}
export async function truncateTables(
- knex: Knex,
- truncateTenants = false,
- dbSchema?: string
+ deps: IocContract,
+ options?: { truncateTenants?: boolean }
): Promise {
+ const knex = await deps.use('knex')
+ const config = await deps.use('config')
+ const dbSchema = config.dbSchema ?? 'public'
+
+ const truncateTenants = options?.truncateTenants ?? false
+
const ignoreTables = [
'knex_migrations',
'knex_migrations_lock',
diff --git a/packages/backend/src/webhook/service.test.ts b/packages/backend/src/webhook/service.test.ts
index d2d55f09e3..3a574d8cb4 100644
--- a/packages/backend/src/webhook/service.test.ts
+++ b/packages/backend/src/webhook/service.test.ts
@@ -74,7 +74,7 @@ describe('Webhook Service', (): void => {
afterEach(async (): Promise => {
jest.useRealTimers()
- await truncateTables(knex)
+ await truncateTables(deps)
})
afterAll(async (): Promise => {
diff --git a/packages/frontend/app/lib/validate.server.ts b/packages/frontend/app/lib/validate.server.ts
index 8e91af96a2..97e8e4404c 100644
--- a/packages/frontend/app/lib/validate.server.ts
+++ b/packages/frontend/app/lib/validate.server.ts
@@ -130,20 +130,32 @@ export const updateWalletAddressSchema = z
})
.merge(uuidSchema)
-export const updateTenantSchema = z
+export const updateTenantGeneralSchema = z
+ .object({
+ publicName: z.string().optional(),
+ email: z.string().email().or(z.literal(''))
+ })
+ .merge(uuidSchema)
+
+export const updateTenantIpSchema = z
+ .object({
+ idpSecret: z.string().optional(),
+ idpConsentUrl: z.string().optional()
+ })
+ .merge(uuidSchema)
+
+export const updateTenantSensitiveSchema = z
.object({
apiSecret: z
.string()
.min(10, { message: 'API Secret should be at least 10 characters long' })
- .max(255, { message: 'Maximum length of API Secret is 255 characters' }),
- publicName: z.string().optional(),
- email: z.string().email().or(z.literal('')),
- idpConsentUrl: z.string().optional(),
- idpSecret: z.string().optional()
+ .max(255, { message: 'Maximum length of API Secret is 255 characters' })
})
.merge(uuidSchema)
export const createTenantSchema = z
.object({})
- .merge(updateTenantSchema)
+ .merge(updateTenantGeneralSchema)
+ .merge(updateTenantIpSchema)
+ .merge(updateTenantSensitiveSchema)
.omit({ id: true })
diff --git a/packages/frontend/app/routes/tenants.$tenantId.tsx b/packages/frontend/app/routes/tenants.$tenantId.tsx
index 3cd6a6d38f..b85b80b301 100644
--- a/packages/frontend/app/routes/tenants.$tenantId.tsx
+++ b/packages/frontend/app/routes/tenants.$tenantId.tsx
@@ -12,6 +12,7 @@ import {
useSubmit
} from '@remix-run/react'
import { type FormEvent, useState, useRef } from 'react'
+import type { ZodSchema } from 'zod'
import { z } from 'zod'
import { DangerZone, PageHeader } from '~/components'
import { Button, ErrorPanel, Input, PasswordInput } from '~/components/ui'
@@ -21,11 +22,16 @@ import {
} from '~/components/ConfirmationDialog'
import { updateTenant, deleteTenant, whoAmI } from '~/lib/api/tenant.server'
import { messageStorage, setMessageAndRedirect } from '~/lib/message.server'
-import type { createTenantSchema } from '~/lib/validate.server'
-import { updateTenantSchema, uuidSchema } from '~/lib/validate.server'
+import {
+ updateTenantGeneralSchema,
+ updateTenantIpSchema,
+ updateTenantSensitiveSchema,
+ uuidSchema
+} from '~/lib/validate.server'
import type { ZodFieldErrors } from '~/shared/types'
import { checkAuthAndRedirect } from '../lib/kratos_checks.server'
import { getTenantInfo } from '~/lib/api/tenant.server'
+import type { UpdateTenantInput } from '~/generated/graphql'
export async function loader({ request, params }: LoaderFunctionArgs) {
const cookies = request.headers.get('cookie')
@@ -87,18 +93,12 @@ export default function ViewTenantPage() {
>
)}
-