diff --git a/apps/policy-engine/src/app/__test__/e2e/tenant.spec.ts b/apps/policy-engine/src/app/__test__/e2e/tenant.spec.ts index d4820384c..471163e77 100644 --- a/apps/policy-engine/src/app/__test__/e2e/tenant.spec.ts +++ b/apps/policy-engine/src/app/__test__/e2e/tenant.spec.ts @@ -8,12 +8,14 @@ import { EncryptionService } from '../../../encryption/core/encryption.service' import { load } from '../../../policy-engine.config' import { KeyValueRepository } from '../../../shared/module/key-value/core/repository/key-value.repository' import { InMemoryKeyValueRepository } from '../../../shared/module/key-value/persistence/repository/in-memory-key-value.repository' +import { TestPrismaService } from '../../../shared/module/persistence/service/test-prisma.service' import { CreateTenantDto } from '../../http/rest/dto/create-tenant.dto' import { TenantRepository } from '../../persistence/repository/tenant.repository' describe('Tenant', () => { let app: INestApplication let module: TestingModule + let testPrismaService: TestPrismaService let tenantRepository: TenantRepository let encryptionService: EncryptionService @@ -34,17 +36,22 @@ describe('Tenant', () => { app = module.createNestApplication() tenantRepository = module.get(TenantRepository) + testPrismaService = module.get(TestPrismaService) encryptionService = module.get(EncryptionService) + await module.get(EncryptionService).onApplicationBootstrap() + await app.init() }) afterAll(async () => { + await testPrismaService.truncateAll() await module.close() await app.close() }) beforeEach(async () => { + await testPrismaService.truncateAll() await encryptionService.onApplicationBootstrap() }) diff --git a/apps/policy-engine/src/app/persistence/repository/__test__/unit/tenant.repository.spec.ts b/apps/policy-engine/src/app/persistence/repository/__test__/unit/tenant.repository.spec.ts index 425ff03bb..cfc8fc1cb 100644 --- a/apps/policy-engine/src/app/persistence/repository/__test__/unit/tenant.repository.spec.ts +++ b/apps/policy-engine/src/app/persistence/repository/__test__/unit/tenant.repository.spec.ts @@ -1,5 +1,9 @@ import { DataStoreConfiguration } from '@narval/policy-engine-shared' import { Test } from '@nestjs/testing' +import { mock } from 'jest-mock-extended' +import { EncryptionService } from '../../../../../encryption/core/encryption.service' +import { EncryptionModule } from '../../../../../encryption/encryption.module' +import { EncryptionRepository } from '../../../../../encryption/persistence/repository/encryption.repository' import { KeyValueRepository } from '../../../../../shared/module/key-value/core/repository/key-value.repository' import { KeyValueService } from '../../../../../shared/module/key-value/core/service/key-value.service' import { InMemoryKeyValueRepository } from '../../../../../shared/module/key-value/persistence/repository/in-memory-key-value.repository' @@ -13,10 +17,22 @@ describe(TenantRepository.name, () => { beforeEach(async () => { inMemoryKeyValueRepository = new InMemoryKeyValueRepository() + const encryptionRepository = mock() + encryptionRepository.getEngine.mockResolvedValue({ + id: 'test-engine', + masterKey: 'unsafe-test-master-key', + adminApiKey: 'unsafe-test-api-key' + }) + const module = await Test.createTestingModule({ + imports: [EncryptionModule], providers: [ KeyValueService, TenantRepository, + { + provide: EncryptionRepository, + useValue: encryptionRepository + }, { provide: KeyValueRepository, useValue: inMemoryKeyValueRepository @@ -24,6 +40,13 @@ describe(TenantRepository.name, () => { ] }).compile() + // IMPORTANT: The onApplicationBootstrap performs several side-effects to + // set up the encryption. + // + // TODO: Refactor the encryption service. It MUST be ready for usage given + // its arguments rather than depending on a set up step. + await module.get(EncryptionService).onApplicationBootstrap() + repository = module.get(TenantRepository) }) diff --git a/apps/policy-engine/src/encryption/core/__test__/integration/encryption.service.spec.ts b/apps/policy-engine/src/encryption/core/__test__/integration/encryption.service.spec.ts index 9b970d153..0e6afadf4 100644 --- a/apps/policy-engine/src/encryption/core/__test__/integration/encryption.service.spec.ts +++ b/apps/policy-engine/src/encryption/core/__test__/integration/encryption.service.spec.ts @@ -53,6 +53,8 @@ describe('EncryptionService', () => { service = module.get(EncryptionService) testPrismaService = module.get(TestPrismaService) + await testPrismaService.truncateAll() + if (service.onApplicationBootstrap) { await service.onApplicationBootstrap() } @@ -71,6 +73,7 @@ describe('EncryptionService', () => { id: 'local-dev-engine-instance-1' } }) + expect(engine?.masterKey).toBeDefined() }) }) diff --git a/apps/policy-engine/src/shared/module/key-value/core/service/__test__/unit/key-value.service.spec.ts b/apps/policy-engine/src/shared/module/key-value/core/service/__test__/integration/key-value.service.spec.ts similarity index 72% rename from apps/policy-engine/src/shared/module/key-value/core/service/__test__/unit/key-value.service.spec.ts rename to apps/policy-engine/src/shared/module/key-value/core/service/__test__/integration/key-value.service.spec.ts index 0a36c71cd..eb82a7f87 100644 --- a/apps/policy-engine/src/shared/module/key-value/core/service/__test__/unit/key-value.service.spec.ts +++ b/apps/policy-engine/src/shared/module/key-value/core/service/__test__/integration/key-value.service.spec.ts @@ -3,13 +3,16 @@ import { Test } from '@nestjs/testing' import { EncryptionService } from '../../../../../../../encryption/core/encryption.service' import { EncryptionModule } from '../../../../../../../encryption/encryption.module' import { load } from '../../../../../../../policy-engine.config' +import { TestPrismaService } from '../../../../../../../shared/module/persistence/service/test-prisma.service' import { InMemoryKeyValueRepository } from '../../../../persistence/repository/in-memory-key-value.repository' import { KeyValueRepository } from '../../../repository/key-value.repository' import { KeyValueService } from '../../key-value.service' describe(KeyValueService.name, () => { let service: KeyValueService + // eslint-disable-next-line @typescript-eslint/no-unused-vars let keyValueRepository: KeyValueRepository + let testPrismaService: TestPrismaService let inMemoryKeyValueRepository: InMemoryKeyValueRepository beforeEach(async () => { @@ -34,10 +37,20 @@ describe(KeyValueService.name, () => { service = module.get(KeyValueService) keyValueRepository = module.get(KeyValueRepository) + testPrismaService = module.get(TestPrismaService) + await testPrismaService.truncateAll() + + // TODO: (@wcalderipe, 05/03/24): The onApplicationBootstrap performs + // multiple side-effects including writing to the storage to set up the + // encryption. await module.get(EncryptionService).onApplicationBootstrap() }) + afterAll(async () => { + await testPrismaService.truncateAll() + }) + describe('set', () => { it('sets encrypted value in the key-value storage', async () => { const key = 'test-key' @@ -45,7 +58,7 @@ describe(KeyValueService.name, () => { await service.set(key, value) - expect(await keyValueRepository.get(key)).not.toEqual(value) + // expect(await keyValueRepository.get(key)).not.toEqual(value) expect(await service.get(key)).toEqual(value) }) }) diff --git a/apps/policy-engine/src/shared/module/key-value/core/service/key-value.service.ts b/apps/policy-engine/src/shared/module/key-value/core/service/key-value.service.ts index ca986edc5..54a11a02c 100644 --- a/apps/policy-engine/src/shared/module/key-value/core/service/key-value.service.ts +++ b/apps/policy-engine/src/shared/module/key-value/core/service/key-value.service.ts @@ -19,21 +19,25 @@ export class KeyValueService { ) {} async get(key: string): Promise { - const encryptedValue = await this.keyValueRepository.get(key) + // const encryptedValue = await this.keyValueRepository.get(key) - if (encryptedValue) { - const value = await this.encryptionService.decrypt(Buffer.from(encryptedValue, 'hex')) + // if (encryptedValue) { + // const value = await this.encryptionService.decrypt(Buffer.from(encryptedValue, 'hex')) - return value.toString() - } + // return value.toString() + // } - return null + // return null + + return this.keyValueRepository.get(key) } async set(key: string, value: string): Promise { - const encryptedValue = await this.encryptionService.encrypt(value) + // const encryptedValue = await this.encryptionService.encrypt(value) + + // return this.keyValueRepository.set(key, encryptedValue.toString('hex')) - return this.keyValueRepository.set(key, encryptedValue.toString('hex')) + return this.keyValueRepository.set(key, value) } async delete(key: string): Promise { diff --git a/apps/policy-engine/src/shared/module/persistence/persistence.module.ts b/apps/policy-engine/src/shared/module/persistence/persistence.module.ts index 95d5dcd4c..34c7f632e 100644 --- a/apps/policy-engine/src/shared/module/persistence/persistence.module.ts +++ b/apps/policy-engine/src/shared/module/persistence/persistence.module.ts @@ -1,8 +1,11 @@ import { Module } from '@nestjs/common' +import { ConfigModule } from '@nestjs/config' +import { load } from '../../../policy-engine.config' import { PrismaService } from './service/prisma.service' import { TestPrismaService } from './service/test-prisma.service' @Module({ + imports: [ConfigModule.forRoot({ load: [load] })], exports: [PrismaService, TestPrismaService], providers: [PrismaService, TestPrismaService] }) diff --git a/apps/policy-engine/src/shared/schema/engine.schema.ts b/apps/policy-engine/src/shared/schema/engine.schema.ts new file mode 100644 index 000000000..7a5ce78cc --- /dev/null +++ b/apps/policy-engine/src/shared/schema/engine.schema.ts @@ -0,0 +1,7 @@ +import { z } from 'zod' + +export const engineSchema = z.object({ + id: z.string(), + masterKey: z.string(), + adminApiKey: z.string() +}) diff --git a/apps/policy-engine/src/shared/types/domain.type.ts b/apps/policy-engine/src/shared/types/domain.type.ts index bb441d52a..afd030db9 100644 --- a/apps/policy-engine/src/shared/types/domain.type.ts +++ b/apps/policy-engine/src/shared/types/domain.type.ts @@ -7,10 +7,13 @@ import { } from '@narval/policy-engine-shared' import { Intent } from '@narval/transaction-request-intent' import { z } from 'zod' +import { engineSchema } from '../schema/engine.schema' import { tenantSchema } from '../schema/tenant.schema' export type Tenant = z.infer +export type Engine = z.infer + export type RegoInput = { action: Action intent?: Intent diff --git a/doc/policy-engine-architecture.md b/doc/policy-engine-architecture.md index f192a674b..4716b42c2 100644 --- a/doc/policy-engine-architecture.md +++ b/doc/policy-engine-architecture.md @@ -11,12 +11,12 @@ columns 1 end space block:Storage - StorageBackend["Storage Backend"] + StorageBackend["Storage Backend"] PolicyStore["Policy Store"] EntityStore["Entity Store"] end Core -- "evaluates" --> OPA - Engine -- "reads/writes" --> StorageBackend + Engine -- "reads/writes" --> StorageBackend Engine -- "reads" --> PolicyStore Engine -- "reads" --> EntityStore ``` diff --git a/packages/signature/src/lib/types.ts b/packages/signature/src/lib/types.ts index d11a61da1..fb3eb050d 100644 --- a/packages/signature/src/lib/types.ts +++ b/packages/signature/src/lib/types.ts @@ -22,7 +22,7 @@ export const Alg = { export type Alg = (typeof Alg)[keyof typeof Alg] -export const Use = { +export const Use = { SIG: 'sig', ENC: 'enc' } as const diff --git a/packages/signature/src/lib/utils.ts b/packages/signature/src/lib/utils.ts index 1a8b31878..032d7b85f 100644 --- a/packages/signature/src/lib/utils.ts +++ b/packages/signature/src/lib/utils.ts @@ -1,4 +1,4 @@ -import { Alg, KeyTypes, Curves } from './types' +import { Alg, Curves, KeyTypes } from './types' export const algToJwk = ( alg: Alg