diff --git a/apps/core/src/modules/snippet/snippet.service.ts b/apps/core/src/modules/snippet/snippet.service.ts index cf552b2c..a2805a2e 100644 --- a/apps/core/src/modules/snippet/snippet.service.ts +++ b/apps/core/src/modules/snippet/snippet.service.ts @@ -69,7 +69,9 @@ export class SnippetService { async update(id: string, newModel: SnippetModel) { await this.validateTypeAndCleanup(newModel) delete newModel.created - const old = await this.model.findById(id).select('+secret').lean() + const old = await this.model.findById(id).select('+secret').lean({ + getters: true, + }) if (!old) { throw new NotFoundException() @@ -87,6 +89,8 @@ export class SnippetService { // merge secret if (old.secret && newModel.secret) { const oldSecret = qs.parse(old.secret) + + // newSecret will be e.g. `{ foo: '' }` const newSecret = qs.parse(newModel.secret) // first delete key if newer secret not provide diff --git a/apps/core/test/src/modules/snippet/snippet.service.spec.ts b/apps/core/test/src/modules/snippet/snippet.service.spec.ts index 4b6f5c7f..4057c7bd 100644 --- a/apps/core/test/src/modules/snippet/snippet.service.spec.ts +++ b/apps/core/test/src/modules/snippet/snippet.service.spec.ts @@ -1,5 +1,7 @@ +import { stringify } from 'qs' import { redisHelper } from 'test/helper/redis-mock.helper' +import { nanoid } from '@mx-space/external' import { BadRequestException, NotFoundException } from '@nestjs/common' import { Test } from '@nestjs/testing' import { getModelForClass } from '@typegoose/typegoose' @@ -23,7 +25,14 @@ describe('test Snippet Service', () => { SnippetService, { provide: DatabaseService, useValue: {} }, { provide: CacheService, useValue: redis.CacheService }, - { provide: ServerlessService, useValue: {} }, + { + provide: ServerlessService, + useValue: { + isValidServerlessFunction() { + return true + }, + }, + }, { provide: EventManagerService, useValue: mockedEventManageService }, { @@ -44,7 +53,7 @@ describe('test Snippet Service', () => { type: SnippetType.JSON, private: false, reference: 'root', - } + } as SnippetModel let id = '' it('should create one', async () => { @@ -79,7 +88,7 @@ describe('test Snippet Service', () => { const newSnippet = { ...snippet, raw: '{"foo": "b"}', - } + } as SnippetModel const res = await service.update(id, newSnippet) expect(res.raw).toBe(newSnippet.raw) }) @@ -93,4 +102,39 @@ describe('test Snippet Service', () => { await service.delete(id) await expect(service.getSnippetById(id)).rejects.toThrow(NotFoundException) }) + + describe('update function snippet with secret', () => { + const createTestingModel = () => + ({ + name: `test-fn-${nanoid.nanoid()}`, + raw: 'export default async function handler() {}', + type: SnippetType.Function, + private: false, + reference: 'root', + id: nanoid.nanoid(), + secret: 'username=123&password=123', + }) as SnippetModel + + test('patch secret', async () => { + const newSnippet = createTestingModel() + const doc = await service.create(newSnippet) + + await service.update(doc.id, { + ...newSnippet, + secret: stringify({ username: '', password: '' }), + }) + const afterUpdate = await service.getSnippetById(doc.id) + + expect(afterUpdate.secret).toStrictEqual({ + username: '', + password: '', + }) + + const raw = await service.model.findById(doc.id).select('+secret').lean({ + getters: true, + }) + + expect(raw.secret).toBe(newSnippet.secret) + }) + }) })