Skip to content

Commit c674073

Browse files
fix: delete old API key before inserting rotated one (#740)
* fix: delete old API key before inserting rotated one The agent_api_keys table has a OneToOne unique constraint on agent_id, so deactivating the old key (setting is_active=false) still blocks the insert of the new key. Delete the old row instead. * retrigger CI * fix: update rotateKey tests to match delete + insert approach The mock for keyRepo was missing the delete method, causing all rotateKey tests to fail with "this.keyRepo.delete is not a function". Updated test assertions to verify delete is called instead of update. * fix: always show terminal command in configure step The terminal with the copyable CLI/env command was hidden when the full API key wasn't available (e.g. on subsequent visits). Now the terminal is always visible regardless of key availability. --------- Co-authored-by: Bruno Perez <bruno@buddyweb.fr>
1 parent c62ffd3 commit c674073

File tree

2 files changed

+10
-13
lines changed

2 files changed

+10
-13
lines changed

packages/backend/src/otlp/services/api-key.service.spec.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ describe('ApiKeyGeneratorService', () => {
2929
let mockAgentInsert: jest.Mock;
3030
let mockKeyInsert: jest.Mock;
3131
let mockKeyUpdate: jest.Mock;
32+
let mockKeyDelete: jest.Mock;
3233
let mockKeyGetOne: jest.Mock;
3334
let mockKeyQb: Record<string, jest.Mock>;
3435
let mockAgentGetOne: jest.Mock;
@@ -40,6 +41,7 @@ describe('ApiKeyGeneratorService', () => {
4041
mockAgentInsert = jest.fn().mockResolvedValue({});
4142
mockKeyInsert = jest.fn().mockResolvedValue({});
4243
mockKeyUpdate = jest.fn().mockResolvedValue({});
44+
mockKeyDelete = jest.fn().mockResolvedValue({});
4345
mockKeyGetOne = jest.fn();
4446
mockAgentGetOne = jest.fn();
4547

@@ -79,6 +81,7 @@ describe('ApiKeyGeneratorService', () => {
7981
useValue: {
8082
insert: mockKeyInsert,
8183
update: mockKeyUpdate,
84+
delete: mockKeyDelete,
8285
createQueryBuilder: jest.fn().mockReturnValue(mockKeyQb),
8386
},
8487
},
@@ -367,15 +370,12 @@ describe('ApiKeyGeneratorService', () => {
367370
).rejects.toThrow('Agent not found or access denied');
368371
});
369372

370-
it('should deactivate all existing active keys for the agent', async () => {
373+
it('should delete existing keys for the agent before creating a new one', async () => {
371374
mockAgentGetOne.mockResolvedValue(existingAgent);
372375

373376
await service.rotateKey('user-1', 'my-agent');
374377

375-
expect(mockKeyUpdate).toHaveBeenCalledWith(
376-
{ agent_id: 'agent-id-1', is_active: true },
377-
{ is_active: false },
378-
);
378+
expect(mockKeyDelete).toHaveBeenCalledWith({ agent_id: 'agent-id-1' });
379379
});
380380

381381
it('should create a new key with hash and prefix, no plaintext', async () => {
@@ -432,12 +432,12 @@ describe('ApiKeyGeneratorService', () => {
432432
);
433433
});
434434

435-
it('should deactivate old keys before inserting the new one', async () => {
435+
it('should delete old keys before inserting the new one', async () => {
436436
mockAgentGetOne.mockResolvedValue(existingAgent);
437437

438438
const callOrder: string[] = [];
439-
mockKeyUpdate.mockImplementation(() => {
440-
callOrder.push('update');
439+
mockKeyDelete.mockImplementation(() => {
440+
callOrder.push('delete');
441441
return Promise.resolve({});
442442
});
443443
mockKeyInsert.mockImplementation(() => {
@@ -447,7 +447,7 @@ describe('ApiKeyGeneratorService', () => {
447447

448448
await service.rotateKey('user-1', 'my-agent');
449449

450-
expect(callOrder).toEqual(['update', 'insert']);
450+
expect(callOrder).toEqual(['delete', 'insert']);
451451
});
452452
});
453453
});

packages/backend/src/otlp/services/api-key.service.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,7 @@ export class ApiKeyGeneratorService {
101101
.getOne();
102102
if (!agent) throw new NotFoundException('Agent not found or access denied');
103103

104-
await this.keyRepo.update(
105-
{ agent_id: agent.id, is_active: true },
106-
{ is_active: false },
107-
);
104+
await this.keyRepo.delete({ agent_id: agent.id });
108105

109106
const rawKey = this.generateKey();
110107
const keyId = uuidv4();

0 commit comments

Comments
 (0)